Fawkes API Fawkes Development Version
qa_socket_datagram_multicast.cpp
1
2/***************************************************************************
3 * qa_socket_datagram_multicast.cpp - Fawkes QA MulticastDatagramSocket
4 *
5 * Created: Sat Jan 13 23:51:23 2007
6 * Copyright 2006-2007 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24/// @cond QA
25
26/* NOTE:
27 * This program does not do any error correction, if a number is not received
28 * by the reflector, this may stall. On wireless networks this is usually
29 * the case for an i << 100, often even i < 10. If you use a cable connection
30 * this problem does not occur. Meaning that the connection stalls is not an
31 * indicator for a broken implementation, as long as you can do this with a
32 * reliable connection like a cabled LAN for a long time (stopped my tests
33 * at i ~ 1000).
34 */
35
36#include <core/threading/thread.h>
37#include <netcomm/socket/datagram_multicast.h>
38#include <netinet/in.h>
39#include <utils/system/argparser.h>
40#include <utils/system/signal.h>
41
42#include <cstdio>
43#include <cstring>
44#include <netdb.h>
45
46using namespace fawkes;
47
48class MulticastDatagramServerThread : public Thread
49{
50public:
51 MulticastDatagramServerThread(unsigned short int port, bool looping)
52 : Thread("MulticastDatagramServerThread", Thread::OPMODE_CONTINUOUS)
53 {
54 i = 0;
55 try {
56 s = new MulticastDatagramSocket("224.16.0.1", port);
57 s->bind();
58 s->set_loop(looping);
59 } catch (Exception &e) {
60 e.print_trace();
61 throw;
62 }
63 }
64
65 ~MulticastDatagramServerThread()
66 {
67 printf("Closing server socket\n");
68 s->close();
69 printf("Closed server socket\n");
70 delete s;
71 }
72
73 virtual void
74 loop()
75 {
76 try {
77 printf("Sending %u\n", i);
78 s->send(&i, sizeof(i));
79 printf("Sent %u\n", i);
80 unsigned int ri = 0;
81 from_len = sizeof(from);
82 printf("Receiving\n");
83 s->recv(&ri, sizeof(ri), (struct sockaddr *)&from, &from_len);
84 if (ri != i) {
85 printf("ERROR: sent %u but received %u\n", i, ri);
86 } else {
87 printf("OK: sent %u and received %u\n", i, ri);
88 }
89 ++i;
90 } catch (Exception &e) {
91 printf("Loop failed\n");
92 e.print_trace();
93 throw;
94 }
95 }
96
97private:
98 unsigned int i;
100 struct sockaddr_in from;
101 unsigned int from_len;
102};
103
104class MulticastDatagramReflectorThread : public Thread
105{
106public:
107 MulticastDatagramReflectorThread(unsigned short int port)
108 : Thread("MulticastDatagramReflectorThread", Thread::OPMODE_CONTINUOUS)
109 {
110 try {
111 s = new MulticastDatagramSocket("224.16.0.1", port);
112 s->bind();
113 } catch (Exception &e) {
114 e.print_trace();
115 throw;
116 }
117 from_len = sizeof(from);
118 }
119
120 ~MulticastDatagramReflectorThread()
121 {
122 printf("Closing reflector socket\n");
123 s->close();
124 printf("Closed reflector socket\n");
125 delete s;
126 }
127
128 virtual void
129 loop()
130 {
131 unsigned int i = 0;
132 printf("Waiting for data to reflect\n");
133 s->recv(&i, sizeof(i), (struct sockaddr *)&from, &from_len);
134 printf("Received %u, reflecting\n", i);
135 s->send(&i, sizeof(i));
136 }
137
138private:
140 struct sockaddr_in from;
141 unsigned int from_len;
142};
143
144class MulticastDatagramSocketQAMain : public SignalHandler
145{
146public:
147 MulticastDatagramSocketQAMain(ArgumentParser *argp)
148 {
149 s = NULL;
150 r = NULL;
151 this->argp = argp;
152 if (argp->has_arg("r")) {
153 printf("Going to be a reflector\n");
154 r = new MulticastDatagramReflectorThread(1910);
155 } else {
156 bool looping = argp->has_arg("l");
157 if (looping) {
158 printf("Enabling local loop (we receive own traffic)\n");
159 }
160 s = new MulticastDatagramServerThread(1910, looping);
161 }
162 }
163
164 ~MulticastDatagramSocketQAMain()
165 {
166 delete s;
167 delete r;
168 }
169
170 virtual void
171 handle_signal(int signum)
172 {
173 printf("Signal received, cancelling threads\n");
174 if (s != NULL)
175 s->cancel();
176 if (r != NULL)
177 r->cancel();
178 printf("Threads cancelled\n");
179 }
180
181 void
182 run()
183 {
184 if (s != NULL) {
185 s->start();
186 s->join();
187 }
188 if (r != NULL) {
189 r->start();
190 r->join();
191 }
192 }
193
194private:
195 ArgumentParser * argp;
196 MulticastDatagramServerThread * s;
197 MulticastDatagramReflectorThread *r;
198};
199
200int
201main(int argc, char **argv)
202{
203 ArgumentParser *argp = new ArgumentParser(argc, argv, "rl");
204
205 MulticastDatagramSocketQAMain m(argp);
206 SignalManager::register_handler(SIGINT, &m);
207 SignalManager::ignore(SIGPIPE);
208
209 m.run();
210
211 delete argp;
212 return 0;
213}
214
215/// @endcond
Parse command line arguments.
Definition: argparser.h:64
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:165
Base class for exceptions in Fawkes.
Definition: exception.h:36
void print_trace() noexcept
Prints trace to stderr.
Definition: exception.cpp:601
Multicast datagram socket.
Interface for signal handling.
Definition: signal.h:36
Thread class encapsulation of pthreads.
Definition: thread.h:46
Fawkes library namespace.