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 
37 #include <core/threading/thread.h>
38 #include <netcomm/socket/datagram_multicast.h>
39 #include <utils/system/signal.h>
40 #include <utils/system/argparser.h>
41 
42 #include <netdb.h>
43 #include <cstdio>
44 #include <cstring>
45 #include <netinet/in.h>
46 
47 using namespace fawkes;
48 
49 class MulticastDatagramServerThread : public Thread
50 {
51 public:
52  MulticastDatagramServerThread(unsigned short int port, bool looping)
53  : Thread("MulticastDatagramServerThread", Thread::OPMODE_CONTINUOUS)
54  {
55  i = 0;
56  try {
57  s = new MulticastDatagramSocket("224.16.0.1", port);
58  s->bind();
59  s->set_loop(looping);
60  } catch (Exception &e) {
61  e.print_trace();
62  throw;
63  }
64  }
65 
66  ~MulticastDatagramServerThread()
67  {
68  printf("Closing server socket\n");
69  s->close();
70  printf("Closed server socket\n");
71  delete s;
72  }
73 
74  virtual void 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 
97  private:
98  unsigned int i;
100  struct sockaddr_in from;
101  unsigned int from_len;
102 };
103 
104 class MulticastDatagramReflectorThread : public Thread
105 {
106 public:
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 loop()
129  {
130  unsigned int i = 0;
131  printf("Waiting for data to reflect\n");
132  s->recv(&i, sizeof(i), (struct sockaddr *)&from, &from_len);
133  printf("Received %u, reflecting\n", i);
134  s->send(&i, sizeof(i));
135  }
136 
137  private:
139  struct sockaddr_in from;
140  unsigned int from_len;
141 };
142 
143 
144 class MulticastDatagramSocketQAMain : public SignalHandler
145 {
146  public:
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 
171  virtual void handle_signal(int signum)
172  {
173  printf("Signal received, cancelling threads\n");
174  if ( s != NULL ) s->cancel();
175  if ( r != NULL ) r->cancel();
176  printf("Threads cancelled\n");
177  }
178 
179  void run()
180  {
181  if ( s != NULL ) {
182  s->start();
183  s->join();
184  }
185  if ( r != NULL ) {
186  r->start();
187  r->join();
188  }
189  }
190 
191  private:
192  ArgumentParser *argp;
193  MulticastDatagramServerThread *s;
194  MulticastDatagramReflectorThread *r;
195 
196 };
197 
198 int
199 main(int argc, char **argv)
200 {
201  ArgumentParser *argp = new ArgumentParser(argc, argv, "rl");
202 
203  MulticastDatagramSocketQAMain m(argp);
205  SignalManager::ignore(SIGPIPE);
206 
207  m.run();
208 
209  delete argp;
210  return 0;
211 }
212 
213 /// @endcond
Fawkes library namespace.
Interface for signal handling.
Definition: signal.h:35
Parse command line arguments.
Definition: argparser.h:66
Thread class encapsulation of pthreads.
Definition: thread.h:42
Base class for exceptions in Fawkes.
Definition: exception.h:36
Multicast datagram socket.
static void ignore(int signum)
Ignore a signal.
Definition: signal.cpp:182
static SignalHandler * register_handler(int signum, SignalHandler *handler)
Register a SignalHandler for a signal.
Definition: signal.cpp:116
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169