RPi Locator and Display Services
cmdDS.c
Go to the documentation of this file.
1 
16 /*
17  * Program Standards passed from compiler
18  */
19 #ifndef PACKAGE_VERSION
20  #define PACKAGE_VERSION "0.9.0"
21 #endif
22 #ifndef PACKAGE_NAME
23  #define PACKAGE_NAME "cmdDS"
24 #endif
25 #ifndef PACKAGE_DESCRIPTION
26  #define PACKAGE_DESCRIPTION "Display Messages from other Raspberry Pi's on the network."
27 #endif
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <glib-unix.h>
34 #include <gio/gnetworking.h>
35 #include <ifaddrs.h>
36 
37 #ifndef G_OPTION_FLAG_NONE
38  #define G_OPTION_FLAG_NONE 0
39 #endif
40 
41 #define UDP_COMM_PORT 48029
42 #define UDP_BROADCAST_PORT 48028
43 #define UDP_REGULAR_PORT 48027
44 #define MS_TEN_MINUTES 600000
45 
46 #define SZ_TIMESTAMP_BUFF 32
47 #define SZ_PARAMS_BUFF 64
48 #define SZ_RMTADDR_BUFF 256
49 #define SZ_MESSAGE_BUFF 512
50 #define SZ_RESPONSE_BUFF 256
51 
52 #define SZ_CHAR_LABEL 48
53 #define SZ_INFO_BUFF 256
54 #define SZ_CHAR_BUFF 128
55 #define SZ_LINE_BUFF 512
56 #define SZ_COMM_BUFF 256
57 
58 #define SKN_UDP_ANY_PORT 0
59 #define ARY_MAX_INTF 8
60 #define PLATFORM_ERROR -1
61 
62 typedef struct _ipBroadcastArray {
63  char cbName[SZ_CHAR_BUFF];
69  int defaultIndex;
70  int count; // index = count - 1
72 
73 
74 typedef struct _registryData {
75  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
76  gchar ch_from[SZ_RMTADDR_BUFF];
77  gchar ch_name[SZ_RMTADDR_BUFF];
78  gchar ch_ip[SZ_PARAMS_BUFF];
79  gchar ch_port[SZ_PARAMS_BUFF];
80  gchar ch_message[SZ_MESSAGE_BUFF];
82 
83 typedef struct _signalData {
84  guint gTimeoutId;
85  GMainLoop *loop;
86  gchar * signalName;
88 
89 typedef struct _controlData {
90  guint gSourceId;
92  GResolver *resolver;
93  GMainLoop *loop;
94  guint gRegCount;
95  GSocket *gbSock;
96  gchar ch_read[SZ_MESSAGE_BUFF];
97  gchar ch_request[SZ_MESSAGE_BUFF];
98  gchar ch_response[SZ_MESSAGE_BUFF];
99  gchar ch_intfName[SZ_RMTADDR_BUFF];
100  gchar ch_this_ip[SZ_RMTADDR_BUFF];
102  guint gUDPPort;
104 
105 gchar * skn_get_timestamp();
106 gchar * skn_strip(gchar * alpha);
107 gchar * skn_gio_condition_to_string(GIOCondition condition);
108 PPRegData udp_registry_response_parser(PRegData msg, gchar *response);
109 
110 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char * intf, char * ipv4);
111 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB);
112 gint skn_get_default_interface_name(char *pchDefaultInterfaceName);
113 gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray pab);
114 
115 static gboolean cb_unix_signal_handler(PUSignalData psig);
116 static gboolean cb_udp_request_handler(GSocket *socket, GIOCondition condition, PControlData pctrl);
117 static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl);
118 
119 
124 gchar * skn_strip(gchar * alpha) {
125  if (alpha == NULL || strlen(alpha) < 1)
126  return(alpha);
127 
128  int len = strlen(alpha);
129  int end = len - 1;
130  int start = 0;
131 
132  // use isgraph() or !isspace() vs isalnum() to allow ['|' ';' '%']
133  while ( !g_unichar_isgraph(alpha[end]) && end > 0 ) { // remove trailing non-alphanumeric chars
134  alpha[end--] = 0;
135  }
136 
137  len = strlen(alpha);
138  while ( !g_unichar_isalnum(alpha[start]) && start < len ) { // find first non-alpha stricter
139  start++;
140  }
141  if (start < len && start > 0) { // move in place
142  end = len - start;
143  memmove(&alpha[0], &alpha[start], end);
144  alpha[end] = 0;
145  }
146 
147  return(alpha);
148 }
149 
150 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(gchar * intf, gchar * ipv4) {
151  PIPBroadcastArray paB = g_new0(IPBroadcastArray, 1);
152 
154  g_utf8_strncpy(intf, paB->chDefaultIntfName, SZ_CHAR_BUFF);
155  g_utf8_strncpy(ipv4, paB->ipAddrStr[paB->defaultIndex], SZ_CHAR_BUFF);
156  } else {
157  g_warning("[REGISTRY] InterfaceName and Address: unable to access information.");
158  return(NULL);
159  }
160  return (paB);
161 }
162 
170 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB) {
171  struct ifaddrs * ifap;
172  struct ifaddrs * p;
173  gint rc = 0;
174 
175  memset(paB, 0, sizeof(IPBroadcastArray));
176  paB->count = 0;
177  paB->defaultIndex = 0;
178  strcpy(paB->cbName, "IPBroadcastArray");
179 
181  if (rc == EXIT_FAILURE) { // Alternate method for Mac: 'route -n -A inet'
182  g_warning("[REGISTRY] No Default Network Interfaces Found!.");
183  paB->chDefaultIntfName[0] = 0;
184  }
185  rc = getifaddrs(&ifap);
186  if (rc != 0) {
187  g_warning("[REGISTRY] No Network Interfaces Found at All ! %d:%d:%s", rc, errno, strerror(errno) );
188  return (PLATFORM_ERROR);
189  }
190  p = ifap;
191 
192  while (p && (paB->count < ARY_MAX_INTF)) {
193  if (p->ifa_addr != NULL && p->ifa_addr->sa_family == AF_INET && ((p->ifa_flags & IFF_BROADCAST) > 0)) {
194 
195  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_addr)->sin_addr, paB->ipAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
196  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_netmask)->sin_addr, paB->maskAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
197  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_broadaddr)->sin_addr, paB->broadAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
198 
199  strncpy(paB->ifNameStr[paB->count], p->ifa_name, (SZ_CHAR_BUFF -1));
200 
201  /* Take match as the default */
202  if (strcmp(paB->chDefaultIntfName, p->ifa_name) == 0) {
203  paB->defaultIndex = paB->count;
204  }
205 
206  paB->count++;
207  }
208  p = p->ifa_next;
209  } // end while
210  freeifaddrs(ifap);
211 
212  return (paB->count);
213 }
214 
231 gint skn_get_default_interface_name(char *pchDefaultInterfaceName) {
232  FILE *f_route;
233  char line[SZ_INFO_BUFF], *dRoute = NULL, *iName = NULL;
234 
235  f_route = fopen("/proc/net/route", "r");
236  if (f_route != NULL) {
237  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
238  iName = strtok(line, "\t");
239  dRoute = strtok(NULL, "\t");
240 
241  if (iName != NULL && dRoute != NULL) {
242  if (strcmp(dRoute, "00000000") == 0) {
243  strncpy(pchDefaultInterfaceName, iName, (SZ_INFO_BUFF - 1));
244  break;
245  }
246  }
247  }
248  fclose(f_route);
249 
250  return (EXIT_SUCCESS);
251  }
252  g_print("[REGISTRY] Opening ProcFs for RouteInfo Failed: %d:%s, Alternate method will be attempted.", errno, strerror(errno));
253 
254  f_route = popen("route -n get 0.0.0.0", "r"); // for linux 'route -n -A inet', with interface at line_word[7]
255  if (f_route != NULL) {
256  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
257  dRoute = strtok(line, ":");
258  iName = strtok(NULL, "\n");
259  if (strcmp(skn_strip(dRoute), "interface") == 0) {
260  strncpy(pchDefaultInterfaceName, skn_strip(iName), (SZ_INFO_BUFF - 1));
261  break;
262  }
263  }
264  fclose(f_route);
265 
266  return (EXIT_SUCCESS);
267  } else {
268  g_warning("[REGISTRY] Alternate method to get RouteInfo Failed: %d:%s", errno, strerror(errno));
269  return (EXIT_FAILURE);
270  }
271 
272 }
282 gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray paB) {
283  struct sockaddr_in remaddr; /* remote address */
284  socklen_t addrlen = sizeof(remaddr); /* length of addresses */
285  gchar *request = "urn:rpilocator - Rpi Where Are You?";
286  gint vIndex = 0;
287  gint i_socket = g_socket_get_fd(gSock);
288 
289  g_print("[REGISTRY] Broadcast Socket Bound to %s\n", paB->ipAddrStr[paB->defaultIndex]);
290 
291  for (vIndex = 0; vIndex < paB->count; vIndex++) {
292  memset(&remaddr, 0, sizeof(remaddr));
293  remaddr.sin_family = AF_INET;
294  remaddr.sin_addr.s_addr = inet_addr(paB->broadAddrStr[vIndex]);
295  remaddr.sin_port = htons(UDP_BROADCAST_PORT);
296 
297  if (sendto(i_socket, request, strlen(request), 0, (struct sockaddr *) &remaddr, addrlen) < 0) {
298  g_warning("SendTo() Timed out; Failure code=%d, etext=%s", errno, strerror(errno));
299  break;
300  }
301  g_print("[REGISTRY] Query Broadcasted on %s:%s:%d\n", paB->ifNameStr[vIndex], paB->broadAddrStr[vIndex], UDP_BROADCAST_PORT);
302  }
303 
304  return(TRUE);
305 }
306 
307 static gboolean cb_unix_signal_handler(PUSignalData psig) {
308  g_message("DisplayService::cb_unix_signal_handler() %s Unix Signal Received => Shutdown Initiated!\n", psig->signalName);
309  g_main_loop_quit(psig->loop);
310  return ( G_SOURCE_REMOVE );
311 }
312 gchar * skn_get_timestamp() {
313  GDateTime *stamp = g_date_time_new_now_local();
314  gchar *response = g_date_time_format(stamp,"%F.%T");
315 
316  return(response);
317 }
318 
329 PPRegData udp_registry_response_parser(PRegData msg, gchar *response) {
330  gboolean rc = FALSE;
331  gboolean final_rc = FALSE;
332  gchar ** lines = NULL;
333  gchar *current_line = NULL;
334  gchar ** entries = NULL;
335  gchar *current_entry = NULL;
336  gchar ** key_value = NULL;
337  PRegData *msgs;
338  PRegData preg = NULL;
339  gint h_index = 0;
340  gint v_index = 0;
341  gint o_index = 0;
342  gint a_count = 0;
343  gint e_count = 0;
344 
345  if (g_utf8_strchr(response, -1, '|') == NULL) { // must be a registry entry
346  return (NULL);
347  }
348 
349  lines = g_strsplit_set(response, "|;%", -1); // get whole entries
350  if ((NULL == lines) || (g_strv_length(lines) < 1)) {
351  return(NULL);
352  }
353 
354  a_count = g_strv_length(lines);
355  msgs = g_new0(PRegData, a_count);
356  for(o_index = 0; o_index < a_count; o_index += 1) {
357  msgs[o_index] = g_new0(RegData, 1);
358  memmove(msgs[o_index], msg, sizeof(RegData));
359  }
360 
361  o_index = 0;
362  current_line = lines[h_index];
363  while ((NULL != current_line) && (h_index < a_count)) { // do each entry
364  if(g_utf8_strlen(current_line, -1) < 1) {
365  current_line = lines[++h_index];
366  continue;
367  }
368 
369  v_index = 0;
370  entries = g_strsplit_set(current_line, ",", -1);
371  current_entry = entries[v_index];
372  e_count = g_strv_length(entries);
373  preg = msgs[o_index];
374  rc = FALSE;
375 
376  while((NULL != current_entry) && (v_index < e_count)) {
377  if(g_utf8_strlen(current_entry, -1) < 1) {
378  current_entry = entries[++v_index];
379  continue;
380  }
381 
382  // get name, ip, port
383 
384  key_value = g_strsplit_set(current_entry, "=", -1);
385  if((key_value != NULL) && (g_strv_length(key_value) > 0)) {
386  if(g_strrstr(key_value[0], "a") != NULL) {
387  final_rc = rc = TRUE;
388  g_utf8_strncpy(preg->ch_name, key_value[1], SZ_RMTADDR_BUFF);
389  }
390  if(g_strrstr(key_value[0], "i") != NULL) {
391  final_rc = rc = TRUE;
392  g_utf8_strncpy(preg->ch_ip, key_value[1], SZ_RMTADDR_BUFF);
393  }
394  if(g_strrstr(key_value[0], "o") != NULL) {
395  final_rc = rc = TRUE;
396  g_utf8_strncpy(preg->ch_port, key_value[1], SZ_RMTADDR_BUFF);
397  }
398  }
399  g_strfreev(key_value);
400  current_entry = entries[++v_index];
401  } // end entries
402 
403  if (rc && (g_utf8_strlen(preg->ch_ip, -1) > 6)) { // only move if used and valid
404  o_index += 1;
405  }
406  g_strfreev(entries);
407 
408  h_index +=1;
409  current_line = lines[h_index];
410  } // end lines
411  g_strfreev(lines);
412 
413  if (final_rc) {
414  while(o_index < a_count) {
415  g_free(msgs[o_index]);
416  msgs[o_index++] = NULL;
417  }
418  return(msgs);
419  } else {
420  while(o_index < a_count) {
421  g_free(msgs[o_index]);
422  msgs[o_index++] = NULL;
423  }
424  g_free(msgs);
425  return(NULL);
426  }
427 }
428 
429 static gboolean cb_udp_request_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl) {
430  GError *error = NULL;
431  GSocketAddress *gsRmtAddr = NULL;
432  GInetAddress *gsAddr = NULL;
433  gchar * rmtHost = NULL;
434  gchar *stamp = skn_get_timestamp();
435  gssize gss_receive = 0;
436 
437  if ((condition & G_IO_HUP) || (condition & G_IO_ERR) || (condition & G_IO_NVAL)) { /* SHUTDOWN THE MAIN LOOP */
438  g_message("DisplayService::cb_udp_request_handler(error) G_IO_HUP => %s\n", skn_gio_condition_to_string(condition));
439  g_main_loop_quit(pctrl->loop);
440  return ( G_SOURCE_REMOVE );
441  }
442  if (condition != G_IO_IN) {
443  g_message("DisplayService::cb_udp_request_handler(error) NOT G_IO_IN => %s\n", skn_gio_condition_to_string(condition));
444  return (G_SOURCE_CONTINUE);
445  }
446 
447  /*
448  * If socket times out before reading data any operation will error with 'G_IO_ERROR_TIMED_OUT'.
449  */
450  gss_receive = g_socket_receive_from (gSock, &gsRmtAddr, pctrl->ch_read, sizeof(pctrl->ch_read), NULL, &error);
451  if (error != NULL) { // gss_receive = Number of bytes read, or 0 if the connection was closed by the peer, or -1 on error
452  g_error("g_socket_receive_from() => %s", error->message);
453  g_clear_error(&error);
454  return (G_SOURCE_CONTINUE);
455  }
456  if (gss_receive > 0 ) {
457  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) ) {
458  gsAddr = g_inet_socket_address_get_address( G_INET_SOCKET_ADDRESS(gsRmtAddr) );
459  if ( G_IS_INET_ADDRESS(gsAddr) ) {
460  g_object_ref(gsAddr);
461  rmtHost = g_resolver_lookup_by_address (pctrl->resolver, gsAddr, NULL, NULL);
462  if (NULL == rmtHost) {
463  rmtHost = g_inet_address_to_string ( gsAddr);
464  }
465  }
466  }
467  pctrl->ch_read[gss_receive] = 0;
468  g_snprintf(pctrl->ch_request, sizeof(pctrl->ch_request), "[%s]MSG From=%s, Msg=%s", stamp, rmtHost, pctrl->ch_read);
469  g_free(rmtHost);
470  g_snprintf(pctrl->ch_response, sizeof(pctrl->ch_response), "%d %s", 202, "Accepted");
471  } else {
472  g_snprintf(pctrl->ch_request, sizeof(pctrl->ch_request), "%s", "Error: Input not Usable");
473  g_snprintf(pctrl->ch_response, sizeof(pctrl->ch_response), "%d %s", 406, "Not Acceptable");
474  }
475 
476  g_socket_send_to (gSock, gsRmtAddr, pctrl->ch_response, strlen(pctrl->ch_response), NULL, &error);
477  if (error != NULL) { // gss_send = Number of bytes written (which may be less than size ), or -1 on error
478  g_error("g_socket_send_to() => %s", error->message);
479  g_clear_error(&error);
480  }
481 
482  g_free(stamp);
483  g_print("%s\n", pctrl->ch_request);
484 
485  if ( G_IS_INET_ADDRESS(gsAddr) )
486  g_object_unref(gsAddr);
487 
488  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
489  g_object_unref(gsRmtAddr);
490 
491 
492  return (G_SOURCE_CONTINUE);
493 }
494 
495 static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl) {
496  GError *error = NULL;
497  GSocketAddress *gsRmtAddr = NULL;
498  GInetAddress *gsAddr = NULL;
499  PRegData message = NULL;
500  PRegData msg = NULL;
501  PRegData *msgs;
502  gchar * rmtHost = NULL;
503  gssize gss_receive = 0;
504  gchar *stamp = skn_get_timestamp();
505  gchar response[SZ_RESPONSE_BUFF];
506  gint h_index = 0;
507  gchar *converted = NULL;
508 
509  if ((condition & G_IO_HUP) || (condition & G_IO_ERR) || (condition & G_IO_NVAL)) { /* SHUTDOWN THE MAIN LOOP */
510  g_message("DisplayService::cb_udp_broadcast_response_handler(error) Operational Error / Shutdown Signaled => %s\n", skn_gio_condition_to_string(condition));
511  g_main_loop_quit(pctrl->loop);
512  return ( G_SOURCE_REMOVE );
513  }
514  if (condition != G_IO_IN) {
515  g_message("DisplayService::cb_udp_broadcast_response_handler(error) NOT G_IO_IN => %s\n", skn_gio_condition_to_string(condition));
516  return (G_SOURCE_CONTINUE);
517  }
518 
519  /*
520  * Allocate a new queue message and read incoming request directly into it */
521  message = g_new0(RegData,1);
522 
523  /*
524  * If socket times out before reading data any operation will error with 'G_IO_ERROR_TIMED_OUT'.
525  * Read Request Message and get Requestor IP Address or Name
526  */
527  gss_receive = g_socket_receive_from (gSock, &gsRmtAddr, message->ch_message, sizeof(message->ch_message), NULL, &error);
528  if (error != NULL) { // gss_receive = Number of bytes read, or 0 if the connection was closed by the peer, or -1 on error
529  g_error("g_socket_receive_from() => %s", error->message);
530  g_clear_error(&error);
531  g_free(message);
532  g_free(stamp);
533  return (G_SOURCE_CONTINUE);
534  }
535  if (gss_receive > 0 ) {
536  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) ) {
537  gsAddr = g_inet_socket_address_get_address( G_INET_SOCKET_ADDRESS(gsRmtAddr) );
538  if ( G_IS_INET_ADDRESS(gsAddr) ) {
539  g_object_ref(gsAddr);
540  rmtHost = g_resolver_lookup_by_address (pctrl->resolver, gsAddr, NULL, NULL);
541  if (NULL == rmtHost) {
542  rmtHost = g_inet_address_to_string ( gsAddr);
543  }
544  }
545  }
546 
547  /*
548  * Convert to UTF8
549  */
550  converted = g_convert (message->ch_message, gss_receive, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
551  if (NULL != converted) {
552  g_utf8_strncpy(message->ch_message, converted, sizeof(message->ch_message));
553  g_free(converted);
554  }
555 
556  g_utf8_strncpy(message->ch_timestamp, stamp, sizeof(message->ch_timestamp));
557  g_utf8_strncpy(message->ch_from, rmtHost, sizeof(message->ch_from));
558  if ( (msgs = udp_registry_response_parser(message, message->ch_message)) != NULL ) {
559  /*
560  * Send it to be processed by a message handler */
561  g_free(message);
562  h_index = 0;
563  msg = (PRegData)msgs[h_index];
564  while ( msg != NULL ) {
565  g_print("[REGISTRY] From=%s, Node=%s, IP=%s, Port=%s\n", msg->ch_from, msg->ch_name, msg->ch_ip, msg->ch_port);
566  g_free(msg);
567  msg = (PRegData)msgs[++h_index];
568  }
569  g_free(msgs);
570  } else {
571  g_free(message);
572 
573  /* Format: name=rpi_locator_service,ip=10.100.1.19,port=48028|
574  * name=cmdline_display_service,ip=10.100.1.19,port=48029|
575  */
576 
577  g_snprintf(response, sizeof(response),
578  "name=rpi_locator_service,ip=%s,port=48028|name=%s,ip=%s,port=%d|",
579  pctrl->ch_this_ip, pctrl->pch_service_name, pctrl->ch_this_ip, pctrl->gUDPPort);
580  /*
581  * Send Registry Response to caller */
582  g_socket_send_to (gSock, gsRmtAddr, response, strlen(response), NULL, &error);
583  if (error != NULL) { // gss_send = Number of bytes written (which may be less than size ), or -1 on error
584  g_error("g_socket_send_to() => %s", error->message);
585  g_free(message);
586  g_clear_error(&error);
587  }
588  }
589  }
590  g_free(stamp);
591  g_free(rmtHost);
592 
593  if ( G_IS_INET_ADDRESS(gsAddr) )
594  g_object_unref(gsAddr);
595 
596  if ( G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
597  g_object_unref(gsRmtAddr);
598 
599  return (G_SOURCE_CONTINUE);
600 }
601 
602 
603 gchar * skn_gio_condition_to_string(GIOCondition condition) {
604  gchar *value = NULL;
605 
606  switch(condition) {
607  case G_IO_IN:
608  value = "There is data to read.";
609  break;
610  case G_IO_OUT:
611  value = "Data can be written (without blocking).";
612  break;
613  case G_IO_PRI:
614  value = "There is urgent data to read.";
615  break;
616  case G_IO_ERR:
617  value = "Error condition.";
618  break;
619  case G_IO_HUP:
620  value = "Hung up (the connection has been broken, usually for pipes and sockets).";
621  break;
622  case G_IO_NVAL:
623  value = "Invalid request. The file descriptor is not open.";
624  break;
625  default:
626  value = "Unknown GIOCondition!";
627  }
628 
629  return (value);
630 }
631 
632 int main(int argc, char **argv) {
633 
634  GError *error = NULL;
635  GSocket *gSock = NULL;
636  GSocketAddress *gsAddr = NULL;
637  GInetAddress *anyAddr = NULL;
638  GSource * gSource = NULL;
639  GSocketAddress *gbAddr = NULL;
640  GSource * gBroadSource = NULL;
641  guint gSourceId = 0;
642  ControlData cData;
643  PIPBroadcastArray paB = NULL;
644 
645  USignalData sigTerm;
646  USignalData sigInt;
647  USignalData sigHup;
648 
649  guint gUDPPort = 0;
650 
651  GOptionContext *gOptions = NULL;
652  GOptionEntry pgmOptions[] = {
653  {"service-name", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &cData.pch_service_name, "Alternate Service Name", "cmdline_display_service"},
654  {"udp_port_number", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &gUDPPort, "UDP Port Number to listen on.", "port number defaults to 48029"},
655  {NULL}
656  };
657 
658  cData.pch_service_name = NULL;
659 
660  gOptions = g_option_context_new ("UDP message display service for IOT.");
661  g_option_context_add_main_entries (gOptions, pgmOptions, NULL);
662 
663  g_option_context_parse (gOptions, &argc, &argv, &error);
664  if (error != NULL) {
665  g_error("g_option_context_parse() => %s", error->message);
666  g_clear_error(&error);
667  exit(EXIT_FAILURE);
668  }
669  g_option_context_free(gOptions);
670 
671  if (gUDPPort == 0) {
672  gUDPPort = cData.gUDPPort = UDP_COMM_PORT;
673  } else {
674  cData.gUDPPort = gUDPPort;
675  }
676  if (NULL == cData.pch_service_name) {
677  cData.pch_service_name = "cmdline_display_service";
678  }
679 
680 
681  paB = skn_get_default_interface_name_and_ipv4_address((char *)&cData.ch_intfName, (char *)&cData.ch_this_ip);
682  if (NULL == paB) {
683  g_error("skn_skn_get_default_interface_name_and_ipv4_address() => Unable to discover network interface or non-available.");
684  exit(EXIT_FAILURE);
685  }
686 
687  sigHup.loop = sigTerm.loop = sigInt.loop = cData.loop = g_main_loop_new(NULL, FALSE);
688  sigTerm.signalName = "SIGTERM";
689  sigInt.signalName = "SIGINT";
690  sigHup.signalName = "SIGHUP";
691 
692  cData.resolver = g_resolver_get_default();
693 
694  gSock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
695  if (error != NULL) {
696  g_error("g_socket_new() => %s", error->message);
697  g_clear_error(&error);
698  exit(EXIT_FAILURE);
699  }
700 
701  anyAddr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
702  gsAddr = g_inet_socket_address_new(anyAddr, gUDPPort);
703 
704  g_socket_bind(gSock, gsAddr, TRUE, &error);
705  if (error != NULL) {
706  g_error("g_socket_bind() => %s", error->message);
707  g_clear_error(&error);
708  exit(EXIT_FAILURE);
709  }
710 
711  /*
712  * Create broadcast UDP Socket for receiving messages */
713  cData.gbSock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
714  if (error != NULL) {
715  g_error("g_socket_new(broadcast) => %s", error->message);
716  g_clear_error(&error);
717  exit(EXIT_FAILURE);
718  }
719  g_socket_set_broadcast(cData.gbSock, TRUE);
720 
721  gbAddr = g_inet_socket_address_new(anyAddr, UDP_BROADCAST_PORT);
722  g_object_unref(anyAddr);
723 
724  g_socket_bind(cData.gbSock, gbAddr, TRUE, &error);
725  if (error != NULL) {
726  g_error("g_socket_bind() => %s", error->message);
727  g_clear_error(&error);
728  exit(EXIT_FAILURE);
729  }
730 
731  /*
732  * Create and Add socket to gmain loop for service (i.e. polling socket) */
733  gSource = g_socket_create_source (gSock, G_IO_IN, NULL);
734  g_source_set_callback (gSource, (GSourceFunc) cb_udp_request_handler, &cData, NULL); // its really a GSocketSourceFunc
735  cData.gSourceId = gSourceId = g_source_attach (gSource, NULL);
736 
737  gBroadSource = g_socket_create_source(cData.gbSock, G_IO_IN, NULL);
738  g_source_ref(gBroadSource);
739  g_source_set_callback (gBroadSource, (GSourceFunc) cb_udp_broadcast_response_handler, &cData, NULL); // its really a GSocketSourceFunc
740  g_source_attach (gBroadSource, NULL);
741 
742  /*
743  * Handle ctrl-break and kill signals cleanly */
744  g_unix_signal_add (SIGINT, (GSourceFunc) cb_unix_signal_handler, &sigInt); // SIGINT signal (Ctrl+C)
745  g_unix_signal_add (SIGHUP, (GSourceFunc) cb_unix_signal_handler, &sigHup);
746  g_unix_signal_add (SIGTERM,(GSourceFunc) cb_unix_signal_handler, &sigTerm);
747 
748 
749  /*
750  * Broadcast Registry Request: 10.100.1.255 */
752  g_message("cmdDS: Ready to do Good, on %s:%s:%d...\n", cData.ch_intfName, cData.ch_this_ip, gUDPPort);
753 
754  g_main_loop_run(cData.loop);
755  }
756 
757  g_main_loop_unref(cData.loop);
758 
759  g_source_unref(gBroadSource);
760  g_source_unref(gSource);
761  g_object_unref(cData.gbSock);
762  g_object_unref(gSock);
763  g_object_unref(gbAddr);
764  g_object_unref(gsAddr);
765  g_object_unref(cData.resolver);
766 
767  g_message("cmdDS: normal shutdown...");
768 
769  exit(EXIT_SUCCESS);
770 }
char ifNameStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:68
#define ARY_MAX_INTF
Definition: cmdDS.c:59
char ipAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:69
guint gTimeoutId
Definition: cmdDS.c:84
gchar ch_request[SZ_MESSAGE_BUFF]
Definition: cmdDC.c:112
gchar * pch_service_name
Definition: cmdDS.c:101
#define PLATFORM_ERROR
Definition: cmdDS.c:60
struct _signalData USignalData
char maskAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:70
gchar ch_ip[SZ_PARAMS_BUFF]
Definition: cmdDC.c:85
gchar ch_response[SZ_RESPONSE_BUFF]
Definition: cmdDC.c:113
#define SZ_CHAR_BUFF
Definition: cmdDS.c:54
gchar ch_message[SZ_MESSAGE_BUFF]
Definition: cmdDS.c:80
#define FALSE
struct _signalData * PUSignalData
char cbName[SZ_CHAR_BUFF]
Definition: cmdDC.c:66
static gboolean cb_udp_request_handler(GSocket *socket, GIOCondition condition, PControlData pctrl)
Definition: cmdDS.c:429
struct _ipBroadcastArray * PIPBroadcastArray
#define SZ_RESPONSE_BUFF
Definition: cmdDS.c:50
gchar ch_port[SZ_PARAMS_BUFF]
Definition: cmdDC.c:86
#define UDP_BROADCAST_PORT
Definition: cmdDS.c:42
static gboolean cb_unix_signal_handler(PUSignalData psig)
Definition: cmdDS.c:307
#define SZ_PARAMS_BUFF
Definition: cmdDS.c:47
#define TRUE
gchar * skn_gio_condition_to_string(GIOCondition condition)
Definition: cmdDS.c:603
gint skn_get_default_interface_name(char *pchDefaultInterfaceName)
Definition: cmdDS.c:231
#define SZ_RMTADDR_BUFF
Definition: cmdDS.c:48
gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray pab)
Definition: cmdDS.c:282
struct _ipBroadcastArray IPBroadcastArray
struct _registryData RegData
struct _controlData * PControlData
#define SZ_INFO_BUFF
Definition: cmdDS.c:53
#define G_OPTION_FLAG_NONE
Definition: cmdDS.c:38
GMainLoop * loop
Definition: cmdDC.c:91
gchar * signalName
Definition: cmdDC.c:78
gchar ch_name[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:84
#define UDP_COMM_PORT
Definition: cmdDS.c:41
struct _registryData ** PPRegData
int defaultIndex
Definition: cmdDC.c:72
GSocket * gbSock
Definition: cmdDS.c:95
guint gUDPPort
Definition: cmdDS.c:102
gchar ch_this_ip[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:109
char chDefaultIntfName[SZ_CHAR_BUFF]
Definition: cmdDC.c:67
static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl)
Definition: cmdDS.c:495
PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char *intf, char *ipv4)
struct _registryData * PRegData
struct _controlData ControlData
gchar ch_from[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:83
#define SZ_MESSAGE_BUFF
Definition: cmdDS.c:49
gint skn_get_broadcast_ip_array(PIPBroadcastArray paB)
Definition: cmdDS.c:170
#define SZ_TIMESTAMP_BUFF
Definition: cmdDS.c:46
guint gSourceId
Definition: cmdDS.c:90
gchar * skn_get_timestamp()
Definition: cmdDS.c:312
guint gBroadSourceId
Definition: cmdDS.c:91
gchar ch_timestamp[SZ_TIMESTAMP_BUFF]
Definition: cmdDC.c:82
GMainLoop * loop
Definition: cmdDC.c:77
char broadAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:71
GResolver * resolver
Definition: cmdDC.c:100
gchar * skn_strip(gchar *alpha)
Definition: cmdDS.c:124
int main(int argc, char **argv)
Definition: cmdDS.c:632
PPRegData udp_registry_response_parser(PRegData msg, gchar *response)
Definition: cmdDS.c:329
gchar ch_intfName[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:108
gchar ch_read[SZ_MESSAGE_BUFF]
Definition: cmdDS.c:96