RPi Locator and Display Services
gssdpDC.c
Go to the documentation of this file.
1 
15 /*
16  * Program Standards passed from compiler
17  */
18 #ifndef PACKAGE_VERSION
19  #define PACKAGE_VERSION "0.9.0"
20 #endif
21 #ifndef PACKAGE_NAME
22  #define PACKAGE_NAME "gssdpDC"
23 #endif
24 #ifndef PACKAGE_DESCRIPTION
25  #define PACKAGE_DESCRIPTION "Send Message to Raspberry Pi's on the network."
26 #endif
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <libgssdp/gssdp.h>
34 #include <glib-unix.h>
35 #include <gio/gnetworking.h>
36 #include <ifaddrs.h>
37 
38 #ifndef G_OPTION_FLAG_NONE
39  #define G_OPTION_FLAG_NONE 0
40 #endif
41 
42 
43 #define UDP_DISPLAY_COMM_PORT 48029
44 #define UDP_BROADCAST_PORT 48028
45 #define UDP_REGULAR_PORT 48027
46 #define UDP_CLIENTS_PORT 48026
47 #define MS_TEN_MINUTES 600000
48 #define MSG_DELAY_INTERVAL 10
49 
50 #define SZ_TIMESTAMP_BUFF 32
51 #define SZ_PARAMS_BUFF 64
52 #define SZ_RMTADDR_BUFF 256
53 #define SZ_MESSAGE_BUFF 512
54 #define SZ_RESPONSE_BUFF 256
55 
56 #define SZ_CHAR_LABEL 48
57 #define SZ_INFO_BUFF 256
58 #define SZ_CHAR_BUFF 128
59 #define SZ_LINE_BUFF 512
60 #define SZ_COMM_BUFF 256
61 
62 #define SKN_UDP_ANY_PORT 0
63 #define ARY_MAX_INTF 8
64 #define PLATFORM_ERROR -1
65 
66 typedef struct _ipBroadcastArray {
67  char cbName[SZ_CHAR_BUFF];
73  int defaultIndex;
74  int count; // index = count - 1
76 
77 typedef struct _signalData {
78  GMainLoop *loop;
79  gchar * signalName;
81 
82 typedef struct _registryData {
83  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
84  gchar ch_from[SZ_RMTADDR_BUFF];
85  gchar ch_name[SZ_RMTADDR_BUFF];
86  gchar ch_ip[SZ_PARAMS_BUFF];
87  gchar ch_port[SZ_PARAMS_BUFF];
88  gchar pch_message[SZ_MESSAGE_BUFF];
90 
91 typedef struct _gssdpRegistryData {
92  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
93  gchar ch_urn[SZ_RMTADDR_BUFF];
94  gchar ch_location[SZ_RMTADDR_BUFF];
95  gchar ch_status[SZ_PARAMS_BUFF];
97 
98 typedef struct _controlData {
99  GMainLoop *loop;
100  USignalData sigTerm;
101  USignalData sigInt;
102  USignalData sigHup;
103  GSource *gCommSource;
104  GSocket *gSock;
105  GSocketAddress *gsDSAddr;
106  GSocketAddress *gsAddr;
107  GSSDPClient *gssdp_rgroup_client;
108  GSSDPResourceBrowser *resource_browser;
109  GResolver *resolver;
110  GList *glRegistry;
111  PIPBroadcastArray paB;
112  guint gRegistryQueries;
113  guint gRegCount;
114  guint gErrorCount;
115  guint gMsgDelay;
116  gboolean gReady;
117  gboolean oneShot;
118  gchar *pch_search;
119  gchar ch_intfName[SZ_RMTADDR_BUFF];
120  gchar ch_this_ip[SZ_RMTADDR_BUFF];
121  gchar ch_display_service_name[SZ_RMTADDR_BUFF];
122  gchar ch_message[SZ_MESSAGE_BUFF];
123  gchar ch_request[SZ_MESSAGE_BUFF];
124  gchar ch_response[SZ_RESPONSE_BUFF];
126 
127 
128 gboolean skn_gssdp_browse(PControlData pctrl);
129 static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl);
130 
131 gchar * skn_get_timestamp();
132 gint udp_registry_find_by_name(PGSSDPRegData pr, gchar *pch_name);
133 gchar * skn_gio_condition_to_string(GIOCondition condition);
134 gboolean udp_initialize_message_send(PControlData pctrl);
135 
136 static gboolean cb_unix_signal_handler(PUSignalData psig);
137 static gboolean cb_udp_comm_request_handler(PControlData pctrl);
138 static gboolean cb_udp_comm_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl);
139 static gboolean cb_udp_registry_select_handler(PControlData pctrl);
140 
141 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char * intf, char * ipv4);
142 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB);
143 gint skn_get_default_interface_name(char *pchDefaultInterfaceName);
144 gchar * skn_strip(gchar * alpha);
145 
150 gchar * skn_strip(gchar * alpha) {
151  if (alpha == NULL || strlen(alpha) < 1)
152  return(alpha);
153 
154  int len = strlen(alpha);
155  int end = len - 1;
156  int start = 0;
157 
158  // use isgraph() or !isspace() vs isalnum() to allow ['|' ';' '%']
159  while ( !g_unichar_isgraph(alpha[end]) && end > 0 ) { // remove trailing non-alphanumeric chars
160  alpha[end--] = 0;
161  }
162 
163  len = strlen(alpha);
164  while ( !g_unichar_isalnum(alpha[start]) && start < len ) { // find first non-alpha stricter
165  start++;
166  }
167  if (start < len && start > 0) { // move in place
168  end = len - start;
169  memmove(&alpha[0], &alpha[start], end);
170  alpha[end] = 0;
171  }
172 
173  return(alpha);
174 }
175 
176 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(gchar * intf, gchar * ipv4) {
177  PIPBroadcastArray paB = g_new0(IPBroadcastArray, 1);
178 
180  g_utf8_strncpy(intf, paB->chDefaultIntfName, SZ_CHAR_BUFF);
181  g_utf8_strncpy(ipv4, paB->ipAddrStr[paB->defaultIndex], SZ_CHAR_BUFF);
182  } else {
183  g_warning("[GSSDP] InterfaceName and Address: unable to access information.");
184  return(NULL);
185  }
186  return (paB);
187 }
188 
196 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB) {
197  struct ifaddrs * ifap;
198  struct ifaddrs * p;
199  gint rc = 0;
200 
201  memset(paB, 0, sizeof(IPBroadcastArray));
202  paB->count = 0;
203  paB->defaultIndex = 0;
204  strcpy(paB->cbName, "IPBroadcastArray");
205 
207  if (rc == EXIT_FAILURE) { // Alternate method for Mac: 'route -n -A inet'
208  g_warning("[GSSDP] No Default Network Interfaces Found!.");
209  paB->chDefaultIntfName[0] = 0;
210  }
211  rc = getifaddrs(&ifap);
212  if (rc != 0) {
213  g_warning("[GSSDP] No Network Interfaces Found at All ! %d:%d:%s", rc, errno, strerror(errno) );
214  return (PLATFORM_ERROR);
215  }
216  p = ifap;
217 
218  while (p && (paB->count < ARY_MAX_INTF)) {
219  if (p->ifa_addr != NULL && p->ifa_addr->sa_family == AF_INET && ((p->ifa_flags & IFF_BROADCAST) > 0)) {
220 
221  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_addr)->sin_addr, paB->ipAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
222  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_netmask)->sin_addr, paB->maskAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
223  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_broadaddr)->sin_addr, paB->broadAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
224 
225  strncpy(paB->ifNameStr[paB->count], p->ifa_name, (SZ_CHAR_BUFF -1));
226 
227  /* Take match as the default */
228  if (strcmp(paB->chDefaultIntfName, p->ifa_name) == 0) {
229  paB->defaultIndex = paB->count;
230  }
231 
232  paB->count++;
233  }
234  p = p->ifa_next;
235  } // end while
236  freeifaddrs(ifap);
237 
238  return (paB->count);
239 }
240 
257 gint skn_get_default_interface_name(char *pchDefaultInterfaceName) {
258  FILE *f_route;
259  char line[SZ_INFO_BUFF], *dRoute = NULL, *iName = NULL;
260 
261  f_route = fopen("/proc/net/route", "r");
262  if (f_route != NULL) {
263  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
264  iName = strtok(line, "\t");
265  dRoute = strtok(NULL, "\t");
266 
267  if (iName != NULL && dRoute != NULL) {
268  if (strcmp(dRoute, "00000000") == 0) {
269  strncpy(pchDefaultInterfaceName, iName, (SZ_INFO_BUFF - 1));
270  break;
271  }
272  }
273  }
274  fclose(f_route);
275 
276  return (EXIT_SUCCESS);
277  }
278  g_print("[GSSDP] Opening ProcFs for RouteInfo Failed: %d:%s, Alternate method will be attempted.\n", errno, strerror(errno));
279 
280  f_route = popen("route -n get 0.0.0.0", "r"); // for linux 'route -n -A inet', with interface at line_word[7]
281  if (f_route != NULL) {
282  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
283  dRoute = strtok(line, ":");
284  iName = strtok(NULL, "\n");
285  if (strcmp(skn_strip(dRoute), "interface") == 0) {
286  strncpy(pchDefaultInterfaceName, skn_strip(iName), (SZ_INFO_BUFF - 1));
287  break;
288  }
289  }
290  fclose(f_route);
291 
292  return (EXIT_SUCCESS);
293  } else {
294  g_warning("[GSSDP] Alternate method to get RouteInfo Failed: %d:%s", errno, strerror(errno));
295  return (EXIT_FAILURE);
296  }
297 
298 }
299 
300 gchar * skn_get_timestamp() {
301  GDateTime *stamp = g_date_time_new_now_local();
302  gchar *response = g_date_time_format(stamp,"%F.%T");
303 
304  return(response);
305 }
306 
307 gchar * skn_gio_condition_to_string(GIOCondition condition) {
308  gchar *value = NULL;
309 
310  switch(condition) {
311  case G_IO_IN:
312  value = "There is data to read.";
313  break;
314  case G_IO_OUT:
315  value = "Data can be written (without blocking).";
316  break;
317  case G_IO_PRI:
318  value = "There is urgent data to read.";
319  break;
320  case G_IO_ERR:
321  value = "Error condition.";
322  break;
323  case G_IO_HUP:
324  value = "Hung up (the connection has been broken, usually for pipes and sockets).";
325  break;
326  case G_IO_NVAL:
327  value = "Invalid request. The file descriptor is not open.";
328  break;
329  default:
330  value = "Unknown GIOCondition!";
331  }
332 
333  return (value);
334 }
335 
336 
337 static gboolean cb_udp_comm_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl) {
338  GError *error = NULL;
339  gssize gss_receive = 0;
340  gchar *stamp = skn_get_timestamp();
341  gchar * rmtHost = NULL;
342  GSocketAddress *gsRmtAddr = NULL;
343  GInetAddress *gsAddr = NULL;
344  gchar *converted = NULL;
345 
346  if ( NULL == pctrl) { /* SHUTDOWN THE MAIN LOOP */
347  g_message("DisplayClient::cb_udp_comm_response_handler(error) Invalid Pointer");
348  return ( G_SOURCE_REMOVE );
349  }
350 
351  gss_receive = g_socket_receive_from(gSock, &gsRmtAddr, pctrl->ch_request, sizeof(pctrl->ch_request), NULL, &error);
352  if (error != NULL) { // gss_receive = Number of bytes read, or 0 if the connection was closed by the peer, or -1 on error
353  g_error("g_socket_receive() => %s", error->message);
354  g_clear_error(&error);
355  }
356  if (gss_receive > 0 ) {
357  pctrl->ch_request[gss_receive] = 0;
358  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) ) {
359  gsAddr = g_inet_socket_address_get_address( G_INET_SOCKET_ADDRESS(gsRmtAddr) );
360  if ( G_IS_INET_ADDRESS(gsAddr) ) {
361  g_object_ref(gsAddr);
362  rmtHost = g_resolver_lookup_by_address (pctrl->resolver, gsAddr, NULL, NULL);
363  if (NULL == rmtHost) {
364  rmtHost = g_inet_address_to_string ( gsAddr);
365  }
366  }
367  }
368 
369  /*
370  * Convert to UTF8 */
371  converted = g_convert (pctrl->ch_request, gss_receive, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
372  if (NULL != converted) {
373  g_utf8_strncpy(pctrl->ch_request, converted, sizeof(pctrl->ch_request));
374  g_free(converted);
375  }
376 
377  g_snprintf(pctrl->ch_response, sizeof(pctrl->ch_response), "[%s]RESPONSE From=%s, Msg=%s", stamp, rmtHost, pctrl->ch_request);
378  pctrl->gErrorCount = 0; // reset send errors
379  } else {
380  g_snprintf(pctrl->ch_response, sizeof(pctrl->ch_response), "%s", "Error: Input not Usable!");
381  }
382 
383  g_print("%s\n", pctrl->ch_response);
384  g_free(stamp);
385 
386  if ( G_IS_INET_ADDRESS(gsAddr) )
387  g_object_unref(gsAddr);
388 
389  if ( G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
390  g_object_unref(gsRmtAddr);
391 
392  if (pctrl->oneShot) {
393  g_main_loop_quit(pctrl->loop);
394  return ( G_SOURCE_REMOVE );
395  } else {
396  return (G_SOURCE_CONTINUE);
397  }
398 
399 }
400 
401 static gboolean cb_udp_comm_request_handler(PControlData pctrl) {
402  GError *error = NULL;
403 
404  if ( NULL == pctrl) { /* SHUTDOWN THE MAIN LOOP */
405  g_message("DisplayClient::cb_udp_comm_request_handler(error) Invalid Pointer");
406  return ( G_SOURCE_REMOVE );
407  }
408 
409  g_socket_send_to (pctrl->gSock, pctrl->gsDSAddr, pctrl->ch_message, strlen(pctrl->ch_message), NULL, &error);
410  if (error != NULL) { // gss_send = Number of bytes written (which may be less than size ), or -1 on error
411  g_error("g_socket_send_to() => %s", error->message);
412  g_clear_error(&error);
413  pctrl->gErrorCount += 1;
414  if(pctrl->gErrorCount > 10) {
415  g_message("DisplayClient::cb_udp_comm_request_handler(error) Display Service @ %s, Not Responding!", pctrl->ch_display_service_name);
416  g_main_loop_quit(pctrl->loop);
417  return ( G_SOURCE_REMOVE );
418  } else {
419  return (G_SOURCE_CONTINUE);
420  }
421  }
422 
423  g_print("%s\n", pctrl->ch_message); // Todo not needed
424 
425  return (G_SOURCE_CONTINUE);
426 }
427 
428 gboolean udp_initialize_message_send(PControlData pctrl) {
429  GError *error = NULL;
430  GInetAddress *anyAddr = NULL;
431 
432  g_return_val_if_fail((NULL != pctrl), G_SOURCE_REMOVE);
433 
434  pctrl->gSock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
435  if (error != NULL) {
436  g_error("g_socket_new() => %s", error->message);
437  g_clear_error(&error);
438  return(FALSE);
439  }
440 
441  anyAddr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
442  pctrl->gsAddr = g_inet_socket_address_new(anyAddr, SKN_UDP_ANY_PORT);
443  g_object_unref(anyAddr);
444 
445  g_socket_bind(pctrl->gSock, pctrl->gsAddr, TRUE, &error);
446  if (error != NULL) {
447  g_error("g_socket_bind() => %s", error->message);
448  g_clear_error(&error);
449  exit(FALSE);
450  }
451 
452  pctrl->gCommSource = g_socket_create_source (pctrl->gSock, G_IO_IN, NULL);
453  g_source_set_callback (pctrl->gCommSource, (GSourceFunc) cb_udp_comm_response_handler, pctrl, NULL); // its really a GSocketSourceFunc
454  g_source_attach (pctrl->gCommSource, NULL);
455 
456  /*
457  * Setup Timer to drive repeated Message to Display Service */
458  g_timeout_add ((pctrl->gMsgDelay * 1000), (GSourceFunc)cb_udp_comm_request_handler, pctrl);
459 
460 
461  return (TRUE);
462 }
463 
464 // (*GCompareFunc) 0 if found, -1 if not found
465 gint udp_registry_find_by_name(PGSSDPRegData pr, gchar *pch_name) {
466  gint result = -1;
467  if (NULL != g_strrstr(pr->ch_urn, pch_name)) {
468  result = 0;
469  }
470  return( result );
471 }
472 
473 static gboolean cb_udp_registry_select_handler(PControlData pctrl) {
474  GList *registry = NULL;
475  PGSSDPRegData preg = NULL;
476  GInetAddress *anyAddr = NULL;
477  gchar **parts = NULL;
478  RegData msg;
479 
480  g_return_val_if_fail((NULL != pctrl), G_SOURCE_REMOVE);
481 
482  /*
483  * Find in Registry the selected service name */
484  if (g_list_length(pctrl->glRegistry) < 1) {
485  pctrl->gRegistryQueries++;
486 
487  if ((pctrl->gRegistryQueries % 15) == 0) { // every 30 seconds redo query
488  g_print("[GSSDP] Looking for [%s] in Rpi Registry every 30 seconds. StandBy...\n", pctrl->ch_display_service_name);
489  gssdp_resource_browser_set_active(pctrl->resource_browser, TRUE);
490  }
491 
492  return (G_SOURCE_CONTINUE);
493  }
494 
495  if ( NULL == (registry = g_list_find_custom (pctrl->glRegistry, pctrl->ch_display_service_name, (GCompareFunc)udp_registry_find_by_name)) ) {
496  g_list_free_full(pctrl->glRegistry, (GDestroyNotify)g_free);
497  pctrl->glRegistry = NULL;
498  return (G_SOURCE_CONTINUE);
499  }
500 
501  preg = registry->data; // now extract ip and port
502  /* Display Service Address */
503 
504  parts = g_strsplit (preg->ch_location, ":",-1);
505  g_utf8_strncpy(msg.ch_name, pctrl->ch_display_service_name, sizeof(msg.ch_name));
506  g_utf8_strncpy(msg.ch_ip, &parts[1][2], sizeof(msg.ch_ip));
507  g_utf8_strncpy(msg.ch_port, parts[2], sizeof(msg.ch_port));
508  g_strfreev(parts);
509 
510  anyAddr = g_inet_address_new_from_string(msg.ch_ip); // g_object_unref(dIP) when done
511  if (NULL == anyAddr) {
512  g_error("g_inet_address_new_from_string() Failed => %s, %s", preg->ch_location, preg->ch_location); // "udp://%s:%d"
513  return(G_SOURCE_CONTINUE);
514  }
515  pctrl->gsDSAddr = g_inet_socket_address_new(anyAddr, g_ascii_strtoll(msg.ch_port, NULL, 10));
516  g_object_unref(anyAddr);
517 
518  pctrl->gReady = udp_initialize_message_send(pctrl);
519 
520  if (pctrl->gReady) {
521  g_print("[GSSDP] FOUND %s on %s, sending your message in %d seconds.\n\n", preg->ch_urn, preg->ch_location, pctrl->gMsgDelay);
522  gssdp_resource_browser_set_active(pctrl->resource_browser, FALSE);
523  return (G_SOURCE_REMOVE);
524  } else {
525  return (G_SOURCE_CONTINUE);
526  }
527 }
528 
529 static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl) {
530  PGSSDPRegData msg = NULL;
531  gchar *stamp = skn_get_timestamp();
532  gchar *converted = NULL;
533 
534  g_warn_if_fail(NULL != pctrl);
535 
536  msg = g_new0(GSSDPRegData, 1);
537 
538  g_utf8_strncpy(msg->ch_timestamp, stamp, sizeof(msg->ch_timestamp));
539  g_free(stamp);
540 
541  /* Convert to UTF8 */
542  converted = g_convert (usn, g_utf8_strlen(usn, -1), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
543  if (NULL != converted) {
544  g_utf8_strncpy(msg->ch_urn, converted, sizeof(msg->ch_urn));
545  g_free(converted);
546  } else {
547  g_utf8_strncpy(msg->ch_urn, usn, sizeof(msg->ch_urn));
548  }
549 
550  converted = g_convert (locations->data, g_utf8_strlen(locations->data, -1), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
551  if (NULL != converted) {
552  g_utf8_strncpy(msg->ch_location, converted, sizeof(msg->ch_location));
553  g_free(converted);
554  } else {
555  g_utf8_strncpy(msg->ch_location, locations->data, sizeof(msg->ch_location));
556  }
557 
558  g_utf8_strncpy(msg->ch_status, "Available", sizeof(msg->ch_status));
559 
560  g_print("[%s]GSSDP %s, %s, %s\n", msg->ch_timestamp, msg->ch_urn, msg->ch_location, msg->ch_status);
561 
562  pctrl->glRegistry = g_list_prepend(pctrl->glRegistry, msg);
563 }
564 
568 gboolean skn_gssdp_browse(PControlData pctrl) {
569  GError *error = NULL;
570 
571  pctrl->gssdp_rgroup_client = gssdp_client_new(NULL, NULL, &error);
572  if (error) {
573  g_printerr ("Error creating the GSSDP gssdp_client for resource_browser: %s\n", error->message);
574  g_error_free (error);
575  return(FALSE);
576  }
577 
578  pctrl->resource_browser = gssdp_resource_browser_new (pctrl->gssdp_rgroup_client, pctrl->pch_search); // GSSDP_ALL_RESOURCES);
579  g_signal_connect (pctrl->resource_browser, "resource-available", G_CALLBACK (cb_gssdp_resource_available), pctrl);
580 
581  gssdp_resource_browser_set_active(pctrl->resource_browser, TRUE);
582 
583  return (TRUE);
584 }
585 
586 static gboolean cb_unix_signal_handler(PUSignalData psig) {
587  g_message("DisplayClient::cb_unix_signal_handler() %s Unix Signal Received => Shutdown Initiated!\n", psig->signalName);
588  g_main_loop_quit(psig->loop);
589  return ( G_SOURCE_REMOVE );
590 }
591 
592 int main(int argc, char **argv) {
593 
594  ControlData cData;
595  GError *error = NULL;
596  gchar * pch_display_service_name = NULL;
597  gchar * pch_message = NULL;
598 
599  GOptionContext *gOptions = NULL;
600  GOptionEntry pgmOptions[] = {
601  {"display_service_name", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &pch_display_service_name, "DisplayService Name", "GtkDisplayService"},
602  {"display_message", 'm', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &pch_message, "Message to send to DisplayService", "single-quoted-string"},
603  {"message_interval_delay", 'n', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &cData.gMsgDelay, "Send one message every Interval.", "[1 to 300] seconds, default no-repeat"},
604  {"search-key", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &cData.pch_search, "GSSDP Search Key.", "[urn:rpilocator | ssdp:all]"},
605  {NULL}
606  };
607 
608  cData.gMsgDelay = 0;
609  cData.gErrorCount = 0;
610  cData.gRegCount = 0;
611  cData.gRegistryQueries = 0;
612  cData.gReady = FALSE;
613  cData.oneShot = FALSE;
614 
615  cData.pch_search = NULL;
616  cData.glRegistry = NULL;
617  cData.sigTerm.signalName = "SIGTERM";
618  cData.sigInt.signalName = "SIGINT";
619  cData.sigHup.signalName = "SIGHUP";
620  cData.gErrorCount = 0;
621  cData.resolver = g_resolver_get_default();
622 
623  gOptions = g_option_context_new ("UDP message display client for IOT.");
624  g_option_context_add_main_entries (gOptions, pgmOptions, NULL);
625  g_option_context_parse (gOptions, &argc, &argv, &error);
626  if (error != NULL) {
627  g_error("g_option_context_parse() => %s", error->message);
628  g_clear_error(&error);
629  exit(EXIT_FAILURE);
630  }
631  g_option_context_free(gOptions);
632 
633  if (NULL == pch_message) {
634  g_utf8_strncpy(cData.ch_message, "GTK-+3.0 Rocks with GLIB-2.0 on any platform! (gssdpDC)", sizeof(cData.ch_message));
635  } else {
636  g_utf8_strncpy(cData.ch_message, pch_message, sizeof(cData.ch_message));
637  g_free(pch_message);
638  }
639  if (NULL == pch_display_service_name) {
640  g_utf8_strncpy(cData.ch_display_service_name, "GtkDisplayService", sizeof(cData.ch_display_service_name));
641  } else {
642  g_utf8_strncpy(cData.ch_display_service_name, pch_display_service_name, sizeof(cData.ch_display_service_name));
643  g_free(pch_display_service_name);
644  }
645  if (0 == cData.gMsgDelay) {
647  cData.oneShot = TRUE; // if no delay is given, send message once and quit.
648  }
649  if (NULL == cData.pch_search) {
650  cData.pch_search = "urn:rpilocator";
651  }
652 
653 
654  cData.paB = NULL;
655  cData.paB = skn_get_default_interface_name_and_ipv4_address((char *)&cData.ch_intfName, (char *)&cData.ch_this_ip);
656  if (NULL == cData.paB) {
657  g_error("skn_skn_get_default_interface_name_and_ipv4_address() => Unable to discover network interface or non-available.");
658  exit(EXIT_FAILURE);
659  }
660 
661  cData.sigHup.loop = cData.sigTerm.loop = cData.sigInt.loop = cData.loop = g_main_loop_new(NULL, FALSE);
662 
663  /*
664  * Handle ctrl-break and kill signals cleanly */
665  g_unix_signal_add (SIGINT, (GSourceFunc) cb_unix_signal_handler, &cData.sigInt); // SIGINT signal (Ctrl+C)
666  g_unix_signal_add (SIGHUP, (GSourceFunc) cb_unix_signal_handler, &cData.sigHup);
667  g_unix_signal_add (SIGTERM,(GSourceFunc) cb_unix_signal_handler, &cData.sigTerm);
668 
669  if ( skn_gssdp_browse(&cData) ) {
670  /*
671  * Setup 2secTimer to find display_service before starting rest */
672  g_timeout_add (2000, (GSourceFunc)cb_udp_registry_select_handler, &cData);
673 
674  g_print("[GSSDP] Looking for [%s] in Rpi Registry. StandBy...\n", cData.ch_display_service_name);
675 
676  g_main_loop_run(cData.loop);
677 
678  gssdp_resource_browser_set_active(cData.resource_browser, FALSE);
679  }
680 
681  g_main_loop_unref(cData.loop);
682 
683  if (cData.gReady) {
684  g_source_unref(cData.gCommSource);
685  g_object_unref(cData.gSock);
686  g_object_unref(cData.gsDSAddr);
687  g_object_unref(cData.gsAddr);
688  }
689  g_object_unref (cData.resource_browser);
690  g_object_unref (cData.gssdp_rgroup_client);
691 
692  g_free(cData.paB);
693  g_list_free_full(cData.glRegistry, (GDestroyNotify)g_free);
694 
695  g_message("gssdpDC: normal shutdown...");
696 
697  exit(EXIT_SUCCESS);
698 }
char ifNameStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:68
static gboolean cb_udp_comm_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl)
Definition: gssdpDC.c:337
USignalData sigHup
Definition: cmdDC.c:94
GSSDPResourceBrowser * resource_browser
Definition: gssdpDC.c:108
static gboolean cb_udp_registry_select_handler(PControlData pctrl)
Definition: gssdpDC.c:473
struct _controlData ControlData
static gboolean cb_unix_signal_handler(PUSignalData psig)
Definition: gssdpDC.c:586
char ipAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:69
struct _ipBroadcastArray * PIPBroadcastArray
struct _registryData RegData
gchar ch_request[SZ_MESSAGE_BUFF]
Definition: cmdDC.c:112
gchar * skn_strip(gchar *alpha)
Definition: gssdpDC.c:150
gint skn_get_default_interface_name(char *pchDefaultInterfaceName)
Definition: gssdpDC.c:257
struct _ipBroadcastArray IPBroadcastArray
#define SZ_INFO_BUFF
Definition: gssdpDC.c:57
char maskAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:70
gchar ch_ip[SZ_PARAMS_BUFF]
Definition: cmdDC.c:85
static gboolean cb_udp_comm_request_handler(PControlData pctrl)
Definition: gssdpDC.c:401
struct _gssdpRegistryData * PGSSDPRegData
gchar ch_message[SZ_MESSAGE_BUFF]
Definition: cmdDC.c:111
USignalData sigTerm
Definition: cmdDC.c:92
gchar ch_response[SZ_RESPONSE_BUFF]
Definition: cmdDC.c:113
guint gRegCount
Definition: cmdDC.c:104
#define FALSE
gchar ch_timestamp[SZ_TIMESTAMP_BUFF]
Definition: gssdpDC.c:92
#define PLATFORM_ERROR
Definition: gssdpDC.c:64
char cbName[SZ_CHAR_BUFF]
Definition: cmdDC.c:66
#define SZ_CHAR_BUFF
Definition: gssdpDC.c:58
#define SZ_TIMESTAMP_BUFF
Definition: gssdpDC.c:50
#define G_OPTION_FLAG_NONE
Definition: gssdpDC.c:39
gboolean oneShot
Definition: gssdpDC.c:117
PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char *intf, char *ipv4)
gchar ch_port[SZ_PARAMS_BUFF]
Definition: cmdDC.c:86
GSocketAddress * gsAddr
Definition: cmdDC.c:99
#define TRUE
#define SZ_MESSAGE_BUFF
Definition: gssdpDC.c:53
struct _gssdpRegistryData GSSDPRegData
gchar ch_status[SZ_PARAMS_BUFF]
Definition: gssdpDC.c:95
gchar * skn_get_timestamp()
Definition: gssdpDC.c:300
GSocket * gSock
Definition: cmdDC.c:96
#define SZ_PARAMS_BUFF
Definition: gssdpDC.c:51
#define SZ_RESPONSE_BUFF
Definition: gssdpDC.c:54
GSocketAddress * gsDSAddr
Definition: cmdDC.c:98
struct _controlData * PControlData
#define ARY_MAX_INTF
Definition: gssdpDC.c:63
GMainLoop * loop
Definition: cmdDC.c:91
guint gErrorCount
Definition: cmdDC.c:105
static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl)
Definition: gssdpDC.c:529
gchar * signalName
Definition: cmdDC.c:78
gboolean udp_initialize_message_send(PControlData pctrl)
Definition: gssdpDC.c:428
struct _signalData * PUSignalData
gchar ch_name[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:84
gchar ch_urn[SZ_RMTADDR_BUFF]
Definition: gssdpDC.c:93
int defaultIndex
Definition: cmdDC.c:72
struct _registryData * PRegData
#define SKN_UDP_ANY_PORT
Definition: gssdpDC.c:62
gchar ch_this_ip[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:109
char chDefaultIntfName[SZ_CHAR_BUFF]
Definition: cmdDC.c:67
gchar * skn_gio_condition_to_string(GIOCondition condition)
Definition: gssdpDC.c:307
PIPBroadcastArray paB
Definition: cmdDC.c:102
GList * glRegistry
Definition: cmdDC.c:101
USignalData sigInt
Definition: cmdDC.c:93
struct _signalData USignalData
#define SZ_RMTADDR_BUFF
Definition: gssdpDC.c:52
gboolean gReady
Definition: cmdDC.c:107
int main(int argc, char **argv)
Definition: gssdpDC.c:592
#define MSG_DELAY_INTERVAL
Definition: gssdpDC.c:48
guint gRegistryQueries
Definition: cmdDC.c:103
gchar ch_location[SZ_RMTADDR_BUFF]
Definition: gssdpDC.c:94
gint skn_get_broadcast_ip_array(PIPBroadcastArray paB)
Definition: gssdpDC.c:196
GMainLoop * loop
Definition: cmdDC.c:77
char broadAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:71
gint udp_registry_find_by_name(PGSSDPRegData pr, gchar *pch_name)
Definition: gssdpDC.c:465
guint gMsgDelay
Definition: cmdDC.c:106
GResolver * resolver
Definition: cmdDC.c:100
gchar * pch_search
Definition: gssdpDC.c:118
struct _registryData ** PPRegData
gboolean skn_gssdp_browse(PControlData pctrl)
Definition: gssdpDC.c:568
GSSDPClient * gssdp_rgroup_client
Definition: gssdpDC.c:107
gchar ch_intfName[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:108
gchar ch_display_service_name[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:110
GSource * gCommSource
Definition: cmdDC.c:95