The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nanoprobe/nanoprobe.c
Go to the documentation of this file.
1 
24 #include <projectcommon.h>
25 #include <stdlib.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <framesettypes.h>
33 #include <frameset.h>
34 #include <ctype.h>
35 #include <netgsource.h>
36 #include <reliableudp.h>
37 #include <netaddr.h>
38 #include <authlistener.h>
39 #include <signframe.h>
40 #include <cryptframe.h>
41 #include <compressframe.h>
42 #include <intframe.h>
43 #include <addrframe.h>
44 #include <cstringframe.h>
45 #include <frametypes.h>
46 #include <misc.h>
47 #include <nanoprobe.h>
48 
50 
51 #ifdef WIN32
52 #define SEP "\\"
53 # undef HAS_FORK
54 WINIMPORT int errcount;
55 WINIMPORT GMainLoop* mainloop;
56 WINEXPORT void remove_pid_file(const char * pidfile);
57 WINEXPORT void daemonize_me(gboolean stay_in_foreground, const char * dirtorunin, char* pidfile);
58 WINEXPORT PidRunningStat are_we_already_running(const char * pidfile, int* pid);
59 WINEXPORT int kill_pid_service(const char * pidfile, int signal);
60 #else
61 #define SEP "/"
62 # define HAS_FORK
63 #endif
64 
65 const char * localaddr = NULL;
66 const char * cmaaddr = NULL;
67 const char * procname = "nanoprobe";
68 
69 gint64 pktcount = 0;
75 int pcapcount = 0;
76 int wirepktcount = 0;
77 
78 
79 // Signals...
80 gboolean sigint = FALSE;
81 gboolean sigterm = FALSE;
82 gboolean sighup = FALSE;
83 gboolean sigusr1 = FALSE;
84 gboolean sigusr2 = FALSE;
85 
86 
87 FSTATIC void catch_a_signal(int signum);
88 FSTATIC gboolean check_for_signals(gpointer ignored);
89 FSTATIC gboolean gotnetpkt(Listener*, FrameSet* fs, NetAddr* srcaddr);
90 FSTATIC void usage(const char * cmdname);
91 
92 
94 FSTATIC gboolean
96  FrameSet* fs,
97  NetAddr* srcaddr
98  )
99 {
100  (void)l; (void)srcaddr;
101  ++wirepktcount;
102  switch(fs->fstype) {
104  g_message("%s.%d: Received back alive notification (type %d) over the 'wire'."
105  , __FUNCTION__, __LINE__, fs->fstype);
106  break;
107 
108  default:
110  g_warning("%s.%d: Received a FrameSet of type %d over the 'wire' (OOPS!)."
111  , __FUNCTION__, __LINE__, fs->fstype);
112  }else{
113  DEBUGMSG3("%s.%d: Received a FrameSet of type %d over the 'wire'."
114  , __FUNCTION__, __LINE__, fs->fstype);
115  }
116  }
117  DUMP3(__FUNCTION__, &srcaddr->baseclass, " Was address received from.");
118  DUMP3(__FUNCTION__, &fs->baseclass, " Was the frameset received.");
119  UNREF(fs);
120  return TRUE;
121 }
122 
124 FSTATIC void
125 catch_a_signal(int signum)
126 {
127  switch(signum) {
128  case SIGINT:
129  sigint = TRUE;
130  break;
131  case SIGTERM:
132  sigterm = TRUE;
133  break;
134 #ifndef WIN32
135  case SIGHUP:
136  sighup = TRUE;
137  break;
138  case SIGUSR1:
139  proj_class_incr_debug(NULL);
140  sigusr1 = TRUE;
141  break;
142  case SIGUSR2:
143  proj_class_decr_debug(NULL);
144  sigusr2 = TRUE;
145  break;
146 #endif
147  }
148 }
149 
150 // If our output is all ACKed, then go ahead and shutdown
151 
153 FSTATIC gboolean
154 check_for_signals(gpointer ignored)
155 {
156  (void)ignored;
157  if (sigterm || sigint) {
158  g_message("%s: exiting on %s.", procname, (sigterm ? "SIGTERM" : "SIGINT"));
159  return nano_initiate_shutdown();
160  return FALSE;
161  }
162  if (sigusr1) {
163  sigusr1 = FALSE;
164  }
165  if (sigusr2) {
166  sigusr2 = FALSE;
167  }
168  return TRUE;
169 }
170 
171 FSTATIC void
172 usage(const char * cmdname)
173 {
174  fprintf(stderr, "usage: %s [arguments...]\n", cmdname);
175  fprintf(stderr, "Legal arguments are:\n");
176  fprintf(stderr, "\t-c --cmaaddr <address:port-of-CMA>\n");
177  fprintf(stderr, "\t-b --bind <address:port-to-listen-on-locally>\n");
178  fprintf(stderr, "\t-t --ttl <multi cast ttl (default == 31)>\n");
179 #ifndef WIN32
180 #ifdef HAS_FORK
181  fprintf(stderr, "\t-f --foreground (stay in foreground.)\n");
182 #endif
183  fprintf(stderr, "\t-k --kill (send SIGTERM to the running service.)\n");
184  fprintf(stderr, "\t-p --pidfile <pid-file-pathname>.\n");
185  fprintf(stderr, "\t-s --status (report nanoprobe status)\n");
186 #endif
187  fprintf(stderr, "\t-d --debug <debug-level (0-5)>\n");
188  fprintf(stderr, "\t-D --dynamic\n");
189 }
190 
196 int
197 main(int argc, char **argv)
198 {
199  static char defaultCMAaddr[] = CMAADDR;
200  static char defaultlocaladdress [] = NANOLISTENADDR;
201  SignFrame* signature = signframe_new(G_CHECKSUM_SHA256, 0);
202  Listener* otherlistener;
204  PacketDecoder* decoder = nano_packet_decoder();
205 #ifdef HAVE_SIGACTION
206  struct sigaction sigact;
207 #endif
208  static char * localaddr = defaultlocaladdress;
209  static char * cmaaddr = defaultCMAaddr;
210  static int debug = 0;
211  gboolean anyportpermitted = TRUE;
212  static int mcast_ttl = 31;
213  static gboolean stay_in_foreground = FALSE;
214  static gboolean dostatusonly = FALSE;
215  static gboolean dokillonly = FALSE;
216  static gboolean dynamicport = FALSE;
217  static char* pidfile = NULL;
218  gboolean bindret = FALSE;
219  PidRunningStat rstat;
220  int ret;
221 
222  GError *error = NULL;
223  static GOptionEntry long_options[] = {
224  {"bind", 'b', 0, G_OPTION_ARG_STRING, &localaddr, "<address:port-to-listen-on-locally>", NULL},
225  {"cmaaddr", 'c', 0, G_OPTION_ARG_STRING, &cmaaddr, "<address:port-of-CMA>", NULL},
226  {"debug", 'd', 0, G_OPTION_ARG_INT, &debug, "set debug level", NULL},
227  {"dynamic", 'D', 0, G_OPTION_ARG_NONE, &dynamicport," force dynamic port", NULL},
228  {"ttl", 't', 0, G_OPTION_ARG_INT, &mcast_ttl, "<multicast-ttl> (default is 31)", NULL},
229  {"kill", 'k', 0, G_OPTION_ARG_NONE, &dokillonly, "send SIGTERM to the running service", NULL},
230  {"pidfile", 'p', 0, G_OPTION_ARG_STRING, &pidfile, "<pid-file-pathname>", NULL},
231  {"status", 's', 0, G_OPTION_ARG_NONE, &dostatusonly, "report nanoprobe status", NULL},
232 #ifdef HAS_FORK
233  {"foreground", 'f', 0, G_OPTION_ARG_NONE, &stay_in_foreground, "stay in foreground", NULL},
234 #endif
235  {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
236  };
237 
238  GOptionContext *context = g_option_context_new("- start nanoprobe");
239  g_option_context_add_main_entries(context, long_options, NULL);
241 
242 
243  if(!(g_option_context_parse(context, &argc, &argv, &error))) {
244  g_print("option parsing failed %s\n", error->message);
245  usage(argv[0]);
246  exit(1);
247  }
248 
249  BINDDEBUG(NanoprobeMain);
250 
251  if(debug > 0 && debug <= 5) {
252  while(debug--) {
253  proj_class_incr_debug(NULL);
254  }
255  }
256 
257 
258  if (pidfile == NULL) {
260  }
261 
262  if (dostatusonly) {
263  rstat = are_we_already_running(pidfile, NULL);
264  ret = pidrunningstat_to_status(rstat);
265  g_free(pidfile);
266  exit(ret);
267  }
268  if (dokillonly) {
269  int rc = kill_pid_service(pidfile, SIGTERM);
270  if (rc != 0) {
271  fprintf(stderr, "%s: could not stop service [%s]\n", "nanoprobe", g_strerror(errno));
272  g_warning("%s: could not stop service [%s]\n", "nanoprobe", g_strerror(errno));
273  g_free(pidfile);
274  exit(1);
275  }
276  while (are_we_already_running(pidfile, NULL) == PID_RUNNING) {
277  usleep(100000); // 1/10 second
278  }
279  g_free(pidfile);
280  exit(0);
281  }
282  daemonize_me(stay_in_foreground, SEP, pidfile);
283 
284  assimilation_openlog(argv[0]);
285 
287  g_warning("This OS DOES NOT support dual ipv4/v6 sockets - this may not work!!");
288  }
289 #ifndef HAVE_SIGACTION
290  signal(SIGTERM, catch_a_signal);
291  if (stay_in_foreground) {
292  if (signal(SIGINT, catch_a_signal) == SIG_IGN) {
293  signal(SIGINT, SIG_IGN);
294  }
295  }else{
296  signal(SIGINT, SIG_IGN);
297  }
298 #else
299  memset(&sigact, 0, sizeof(sigact));
300  sigact.sa_handler = catch_a_signal;
301  sigaction(SIGTERM, &sigact, NULL);
302  if (stay_in_foreground) {
303  struct sigaction oldact;
304  sigaction(SIGINT, &sigact, &oldact); // Need to check to see if it's already blocked.
305  if (oldact.sa_handler == SIG_IGN) {
306  // OOPS - put it back like it was
307  sigaction(SIGINT, &oldact, NULL);
308  }
309  }else{
310  // Always ignore SIGINT when in the background
311  struct sigaction ignoreme;
312  memset(&ignoreme, 0, sizeof(ignoreme));
313  ignoreme.sa_handler = SIG_IGN;
314  sigaction(SIGINT, &ignoreme, NULL);
315  }
316  sigaction(SIGUSR1, &sigact, NULL);
317  sigaction(SIGUSR2, &sigact, NULL);
318 #endif
319 
320  config->setframe(config, CONFIGNAME_OUTSIG, &signature->baseclass);
321 
322  // Create a network transport object for normal UDP packets
323  nettransport = &(reliableudp_new(0, config, decoder, 0)->baseclass.baseclass);
324  g_return_val_if_fail(NULL != nettransport, 2);
325 
326 
327  // Construct the NetAddr we'll talk to (it defaults to a mcast address nowadays)
328  destaddr = netaddr_string_new(cmaaddr);
329  g_info("CMA address: %s", cmaaddr);
330  if (destaddr->ismcast(destaddr)) {
331  if (!nettransport->setmcast_ttl(nettransport, mcast_ttl)) {
332  g_warning("Unable to set multicast TTL to %d [%s %d]", mcast_ttl
333  , g_strerror(errno), errno);
334  }
335  }
336 
337  g_return_val_if_fail(NULL != destaddr, 3);
338  g_return_val_if_fail(destaddr->port(destaddr) != 0, 4);
339  config->setaddr(config, CONFIGNAME_CMAINIT, destaddr);
340 
341 
342  if (dynamicport) {
343  anyportpermitted = TRUE;
344  }else{
345  // Construct a NetAddr to bind to (listen from) (normally ANY address)
346  localbindaddr = netaddr_string_new(localaddr);
347  g_return_val_if_fail(NULL != localbindaddr, 5);
348 
349  // Bind to the requested address (defaults to ANY as noted above)
350  bindret = nettransport->bindaddr(nettransport, localbindaddr, anyportpermitted);
351  UNREF(localbindaddr);
352  }
353  if (!bindret) {
354  // OOPS! Address:Port already busy...
355  if (anyportpermitted) {
356  guint8 anyaddr[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
357  localbindaddr = netaddr_ipv6_new(anyaddr, 0);
358  g_return_val_if_fail(NULL != localbindaddr, 5);
359  bindret = nettransport->bindaddr(nettransport, localbindaddr, FALSE);
360  UNREF(localbindaddr);
361  localbindaddr = NULL;
362  g_return_val_if_fail(bindret, 6);
363  }else{
364  g_warning("Cannot bind to local address [%s] and cannot use any free port."
365  , localaddr);
366  return(5);
367  }
368  }
369  {
370  NetAddr* boundaddr = nettransport->boundaddr(nettransport);
371  if (boundaddr) {
372  char * boundstr = boundaddr->baseclass.toString(&boundaddr->baseclass);
373  g_info("Local address: %s", boundstr);
374  g_free(boundstr);
375  UNREF(boundaddr);
376  }else{
377  g_warning("Unable to determine local address!");
378  }
379  }
380 
381  // Connect up our network transport into the g_main_loop paradigm
382  // so we get dispatched when packets arrive
383  netpkt = netgsource_new(nettransport, NULL, G_PRIORITY_HIGH, FALSE, NULL, 0, NULL);
384 
385  // Observe all unclaimed packets
386  otherlistener = listener_new(config, 0);
387  otherlistener->got_frameset = gotnetpkt;
388  netpkt->addListener(netpkt, 0, otherlistener);
389  otherlistener->associate(otherlistener,netpkt);
390  g_timeout_add_seconds(1, check_for_signals, NULL);
391 
392  // Unref the "other" listener - netpkt et al holds references to it
393  UNREF(otherlistener);
394 
395  // Free signature frame
396  UNREF2(signature);
397 
398  // Free misc addresses
399  UNREF(destaddr);
400 
401  nano_start_full("netconfig", 900, netpkt, config);
402  g_info("Starting version %s: licensed under %s", VERSION_STRING, LONG_LICENSE_STRING);
403 
404  // Free config object
405  UNREF(config);
406 
407  mainloop = g_main_loop_new(g_main_context_default(), TRUE);
408 
409  /********************************************************************
410  * Start up the main loop - run our test program...
411  * (the one pretending to be both the nanoprobe and the CMA)
412  ********************************************************************/
413  g_main_loop_run(mainloop);
414 
415  /********************************************************************
416  * We exited the main loop. Shut things down.
417  ********************************************************************/
418 
419  remove_pid_file(pidfile);
420  g_free(pidfile);
421 
422  nano_shutdown(TRUE); // Tell it to shutdown and print stats
423  g_info("%-35s %8d", "Count of 'other' pkts received:", wirepktcount);
424 
425  UNREF(nettransport);
426 
427  // This two calls need to be last - and in this order...
428  // (I wish the documentation on this stuff was clearer... Sigh...)
429  //g_main_context_unref(g_main_context_default());
430  g_main_loop_unref(mainloop);
431  g_source_unref(&netpkt->baseclass); // Not sure why this is needed...
432  g_source_destroy(&netpkt->baseclass); // Not sure why this is needed...
433  mainloop = NULL; netpkt = NULL;
434 
435 
436  // At this point - nothing should show up - we should have freed everything
437  if (proj_class_live_object_count() > 0) {
439  g_warning("Too many objects (%d) alive at end of test.",
441  ++errcount;
442  }else{
443  g_info("No objects left alive. Awesome!");
444  }
446  return(errcount <= 127 ? errcount : 127);
447 }