RPi Locator and Display Services
gtkDS.c
Go to the documentation of this file.
1 
22 /*
23  * Program Standards passed from compiler
24  */
25 #ifndef PACKAGE_VERSION
26  #define PACKAGE_VERSION "0.9.0"
27 #endif
28 #ifndef PACKAGE_NAME
29  #define PACKAGE_NAME "gtkDS"
30 #endif
31 #ifndef PACKAGE_DESCRIPTION
32  #define PACKAGE_DESCRIPTION "Display Messages from other Raspberry Pi's on the network."
33 #endif
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <gtk/gtk.h>
38 #include <libgssdp/gssdp.h>
39 #include <gio/gio.h>
40 #include <glib-unix.h>
41 #include <gio/gnetworking.h>
42 #include <ifaddrs.h>
43 
44 #ifndef G_OPTION_FLAG_NONE
45  #define G_OPTION_FLAG_NONE 0
46 #endif
47 
48 
49 #define SZ_TIMESTAMP_BUFF 32
50 #define SZ_PARAMS_BUFF 64
51 #define SZ_RMTADDR_BUFF 256
52 #define SZ_MESSAGE_BUFF 512
53 #define SZ_RESPONSE_BUFF 256
54 
55 #define UDP_COMM_PORT 48029
56 #define UDP_BROADCAST_PORT 48028
57 #define UDP_REGULAR_PORT 48027
58 #define MS_TEN_MINUTES 600000
59 
60 #define SKN_SMALL_DISPLAY_MODE_ON 1
61 #define SKN_SMALL_DISPLAY_MODE_OFF 0
62 
63 #define MAX_MESSAGES_VIEWABLE 64
64 
65 #define SZ_CHAR_LABEL 48
66 #define SZ_INFO_BUFF 256
67 #define SZ_CHAR_BUFF 128
68 #define SZ_LINE_BUFF 512
69 #define SZ_COMM_BUFF 256
70 
71 #define SKN_UDP_ANY_PORT 0
72 #define ARY_MAX_INTF 8
73 #define PLATFORM_ERROR -1
74 
75 typedef struct _ipBroadcastArray {
76  char cbName[SZ_CHAR_BUFF];
82  int defaultIndex;
83  int count; // index = count - 1
85 
86 typedef struct _messageData {
87  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
88  gchar ch_remoteAddress[SZ_RMTADDR_BUFF];
89  gchar ch_message[SZ_MESSAGE_BUFF];
90 } MsgData, *PMsgData;
91 
92 typedef struct _signalData {
93  GMainLoop *loop;
94  gchar * signalName;
96 
97 typedef struct _registryData {
98  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
99  gchar ch_from[SZ_RMTADDR_BUFF];
100  gchar ch_name[SZ_RMTADDR_BUFF];
101  gchar ch_ip[SZ_PARAMS_BUFF];
102  gchar ch_port[SZ_PARAMS_BUFF];
103  gchar ch_message[SZ_MESSAGE_BUFF];
104 } RegData, *PRegData, **PPRegData;
105 
106 typedef struct _gssdpRegistryData {
107  gchar ch_timestamp[SZ_TIMESTAMP_BUFF];
108  gchar ch_urn[SZ_RMTADDR_BUFF];
109  gchar ch_location[SZ_RMTADDR_BUFF];
110  gchar ch_status[SZ_PARAMS_BUFF];
112 
113 typedef struct _controlData {
117  guint gBroadSourceId;
119  guint gMsgCount;
121  guint gRegCount;
123  guint gUDPPort;
124  guint gSmall;
125  GResolver *resolver;
126  GSSDPClient *gssdp_rgroup_client;
127  GSSDPResourceGroup *resource_group;
128  GSSDPResourceBrowser *resource_browser;
129  GMainLoop *loop;
130  GSocket *gbSock;
131  GAsyncQueue *queueMessage;
132  GAsyncQueue *queueRegistry;
133  GAsyncQueue *queueGSSDPRegistry;
134  GtkWidget *statusBar;
135  GtkWidget *pg1Target;
136  GtkWidget *pg2Target;
137  GtkWidget *pg3Target;
138  PIPBroadcastArray paB;
139  gchar ch_intfName[SZ_RMTADDR_BUFF];
140  gchar ch_this_ip[SZ_RMTADDR_BUFF];
141  gchar ch_status_message[SZ_MESSAGE_BUFF];
142  gchar *pch_search;
143  gchar *pch_service_name;
145 
146 enum _messages {
151 } EMessages;
152 
153 enum _registry {
160 } EUDPRegistry;
161 
169 
170 gchar * skn_get_timestamp();
171 gchar * skn_gio_condition_to_string(GIOCondition condition);
172 gchar * skn_strip(gchar * alpha);
173 
174 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char * intf, char * ipv4);
175 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB);
176 gint skn_get_default_interface_name(char *pchDefaultInterfaceName);
177 gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray pab);
178 
179 
180 static gboolean cb_unix_signal_handler(PUSignalData psig);
181 static gboolean cb_registry_refresh(PControlData pctrl);
182 static gboolean cb_registry_request_handler(PRegData msg, PControlData pctrl);
183 static gboolean cb_message_request_handler(PMsgData msg, PControlData pctrl);
184 static gboolean cb_udp_comm_request_handler(GSocket *socket, GIOCondition condition, PControlData pctrl);
185 static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl);
186 PPRegData udp_registry_response_parser(PRegData msg, gchar *response);
187 
188 
189 GtkWidget * ui_page_layout(GtkWidget *parent, PControlData pctrl);
190 GtkWidget * ui_message_page_new(GtkWidget *parent, guint gSmall);
191 GtkWidget * ui_registry_page_new(GtkWidget *parent, guint gSmall);
192 GtkWidget * ui_gssdp_registry_page_new(GtkWidget *parent, guint gSmall);
193 
194 gboolean ui_add_message_entry(GtkWidget *treeview, PMsgData msg, gboolean limiter);
195 gboolean ui_add_registry_entry(GtkWidget *treeview, PRegData msg, gboolean limiter);
196 gboolean ui_add_gssdp_registry_entry(GtkWidget *treeview, PGSSDPRegData msg, gboolean limiter);
197 guint ui_update_status_bar(PControlData pctrl);
198 
199 gboolean gssdp_publish(PControlData pctrl, guint udp_port );
200 gboolean gssdp_browse(PControlData pctrl);
201 static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl);
202 static void cb_gssdp_resource_unavailable(GSSDPResourceBrowser *resource_browser, const char *usn, PControlData pctrl);
203 
204 
205 
221 typedef struct {
222  GSource parent;
223  GAsyncQueue *queue; /* owned */
224  GDestroyNotify destroy_message;
226 
234 typedef gboolean (*MessageQueueSourceFunc) (gpointer message, gpointer user_data);
235 
236 static gboolean message_queue_source_prepare (GSource *source, gint *timeout_) {
237  MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
238  return (g_async_queue_length (message_queue_source->queue) > 0);
239 }
240 
241 static gboolean message_queue_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) {
242  MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
243  gpointer message;
245 
246  /* Pop a message off the queue. */
247  message = g_async_queue_try_pop (message_queue_source->queue);
248 
249  /* If there was no message, bail. */
250  if (message == NULL)
251  {
252  /* Keep the source around to handle the next message. */
253  return TRUE;
254  }
255 
256  /* @func may be %NULL if no callback was specified.
257  * If so, drop the message. */
258  if (func == NULL)
259  {
260  if (message_queue_source->destroy_message != NULL)
261  {
262  message_queue_source->destroy_message (message);
263  }
264 
265  /* Keep the source around to consume the next message. */
266  return TRUE;
267  }
268 
269  return (func(message, user_data));
270 }
271 
272 static void message_queue_source_finalize (GSource *source) {
273  MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
274  g_async_queue_unref (message_queue_source->queue);
275 }
276 
277 static gboolean message_queue_source_closure_callback (gpointer message, gpointer user_data) {
278  GClosure *closure = user_data;
279  GValue param_value = G_VALUE_INIT;
280  GValue result_value = G_VALUE_INIT;
281  gboolean retval;
282 
283  g_warn_if_reached();
284 
285  /* The invoked function is responsible for freeing @message. */
286  g_value_init (&result_value, G_TYPE_BOOLEAN);
287  g_value_init (&param_value, G_TYPE_POINTER);
288  g_value_set_pointer (&param_value, message);
289 
290  g_closure_invoke (closure, &result_value, 1, &param_value, NULL);
291  retval = g_value_get_boolean (&result_value);
292 
293  g_value_unset (&param_value);
294  g_value_unset (&result_value);
295 
296  return (retval);
297 }
298 
299 static GSourceFuncs message_queue_source_funcs =
300  {
302  NULL, /* check */
306  NULL,
307  };
308 
326 GSource * message_queue_source_new (GAsyncQueue *queue, GDestroyNotify destroy_message, GCancellable *cancellable) {
327  GSource *source; /* alias of @message_queue_source */
328  MessageQueueSource *message_queue_source; /* alias of @source */
329 
330  g_return_val_if_fail (queue != NULL, NULL);
331  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
332 
333  source = g_source_new (&message_queue_source_funcs, sizeof (MessageQueueSource));
334  message_queue_source = (MessageQueueSource *) source;
335 
336  /* The caller can overwrite this name with something more useful later. */
337  g_source_set_name (source, "MessageQueueSource");
338 
339  message_queue_source->queue = g_async_queue_ref (queue);
340  message_queue_source->destroy_message = destroy_message;
341 
342  /* Add a cancellable source. */
343  if (cancellable != NULL)
344  {
345  GSource *cancellable_source;
346 
347  cancellable_source = g_cancellable_source_new (cancellable);
348  g_source_set_dummy_callback (cancellable_source);
349  g_source_add_child_source (source, cancellable_source);
350  g_source_unref (cancellable_source);
351  }
352 
353  return (source);
354 }
355 
356 
357 PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(gchar * intf, gchar * ipv4) {
358  PIPBroadcastArray paB = g_new0(IPBroadcastArray, 1);
359 
361  g_utf8_strncpy(intf, paB->chDefaultIntfName, SZ_CHAR_BUFF);
362  g_utf8_strncpy(ipv4, paB->ipAddrStr[paB->defaultIndex], SZ_CHAR_BUFF);
363  } else {
364  g_warning("[REGISTRY] InterfaceName and Address: unable to access information.");
365  return(NULL);
366  }
367  return (paB);
368 }
369 
377 gint skn_get_broadcast_ip_array(PIPBroadcastArray paB) {
378  struct ifaddrs * ifap;
379  struct ifaddrs * p;
380  gint rc = 0;
381 
382  memset(paB, 0, sizeof(IPBroadcastArray));
383  paB->count = 0;
384  paB->defaultIndex = 0;
385  strcpy(paB->cbName, "IPBroadcastArray");
386 
388  if (rc == EXIT_FAILURE) { // Alternate method for Mac: 'route -n -A inet'
389  g_warning("[REGISTRY] No Default Network Interfaces Found!.");
390  paB->chDefaultIntfName[0] = 0;
391  }
392  rc = getifaddrs(&ifap);
393  if (rc != 0) {
394  g_warning("[REGISTRY] No Network Interfaces Found at All ! %d:%d:%s", rc, errno, strerror(errno) );
395  return (PLATFORM_ERROR);
396  }
397  p = ifap;
398 
399  while (p && (paB->count < ARY_MAX_INTF)) {
400  if (p->ifa_addr != NULL && p->ifa_addr->sa_family == AF_INET && ((p->ifa_flags & IFF_BROADCAST) > 0)) {
401 
402  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_addr)->sin_addr, paB->ipAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
403  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_netmask)->sin_addr, paB->maskAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
404  inet_ntop(p->ifa_addr->sa_family, &((struct sockaddr_in *) p->ifa_broadaddr)->sin_addr, paB->broadAddrStr[paB->count], (SZ_CHAR_BUFF - 1));
405 
406  strncpy(paB->ifNameStr[paB->count], p->ifa_name, (SZ_CHAR_BUFF -1));
407 
408  /* Take match as the default */
409  if (strcmp(paB->chDefaultIntfName, p->ifa_name) == 0) {
410  paB->defaultIndex = paB->count;
411  }
412 
413  paB->count++;
414  }
415  p = p->ifa_next;
416  } // end while
417  freeifaddrs(ifap);
418 
419  return (paB->count);
420 }
421 
438 gint skn_get_default_interface_name(char *pchDefaultInterfaceName) {
439  FILE *f_route;
440  char line[SZ_INFO_BUFF], *dRoute = NULL, *iName = NULL;
441 
442  f_route = fopen("/proc/net/route", "r");
443  if (f_route != NULL) {
444  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
445  iName = strtok(line, "\t");
446  dRoute = strtok(NULL, "\t");
447 
448  if (iName != NULL && dRoute != NULL) {
449  if (strcmp(dRoute, "00000000") == 0) {
450  strncpy(pchDefaultInterfaceName, iName, (SZ_INFO_BUFF - 1));
451  break;
452  }
453  }
454  }
455  fclose(f_route);
456 
457  return (EXIT_SUCCESS);
458  }
459  g_warning("[REGISTRY] Opening ProcFs for RouteInfo Failed: %d:%s, Alternate method will be attempted.", errno, strerror(errno));
460 
461  f_route = popen("route -n get 0.0.0.0", "r"); // for linux 'route -n -A inet', with interface at line_word[7]
462  if (f_route != NULL) {
463  while (fgets(line, SZ_INFO_BUFF - 1, f_route)) {
464  dRoute = strtok(line, ":");
465  iName = strtok(NULL, "\n");
466  if (strcmp(skn_strip(dRoute), "interface") == 0) {
467  strncpy(pchDefaultInterfaceName, skn_strip(iName), (SZ_INFO_BUFF - 1));
468  break;
469  }
470  }
471  fclose(f_route);
472 
473  return (EXIT_SUCCESS);
474  } else {
475  g_warning("[REGISTRY] Alternate method to get RouteInfo Failed: %d:%s", errno, strerror(errno));
476  return (EXIT_FAILURE);
477  }
478 
479 }
489 gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray paB) {
490  struct sockaddr_in remaddr; /* remote address */
491  socklen_t addrlen = sizeof(remaddr); /* length of addresses */
492  gchar *request = "urn:rpilocator - Rpi Where Are You?";
493  gint vIndex = 0;
494  gint i_socket = g_socket_get_fd(gSock);
495 
496  g_print("[REGISTRY] Socket Bound to %s\n", paB->ipAddrStr[paB->defaultIndex]);
497 
498  for (vIndex = 0; vIndex < paB->count; vIndex++) {
499  memset(&remaddr, 0, sizeof(remaddr));
500  remaddr.sin_family = AF_INET;
501  remaddr.sin_addr.s_addr = inet_addr(paB->broadAddrStr[vIndex]);
502  remaddr.sin_port = htons(UDP_BROADCAST_PORT);
503 
504  if (sendto(i_socket, request, strlen(request), 0, (struct sockaddr *) &remaddr, addrlen) < 0) {
505  g_warning("SendTo() Timed out; Failure code=%d, etext=%s", errno, strerror(errno));
506  break;
507  }
508  g_print("[REGISTRY] Query Broadcasted on %s:%s:%d\n", paB->ifNameStr[vIndex], paB->broadAddrStr[vIndex], UDP_BROADCAST_PORT);
509  }
510 
511  return(TRUE);
512 }
513 
514 
515 gchar * skn_get_timestamp() {
516  GDateTime *stamp = g_date_time_new_now_local();
517  gchar *response = g_date_time_format(stamp,"%F.%T");
518 
519  return(response);
520 }
521 
522 guint ui_update_status_bar(PControlData pctrl) {
523  gchar ch_status_message[SZ_MESSAGE_BUFF];
524 
525  if (pctrl->gSmall != SKN_SMALL_DISPLAY_MODE_OFF) {
526  return (0);
527  }
528 
529  g_snprintf(ch_status_message, sizeof(ch_status_message), "Messages=%d, GSSDP entries=%d, RpiLocator entries=%d", pctrl->gMsgCount, pctrl->gGSSDPRegCount, pctrl->gRegCount);
530  gtk_statusbar_pop(GTK_STATUSBAR(pctrl->statusBar), pctrl->gStatusContextId);
531 
532  return (gtk_statusbar_push(GTK_STATUSBAR(pctrl->statusBar), pctrl->gStatusContextId, ch_status_message));
533 }
534 
535 static gboolean cb_unix_signal_handler(PUSignalData psig) {
536  g_message("gtkDS::cb_unix_signal_handler() %s Unix Signal Received => Shutdown Initiated!\n", psig->signalName);
537  g_main_loop_quit(psig->loop);
538  return ( G_SOURCE_REMOVE );
539 }
540 
541 static gboolean cb_registry_refresh(PControlData pctrl) {
542  g_return_val_if_fail((NULL != pctrl), G_SOURCE_CONTINUE);
543 
545 // gssdp_resource_browser_rescan(pctrl->resource_browser); require 2.4+
546  gssdp_resource_browser_set_active(pctrl->resource_browser, TRUE);
547  return ( G_SOURCE_CONTINUE );
548 }
549 
550 static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl) {
551  GError *error = NULL;
552  GSocketAddress *gsRmtAddr = NULL;
553  GInetAddress *gsAddr = NULL;
554  PRegData message = NULL;
555  PRegData msg = NULL;
556  PRegData *msgs;
557  gchar * rmtHost = NULL;
558  gssize gss_receive = 0;
559  gchar *stamp = skn_get_timestamp();
560  gchar response[SZ_RESPONSE_BUFF];
561  gint h_index = 0;
562  gchar *converted = NULL;
563 
564  if ((condition & G_IO_HUP) || (condition & G_IO_ERR) || (condition & G_IO_NVAL)) { /* SHUTDOWN THE MAIN LOOP */
565  g_message("gtkDS::cb_udp_broadcast_response_handler(error) Operational Error / Shutdown Signaled => %s\n", skn_gio_condition_to_string(condition));
566  g_main_loop_quit(pctrl->loop);
567  return ( G_SOURCE_REMOVE );
568  }
569  if (condition != G_IO_IN) {
570  g_message("gtkDS::cb_udp_broadcast_response_handler(error) NOT G_IO_IN => %s\n", skn_gio_condition_to_string(condition));
571  return (G_SOURCE_CONTINUE);
572  }
573 
574  /*
575  * Allocate a new queue message and read incoming request directly into it */
576  message = g_new0(RegData,1);
577 
578  /*
579  * If socket times out before reading data any operation will error with 'G_IO_ERROR_TIMED_OUT'.
580  * Read Request Message and get Requestor IP Address or Name
581  */
582  gss_receive = g_socket_receive_from (gSock, &gsRmtAddr, message->ch_message, sizeof(message->ch_message), NULL, &error);
583  if (error != NULL) { // gss_receive = Number of bytes read, or 0 if the connection was closed by the peer, or -1 on error
584  g_error("g_socket_receive_from() => %s", error->message);
585  g_clear_error(&error);
586  g_free(message);
587  g_free(stamp);
588  return (G_SOURCE_CONTINUE);
589  }
590  if (gss_receive > 0 ) {
591  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) ) {
592  gsAddr = g_inet_socket_address_get_address( G_INET_SOCKET_ADDRESS(gsRmtAddr) );
593  if ( G_IS_INET_ADDRESS(gsAddr) ) {
594  g_object_ref(gsAddr);
595  rmtHost = g_resolver_lookup_by_address (pctrl->resolver, gsAddr, NULL, NULL);
596  if (NULL == rmtHost) {
597  rmtHost = g_inet_address_to_string ( gsAddr);
598  }
599  }
600  }
601 
602  /*
603  * Convert to UTF8
604  */
605  converted = g_convert (message->ch_message, gss_receive, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
606  if (NULL != converted) {
607  g_utf8_strncpy(message->ch_message, converted, sizeof(message->ch_message));
608  g_free(converted);
609  }
610 
611  g_utf8_strncpy(message->ch_timestamp, stamp, sizeof(message->ch_timestamp));
612  g_utf8_strncpy(message->ch_from, rmtHost, sizeof(message->ch_from));
613  if ( (msgs = udp_registry_response_parser(message, message->ch_message)) != NULL ) {
614  /*
615  * Send it to be processed by a message handler */
616  g_free(message);
617  h_index = 0;
618  msg = (PRegData)msgs[h_index];
619  while ( msg != NULL ) {
620  g_async_queue_push (pctrl->queueRegistry, msg);
621  msg = (PRegData)msgs[++h_index];
622  }
623  g_free(msgs);
624  } else {
625  g_free(message);
626 
627  /* Format: name=rpi_locator_service,ip=10.100.1.19,port=48028|
628  * name=gtk_display_service,ip=10.100.1.19,port=48029|
629  */
630 
631  g_snprintf(response, sizeof(response),
632  "name=rpi_locator_service,ip=%s,port=48028|name=%s,ip=%s,port=%d|",
633  pctrl->ch_this_ip, pctrl->pch_service_name, pctrl->ch_this_ip, pctrl->gUDPPort);
634  /*
635  * Send Registry Response to caller */
636 
637  g_print("[REGISTRY] Responding to Query: %s\n", response);
638 
639  g_socket_send_to (gSock, gsRmtAddr, response, strlen(response), NULL, &error);
640  if (error != NULL) { // gss_send = Number of bytes written (which may be less than size ), or -1 on error
641  g_error("g_socket_send_to() => %s", error->message);
642  g_free(message);
643  g_clear_error(&error);
644  }
645  }
646  }
647  g_free(stamp);
648  g_free(rmtHost);
649 
650  if ( G_IS_INET_ADDRESS(gsAddr) )
651  g_object_unref(gsAddr);
652 
653  if ( G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
654  g_object_unref(gsRmtAddr);
655 
656  return (G_SOURCE_CONTINUE);
657 }
658 
659 static gboolean cb_udp_comm_request_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl) {
660  GError *error = NULL;
661  GSocketAddress *gsRmtAddr = NULL;
662  GInetAddress *gsAddr = NULL;
663  PMsgData message = NULL;
664  gchar * rmtHost = NULL;
665  gssize gss_receive = 0;
666  gchar *stamp = skn_get_timestamp();
667  gchar response[SZ_RESPONSE_BUFF];
668 
669  if ((condition & G_IO_HUP) || (condition & G_IO_ERR) || (condition & G_IO_NVAL)) { /* SHUTDOWN THE MAIN LOOP */
670  g_message("gtkDS::cb_udp_comm_request_handler(error) Operational Error / Shutdown Signaled => %s\n", skn_gio_condition_to_string(condition));
671  g_main_loop_quit(pctrl->loop);
672  return ( G_SOURCE_REMOVE );
673  }
674  if (condition != G_IO_IN) {
675  g_message("gtkDS::cb_udp_comm_request_handler(error) NOT G_IO_IN => %s\n", skn_gio_condition_to_string(condition));
676  return (G_SOURCE_CONTINUE);
677  }
678 
679  /*
680  * Allocate a new queue message and read incoming request directly into it */
681  message = g_new0(MsgData,1);
682  g_utf8_strncpy(message->ch_timestamp, stamp, sizeof(message->ch_timestamp));
683  g_free(stamp);
684 
685  /*
686  * If socket times out before reading data any operation will error with 'G_IO_ERROR_TIMED_OUT'.
687  * Read Request Message and get Requestor IP Address or Name
688  */
689  gss_receive = g_socket_receive_from (gSock, &gsRmtAddr, message->ch_message, sizeof(message->ch_message), NULL, &error);
690  if (error != NULL) { // gss_receive = Number of bytes read, or 0 if the connection was closed by the peer, or -1 on error
691  g_error("g_socket_receive_from() => %s", error->message);
692  g_clear_error(&error);
693  g_free(message);
694  return (G_SOURCE_CONTINUE);
695  }
696  if (gss_receive > 0 ) {
697  if (G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) ) {
698  gsAddr = g_inet_socket_address_get_address( G_INET_SOCKET_ADDRESS(gsRmtAddr) );
699  if ( G_IS_INET_ADDRESS(gsAddr) ) {
700  g_object_ref(gsAddr);
701  rmtHost = g_resolver_lookup_by_address (pctrl->resolver, gsAddr, NULL, NULL);
702  if (NULL == rmtHost) {
703  rmtHost = g_inet_address_to_string ( gsAddr);
704  }
705  }
706  }
707  g_snprintf(message->ch_remoteAddress, sizeof(message->ch_remoteAddress), "%s", rmtHost);
708  g_free(rmtHost);
709  g_snprintf(response, sizeof(response), "%d %s", 202, "Accepted");
710  } else {
711  g_snprintf(message->ch_message, sizeof(message->ch_message), "%s", "Error: Input not Usable");
712  g_snprintf(response, sizeof(response), "%d %s", 406, "Not Acceptable");
713  }
714 
715  /*
716  * Send Response to caller */
717  g_socket_send_to (gSock, gsRmtAddr, response, strlen(response), NULL, &error);
718  if (error != NULL) { // gss_send = Number of bytes written (which may be less than size ), or -1 on error
719  g_error("g_socket_send_to() => %s", error->message);
720  g_free(message);
721  g_clear_error(&error);
722 
723  if ( G_IS_INET_ADDRESS(gsAddr) )
724  g_object_unref(gsAddr);
725 
726  if ( G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
727  g_object_unref(gsRmtAddr);
728 
729  return (G_SOURCE_CONTINUE);
730  }
731 
732  /*
733  * Send it to be processed by a message handler */
734  stamp = g_convert (message->ch_message, gss_receive, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
735  if (NULL != stamp) {
736  g_utf8_strncpy(message->ch_message, stamp, sizeof(message->ch_message));
737  g_free(stamp);
738  } else {
739  g_error("g_convert(udp_comm_request) => %s", error->message);
740  g_clear_error(&error);
741  }
742  g_async_queue_push (pctrl->queueMessage, message);
743 
744  if ( G_IS_INET_ADDRESS(gsAddr) )
745  g_object_unref(gsAddr);
746 
747  if ( G_IS_INET_SOCKET_ADDRESS(gsRmtAddr) )
748  g_object_unref(gsRmtAddr);
749 
750  return (G_SOURCE_CONTINUE);
751 }
752 
753 //MessageQueueSourceFunc
754 static gboolean cb_message_request_handler(PMsgData msg, PControlData pctrl) {
755 
756  g_return_val_if_fail((NULL != msg) && (NULL != pctrl), G_SOURCE_CONTINUE);
757 
758  pctrl->gMsgCount += 1;
759 
761 
762  ui_update_status_bar(pctrl);
763 
764  g_free(msg);
765 
766  return(G_SOURCE_CONTINUE);
767 }
768 
769 //MessageQueueSourceFunc
770 static gboolean cb_registry_request_handler(PRegData msg, PControlData pctrl) {
771 
772  g_return_val_if_fail((NULL != msg) && (NULL != pctrl), G_SOURCE_CONTINUE);
773 
774  pctrl->gRegCount += 1;
775 
776  ui_add_registry_entry( pctrl->pg2Target, msg, (pctrl->gRegCount >= (MAX_MESSAGES_VIEWABLE * 2)));
777 
778  ui_update_status_bar(pctrl);
779 
780  g_free(msg);
781 
782  return(G_SOURCE_CONTINUE);
783 }
784 
785 //MessageQueueSourceFunc
786 static gboolean cb_gssdp_registry_request_handler(PGSSDPRegData msg, PControlData pctrl) {
787 
788  g_return_val_if_fail((NULL != msg) && (NULL != pctrl), G_SOURCE_CONTINUE);
789 
790  pctrl->gGSSDPRegCount += 1;
791 
793 
794  ui_update_status_bar(pctrl);
795 
796  g_free(msg);
797 
798  return(G_SOURCE_CONTINUE);
799 }
800 
801 gchar * skn_gio_condition_to_string(GIOCondition condition) {
802  gchar *value = NULL;
803 
804  switch(condition) {
805  case G_IO_IN:
806  value = "There is data to read.";
807  break;
808  case G_IO_OUT:
809  value = "Data can be written (without blocking).";
810  break;
811  case G_IO_PRI:
812  value = "There is urgent data to read.";
813  break;
814  case G_IO_ERR:
815  value = "Error condition.";
816  break;
817  case G_IO_HUP:
818  value = "Hung up (the connection has been broken, usually for pipes and sockets).";
819  break;
820  case G_IO_NVAL:
821  value = "Invalid request. The file descriptor is not open.";
822  break;
823  default:
824  value = "Unknown GIOCondition!";
825  }
826 
827  return (value);
828 }
829 
834 gchar * skn_strip(gchar * alpha) {
835  if (alpha == NULL || strlen(alpha) < 1)
836  return(alpha);
837 
838  int len = strlen(alpha);
839  int end = len - 1;
840  int start = 0;
841 
842  // use isgraph() or !isspace() vs isalnum() to allow ['|' ';' '%']
843  while ( !g_unichar_isgraph(alpha[end]) && end > 0 ) { // remove trailing non-alphanumeric chars
844  alpha[end--] = 0;
845  }
846 
847  len = strlen(alpha);
848  while ( !g_unichar_isalnum(alpha[start]) && start < len ) { // find first non-alpha stricter
849  start++;
850  }
851  if (start < len && start > 0) { // move in place
852  end = len - start;
853  memmove(&alpha[0], &alpha[start], end);
854  alpha[end] = 0;
855  }
856 
857  return(alpha);
858 }
859 
870 PPRegData udp_registry_response_parser(PRegData msg, gchar *response) {
871  gboolean rc = FALSE;
872  gboolean final_rc = FALSE;
873  gchar ** lines = NULL;
874  gchar *current_line = NULL;
875  gchar ** entries = NULL;
876  gchar *current_entry = NULL;
877  gchar ** key_value = NULL;
878  PRegData *msgs;
879  PRegData preg = NULL;
880  gint h_index = 0;
881  gint v_index = 0;
882  gint o_index = 0;
883  gint a_count = 0;
884  gint e_count = 0;
885 
886  if (g_utf8_strchr(response, -1, '|') == NULL) { // must be a registry entry
887  return (NULL);
888  }
889 
890  lines = g_strsplit_set(response, "|;%", -1); // get whole entries
891  if ((NULL == lines) || (g_strv_length(lines) < 1)) {
892  return(NULL);
893  }
894 
895  a_count = g_strv_length(lines);
896  msgs = g_new0(PRegData, a_count);
897  for(o_index = 0; o_index < a_count; o_index += 1) {
898  msgs[o_index] = g_new0(RegData, 1);
899  memmove(msgs[o_index], msg, sizeof(RegData));
900  }
901 
902  o_index = 0;
903  current_line = lines[h_index];
904  while ((NULL != current_line) && (h_index < a_count)) { // do each entry
905  if(g_utf8_strlen(current_line, -1) < 1) {
906  current_line = lines[++h_index];
907  continue;
908  }
909 
910  v_index = 0;
911  entries = g_strsplit_set(current_line, ",", -1);
912  current_entry = entries[v_index];
913  e_count = g_strv_length(entries);
914  preg = msgs[o_index];
915  rc = FALSE;
916 
917  while((NULL != current_entry) && (v_index < e_count)) {
918  if(g_utf8_strlen(current_entry, -1) < 1) {
919  current_entry = entries[++v_index];
920  continue;
921  }
922 
923  // get name, ip, port
924 
925  key_value = g_strsplit_set(current_entry, "=", -1);
926  if((key_value != NULL) && (g_strv_length(key_value) > 0)) {
927  if(g_strrstr(key_value[0], "a") != NULL) {
928  final_rc = rc = TRUE;
929  g_utf8_strncpy(preg->ch_name, key_value[1], SZ_RMTADDR_BUFF);
930  }
931  if(g_strrstr(key_value[0], "i") != NULL) {
932  final_rc = rc = TRUE;
933  g_utf8_strncpy(preg->ch_ip, key_value[1], SZ_RMTADDR_BUFF);
934  }
935  if(g_strrstr(key_value[0], "o") != NULL) {
936  final_rc = rc = TRUE;
937  g_utf8_strncpy(preg->ch_port, key_value[1], SZ_RMTADDR_BUFF);
938  }
939  }
940  g_strfreev(key_value);
941  current_entry = entries[++v_index];
942  } // end entries
943 
944  if (rc && (g_utf8_strlen(preg->ch_ip, -1) > 6)) { // only move if used and valid
945  o_index += 1;
946  }
947  g_strfreev(entries);
948 
949  h_index +=1;
950  current_line = lines[h_index];
951  } // end lines
952  g_strfreev(lines);
953 
954  if (final_rc) {
955  while(o_index < a_count) {
956  g_free(msgs[o_index]);
957  msgs[o_index++] = NULL;
958  }
959  return(msgs);
960  } else {
961  while(o_index < a_count) {
962  g_free(msgs[o_index]);
963  msgs[o_index++] = NULL;
964  }
965  g_free(msgs);
966  return(NULL);
967  }
968 }
969 
970 GtkWidget * ui_message_page_new(GtkWidget *parent, guint gSmall) {
971  GtkWidget *scrolled = NULL;
972  GtkTreeView *treeview = NULL;
973  GtkListStore *store = NULL;
974  GtkCellRenderer *renderer = NULL;
975  GtkTreeViewColumn *column = NULL;
976 
977  if (gSmall == SKN_SMALL_DISPLAY_MODE_OFF) {
978  gtk_box_pack_start (GTK_BOX (parent), gtk_label_new ("Device Messages from the local Internet of Things (IOT).") , FALSE, FALSE, 6);
979  }
980  /*
981  * main container is a GtkTreeView wrapped by a scrollable window */
982  scrolled = gtk_scrolled_window_new (NULL, NULL);
983  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
984  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled),GTK_SHADOW_ETCHED_OUT);
985  gtk_box_pack_start (GTK_BOX (parent), scrolled, TRUE, TRUE, 0);
986 
987 
988  /* create list store for tree view */
989  store = gtk_list_store_new (MSG_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
990 
991  treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)));
992  gtk_tree_view_set_grid_lines(treeview, GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
993 
994  /* column for timestamp */
995  renderer = gtk_cell_renderer_text_new ();
996  column = gtk_tree_view_column_new_with_attributes ("Timestamp", renderer, "text", MSGS_COLUMN_TIMESTAMP, NULL);
997  gtk_tree_view_column_set_sort_column_id (column, MSGS_COLUMN_TIMESTAMP);
998  gtk_tree_view_column_set_resizable(column, TRUE);
999  gtk_tree_view_append_column(treeview, column);
1000 
1001  /* column for service name */
1002  renderer = gtk_cell_renderer_text_new ();
1003  column = gtk_tree_view_column_new_with_attributes ("Sent By", renderer, "text", COLUMN_NODE, NULL);
1004  gtk_tree_view_column_set_sort_column_id (column, COLUMN_NODE);
1005  gtk_tree_view_column_set_resizable(column, TRUE);
1006  gtk_tree_view_append_column (treeview, column);
1007 
1008  /* column for IP Address */
1009  renderer = gtk_cell_renderer_text_new ();
1010  column = gtk_tree_view_column_new_with_attributes ("Message", renderer, "text", COLUMN_MESSAGES, NULL);
1011  gtk_tree_view_column_set_sort_column_id (column, COLUMN_MESSAGES);
1012  gtk_tree_view_column_set_resizable(column, TRUE);
1013  gtk_tree_view_column_set_expand(column, TRUE);
1014  gtk_tree_view_append_column (treeview, column);
1015 
1016  g_object_unref (store);
1017 
1018  gtk_tree_view_set_search_column(treeview, COLUMN_NODE);
1019  gtk_tree_view_set_enable_search(treeview, TRUE);
1020 
1021  gtk_container_add (GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
1022 
1023  gtk_widget_show_all(parent);
1024  gtk_tree_view_columns_autosize(treeview);
1025 
1026  return (GTK_WIDGET(treeview));
1027 }
1028 
1029 GtkWidget * ui_registry_page_new(GtkWidget *parent, guint gSmall) {
1030  GtkWidget *scrolled = NULL;
1031  GtkTreeView *treeview = NULL;
1032  GtkListStore *store = NULL;
1033  GtkCellRenderer *renderer = NULL;
1034  GtkTreeViewColumn *column = NULL;
1035 
1036 
1037  if (gSmall == SKN_SMALL_DISPLAY_MODE_OFF) {
1038  gtk_box_pack_start (GTK_BOX (parent), gtk_label_new ("Raspberry Pi Network Services Registry.") , FALSE, FALSE, 6);
1039  }
1040 
1041  /*
1042  * main container is a GtkTreeView wrapped by a scrollable window */
1043  scrolled = gtk_scrolled_window_new (NULL, NULL);
1044  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1045  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled),GTK_SHADOW_ETCHED_OUT);
1046  gtk_box_pack_start (GTK_BOX (parent), scrolled, TRUE, TRUE, 0);
1047 
1048 
1049  /* create list store for tree view */
1050  store = gtk_list_store_new (REG_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1051 
1052  treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)));
1053  gtk_tree_view_set_grid_lines(treeview, GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
1054 
1055  /* column for timestamp */
1056  renderer = gtk_cell_renderer_text_new ();
1057  column = gtk_tree_view_column_new_with_attributes ("Timestamp", renderer, "text", UDP_COLUMN_TIMESTAMP, NULL);
1058  gtk_tree_view_column_set_resizable(column, TRUE);
1059  gtk_tree_view_column_set_sort_column_id (column, UDP_COLUMN_TIMESTAMP);
1060  gtk_tree_view_append_column(treeview, column);
1061 
1062  /* column for from node */
1063  renderer = gtk_cell_renderer_text_new ();
1064  column = gtk_tree_view_column_new_with_attributes ("Reported By", renderer, "text", COLUMN_FROM, NULL);
1065  gtk_tree_view_column_set_sort_column_id (column, COLUMN_FROM);
1066  gtk_tree_view_column_set_resizable(column, TRUE);
1067  gtk_tree_view_append_column(treeview, column);
1068 
1069  /* column for service name */
1070  renderer = gtk_cell_renderer_text_new ();
1071  column = gtk_tree_view_column_new_with_attributes ("Service Name", renderer, "text", COLUMN_NAME, NULL);
1072  gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
1073  gtk_tree_view_column_set_resizable(column, TRUE);
1074  gtk_tree_view_append_column(treeview, column);
1075 
1076  /* column for IP Address */
1077  renderer = gtk_cell_renderer_text_new ();
1078  column = gtk_tree_view_column_new_with_attributes ("IP Address", renderer, "text", COLUMN_IP, NULL);
1079  gtk_tree_view_column_set_sort_column_id (column, COLUMN_IP);
1080  gtk_tree_view_column_set_resizable(column, TRUE);
1081  gtk_tree_view_append_column (treeview, column);
1082 
1083  /* column for port number */
1084  renderer = gtk_cell_renderer_text_new ();
1085  column = gtk_tree_view_column_new_with_attributes ("UDP Port", renderer, "text", COLUMN_PORT, NULL);
1086  gtk_tree_view_column_set_sort_column_id (column, COLUMN_PORT);
1087  gtk_tree_view_column_set_resizable(column, TRUE);
1088  gtk_tree_view_append_column (treeview, column);
1089 
1090  g_object_unref (store);
1091 
1092  gtk_tree_view_set_enable_search(treeview, TRUE);
1093  gtk_tree_view_set_search_column (treeview, COLUMN_NAME);
1094 
1095  gtk_container_add (GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
1096 
1097  gtk_widget_show_all(parent);
1098 
1099  gtk_tree_view_columns_autosize(treeview);
1100 
1101  return (GTK_WIDGET(treeview));
1102 }
1103 
1104 GtkWidget * ui_gssdp_registry_page_new(GtkWidget *parent, guint gSmall) {
1105  GtkWidget *scrolled = NULL;
1106  GtkTreeView *treeview = NULL;
1107  GtkListStore *store = NULL;
1108  GtkCellRenderer *renderer = NULL;
1109  GtkTreeViewColumn *column = NULL;
1110 
1111  if (gSmall == SKN_SMALL_DISPLAY_MODE_OFF) {
1112  gtk_box_pack_start (GTK_BOX (parent), gtk_label_new ("GSSDP Network Services Registry.") , FALSE, FALSE, 6);
1113  }
1114 
1115  /*
1116  * main container is a GtkTreeView wrapped by a scrollable window */
1117  scrolled = gtk_scrolled_window_new (NULL, NULL);
1118  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1119  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled),GTK_SHADOW_ETCHED_OUT);
1120  gtk_box_pack_start (GTK_BOX (parent), scrolled, TRUE, TRUE, 0);
1121 
1122 
1123  /* create list store for tree view */
1124  store = gtk_list_store_new (GSSDP_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1125 
1126  treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)));
1127  gtk_tree_view_set_grid_lines(treeview, GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
1128 
1129  /* column for timestamp */
1130  renderer = gtk_cell_renderer_text_new ();
1131  column = gtk_tree_view_column_new_with_attributes ("Timestamp", renderer, "text", GSSDP_COLUMN_TIMESTAMP, NULL);
1132  gtk_tree_view_column_set_resizable(column, TRUE);
1133  gtk_tree_view_column_set_sort_column_id (column, GSSDP_COLUMN_TIMESTAMP);
1134  gtk_tree_view_append_column(treeview, column);
1135 
1136  /* column for service name */
1137  renderer = gtk_cell_renderer_text_new ();
1138  column = gtk_tree_view_column_new_with_attributes ("GSSDP URN", renderer, "text", COLUMN_URN, NULL);
1139  gtk_tree_view_column_set_resizable(column, TRUE);
1140  gtk_tree_view_column_set_sort_column_id (column, COLUMN_URN);
1141  gtk_tree_view_append_column(treeview, column);
1142 
1143  /* column for IP Address */
1144  renderer = gtk_cell_renderer_text_new ();
1145  column = gtk_tree_view_column_new_with_attributes ("GSSDP Location", renderer, "text", COLUMN_LOCATION, NULL);
1146  gtk_tree_view_column_set_expand(column, TRUE);
1147  gtk_tree_view_column_set_resizable(column, TRUE);
1148  gtk_tree_view_column_set_sort_column_id (column, COLUMN_LOCATION);
1149  gtk_tree_view_append_column (treeview, column);
1150 
1151  /* column for port number */
1152  renderer = gtk_cell_renderer_text_new ();
1153  column = gtk_tree_view_column_new_with_attributes ("GSSDP Status", renderer, "text", COLUMN_STATUS, NULL);
1154  gtk_tree_view_column_set_resizable(column, TRUE);
1155  gtk_tree_view_column_set_sort_column_id (column, COLUMN_STATUS);
1156  gtk_tree_view_append_column (treeview, column);
1157 
1158  g_object_unref (store);
1159 
1160  gtk_tree_view_set_enable_search(treeview, TRUE);
1161  gtk_tree_view_set_search_column (treeview, COLUMN_URN);
1162 
1163  gtk_container_add (GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
1164 
1165  gtk_widget_show_all(parent);
1166 
1167  gtk_tree_view_columns_autosize(treeview);
1168 
1169  return (GTK_WIDGET(treeview));
1170 }
1171 
1172 gboolean ui_add_message_entry(GtkWidget *treeview, PMsgData msg, gboolean limiter) {
1173  gboolean result = TRUE;
1174  GtkListStore *store = GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)) );
1175  GtkTreeIter iter;
1176  gint num_rows = 0;
1177 
1178  // insert at head of list
1179  gtk_list_store_insert_with_values (store, NULL, 0, MSGS_COLUMN_TIMESTAMP, msg->ch_timestamp,
1181  COLUMN_MESSAGES, msg->ch_message, -1);
1182 
1183  if (limiter) { // get last iter and remove it
1184  num_rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1185 
1186  if ( (num_rows > 8) && (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, (num_rows -1))) ) { // last entry
1187  gtk_tree_model_unref_node(GTK_TREE_MODEL(store), &iter);
1188  gtk_list_store_remove(store, &iter);
1189  }
1190  }
1191 
1192  return (result);
1193 }
1194 
1195 gboolean ui_add_registry_entry(GtkWidget *treeview, PRegData msg, gboolean limiter) {
1196  gboolean result = TRUE;
1197  GtkListStore *store = GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)) );
1198  GtkTreeIter iter;
1199  gint num_rows = 0;
1200 
1201  // insert at head of list
1202  gtk_list_store_insert_with_values (store, NULL, 0, UDP_COLUMN_TIMESTAMP, msg->ch_timestamp ,
1203  COLUMN_FROM, msg->ch_from,
1204  COLUMN_NAME, msg->ch_name,
1205  COLUMN_IP, msg->ch_ip,
1206  COLUMN_PORT, msg->ch_port, -1);
1207 
1208  if (limiter) { // get last iter and remove it
1209  num_rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1210 
1211  if ( (num_rows > 8) && (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, (num_rows -1))) ) { // last entry
1212  gtk_tree_model_unref_node(GTK_TREE_MODEL(store), &iter);
1213  gtk_list_store_remove(store, &iter);
1214  }
1215  }
1216 
1217  return (result);
1218 }
1219 
1220 gboolean ui_add_gssdp_registry_entry(GtkWidget *treeview, PGSSDPRegData msg, gboolean limiter) {
1221  gboolean result = TRUE;
1222  GtkListStore *store = GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)) );
1223  GtkTreeIter iter;
1224  gint num_rows = 0;
1225 
1226  // insert at head of list
1227  gtk_list_store_insert_with_values (store, NULL, 0, GSSDP_COLUMN_TIMESTAMP, msg->ch_timestamp,
1228  COLUMN_URN, msg->ch_urn,
1230  COLUMN_STATUS, msg->ch_status, -1);
1231 
1232  if (limiter) { // get last iter and remove it
1233  num_rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1234 
1235  if ( (num_rows > 8) && (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, (num_rows -1))) ) { // last entry
1236  gtk_tree_model_unref_node(GTK_TREE_MODEL(store), &iter);
1237  gtk_list_store_remove(store, &iter);
1238  }
1239  }
1240 
1241  return (result);
1242 }
1243 
1244 GtkWidget * ui_page_layout(GtkWidget *parent, PControlData pctrl) {
1245  GtkWidget *grid = NULL;
1246  GtkWidget *switcher = NULL;
1247  GtkWidget *stack = NULL;
1248  GtkWidget *pg1Box = NULL;
1249  GtkWidget *pg2Box = NULL;
1250  GtkWidget *pg3Box = NULL;
1251 
1252 
1253  grid = gtk_grid_new(); // left, top, width, hieght
1254 
1255  switcher = gtk_stack_switcher_new();
1256  gtk_widget_set_hexpand (switcher, TRUE);
1257  gtk_widget_set_halign (switcher, GTK_ALIGN_CENTER);
1258  gtk_grid_attach (GTK_GRID (grid), switcher, 0, 0, 1, 1);
1259 
1260  stack = gtk_stack_new();
1261  gtk_widget_set_hexpand (stack, TRUE);
1262  gtk_widget_set_vexpand(stack, TRUE);
1263  gtk_stack_set_homogeneous( GTK_STACK(stack), TRUE);
1264  gtk_stack_set_transition_type( GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE);
1265  gtk_stack_set_transition_duration( GTK_STACK(stack), 400);
1266  gtk_grid_attach (GTK_GRID (grid), stack, 0, 1, 1, 1);
1267 
1268  pg1Box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1269  pctrl->pg1Target = ui_message_page_new(pg1Box, pctrl->gSmall);
1270  gtk_stack_add_titled ( GTK_STACK(stack), GTK_WIDGET(pg1Box), "messages", "Messages");
1271  pg2Box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1272  pctrl->pg2Target = ui_registry_page_new(pg2Box, pctrl->gSmall);
1273  gtk_stack_add_titled ( GTK_STACK(stack), GTK_WIDGET(pg2Box), "udp_registry", "Rpi Registry");
1274  pg3Box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1275  pctrl->pg3Target = ui_gssdp_registry_page_new(pg3Box, pctrl->gSmall);
1276  gtk_stack_add_titled ( GTK_STACK(stack), GTK_WIDGET(pg3Box), "gssdp_registry", "GSSDP Registry");
1277 
1278  gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER(switcher), GTK_STACK(stack));
1279  gtk_stack_set_visible_child (GTK_STACK(stack), GTK_WIDGET(pg1Box));
1280 
1281  if (pctrl->gSmall == SKN_SMALL_DISPLAY_MODE_OFF) {
1282  pctrl->statusBar = gtk_statusbar_new();
1283  gtk_grid_attach (GTK_GRID (grid), pctrl->statusBar, 0, 3, 1, 1);
1284  pctrl->gStatusContextId = gtk_statusbar_get_context_id(GTK_STATUSBAR(pctrl->statusBar), "GtkDisplayService");
1285  gtk_statusbar_push(GTK_STATUSBAR(pctrl->statusBar), pctrl->gStatusContextId, "Online and Ready to do good work.");
1286  }
1287 
1288  gtk_container_add (GTK_CONTAINER(parent), grid);
1289 
1290  gtk_widget_show_all(grid);
1291 
1292  return (stack);
1293 }
1294 
1295 
1296 static void cb_gtk_shutdown (GtkWidget *object, gpointer data) {
1297  PUSignalData psig = (PUSignalData)data;
1298  g_message("gtkDS::cb_gtk_shutdown() %s Destroy Signal Received => Shutdown Initiated!\n", psig->signalName);
1299  g_main_loop_quit(psig->loop);
1300 }
1301 
1302 
1303 static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl) {
1304  PGSSDPRegData msg = NULL;
1305  gchar *stamp = skn_get_timestamp();
1306  gchar *converted = NULL;
1307 
1308  g_warn_if_fail(NULL != pctrl);
1309 
1310  msg = g_new0(GSSDPRegData, 1);
1311 
1312  g_utf8_strncpy(msg->ch_timestamp, stamp, sizeof(msg->ch_timestamp));
1313  g_free(stamp);
1314 
1315  /* Convert to UTF8 */
1316  converted = g_convert (usn, g_utf8_strlen(usn, -1), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
1317  if (NULL != converted) {
1318  g_utf8_strncpy(msg->ch_urn, converted, sizeof(msg->ch_urn));
1319  g_free(converted);
1320  } else {
1321  g_utf8_strncpy(msg->ch_urn, usn, sizeof(msg->ch_urn));
1322  }
1323 
1324  converted = g_convert (locations->data, g_utf8_strlen(locations->data, -1), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
1325  if (NULL != converted) {
1326  g_utf8_strncpy(msg->ch_location, converted, sizeof(msg->ch_location));
1327  g_free(converted);
1328  } else {
1329  g_utf8_strncpy(msg->ch_location, locations->data, sizeof(msg->ch_location));
1330  }
1331 
1332  g_utf8_strncpy(msg->ch_status, "Available", sizeof(msg->ch_status));
1333 
1334  g_async_queue_push(pctrl->queueGSSDPRegistry, msg);
1335 
1336 }
1337 static void cb_gssdp_resource_unavailable(GSSDPResourceBrowser *resource_browser, const char *usn, PControlData pctrl) {
1338  PGSSDPRegData msg = NULL;
1339  gchar *stamp = skn_get_timestamp();
1340  gchar *converted = NULL;
1341 
1342  g_warn_if_fail(NULL != pctrl);
1343 
1344  msg = g_new0(GSSDPRegData, 1);
1345 
1346  g_utf8_strncpy(msg->ch_timestamp, stamp, sizeof(msg->ch_timestamp));
1347  g_free(stamp);
1348 
1349  /* Convert to UTF8 */
1350  converted = g_convert (usn, g_utf8_strlen(usn, -1), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
1351  if (NULL != converted) {
1352  g_utf8_strncpy(msg->ch_urn, converted, sizeof(msg->ch_urn));
1353  g_free(converted);
1354  } else {
1355  g_utf8_strncpy(msg->ch_urn, usn, sizeof(msg->ch_urn));
1356  }
1357 
1358  g_utf8_strncpy(msg->ch_location, "N/A", sizeof(msg->ch_location));
1359  g_utf8_strncpy(msg->ch_status, "Unavailable", sizeof(msg->ch_status));
1360 
1361  g_async_queue_push(pctrl->queueGSSDPRegistry, msg);
1362 }
1363 
1364 gboolean gssdp_publish(PControlData pctrl, guint udp_port ) {
1365  GError *error = NULL;
1366  gchar ch_buffer[SZ_MESSAGE_BUFF];
1367 
1368 
1369  pctrl->gssdp_rgroup_client = gssdp_client_new(NULL, NULL, &error);
1370  if (error) {
1371  g_printerr ("Error creating the GSSDP gssdp_client for resource_group: %s\n", error->message);
1372  g_error_free (error);
1373  return(FALSE);
1374  }
1375 
1376  pctrl->resource_group = gssdp_resource_group_new(pctrl->gssdp_rgroup_client);
1377 
1378  g_snprintf(ch_buffer, sizeof(ch_buffer), "http://%s/", pctrl->ch_this_ip );
1379  gssdp_resource_group_add_resource_simple
1380  (pctrl->resource_group,
1381  "urn:rpilocator",
1382  "uuid:80e6e2b7-fa4a-4d06-820a-406d5ecbbe51::upnp:rootdevice",
1383  ch_buffer);
1384 
1385  g_snprintf(ch_buffer, sizeof(ch_buffer), "udp://%s:%d", pctrl->ch_this_ip, udp_port );
1386  gssdp_resource_group_add_resource_simple
1387  (pctrl->resource_group,
1388  "urn:rpilocator",
1389  "uuid:21798cdc-d875-42b9-bb52-8043e6396301::urn:schemas-upnp-org:service:GtkDisplayService:1",
1390  ch_buffer);
1391 
1392  gssdp_resource_group_set_available(pctrl->resource_group, TRUE);
1393 
1394 
1395  return(TRUE);
1396 }
1397 
1401 gboolean gssdp_browse(PControlData pctrl) {
1402 
1403  pctrl->resource_browser = gssdp_resource_browser_new (pctrl->gssdp_rgroup_client, pctrl->pch_search); // GSSDP_ALL_RESOURCES);
1404  g_signal_connect (pctrl->resource_browser, "resource-available", G_CALLBACK (cb_gssdp_resource_available), pctrl);
1405  g_signal_connect (pctrl->resource_browser, "resource-unavailable", G_CALLBACK (cb_gssdp_resource_unavailable), pctrl);
1406 
1407  gssdp_resource_browser_set_active(pctrl->resource_browser, TRUE);
1408 
1409  return (TRUE);
1410 }
1411 
1412 int main(int argc, char **argv) {
1413 
1414  GError *error = NULL;
1415  GMainLoop *loop = NULL;
1416  GSocket *gSock = NULL;
1417  GSocketAddress *gsAddr = NULL;
1418  GSource * gCommSource = NULL;
1419  GSocketAddress *gbAddr = NULL;
1420  GSource * gBroadSource = NULL;
1421  GSource * gMsgSource = NULL;
1422  GSource * gRegSource = NULL;
1423  GSource * gGSSDPRegSource = NULL;
1424  ControlData cData;
1425  PIPBroadcastArray paB = NULL;
1426  GInetAddress *anyAddr = NULL;
1427  USignalData sigTerm;
1428  USignalData sigInt;
1429  USignalData sigHup;
1430  USignalData winDestroy;
1431  GtkWidget *window = NULL;
1432  guint gUDPPort = 0;
1433  GOptionContext *gOptions = NULL;
1434  GOptionEntry pgmOptions[] = {
1435  {"service-name", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &cData.pch_service_name, "Alternate Service Name", "gtk_display_service"},
1436  {"udp_port_number", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &gUDPPort, "UDP Port Number to listen on. default=48029", "48029"},
1437  {"small", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &cData.gSmall, "Small Screen mode, reduced status and titles.", NULL},
1438  {"search-key", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &cData.pch_search, "GSSDP Search Key.", "[urn:rpilocator | ssdp:all]"},
1439  {NULL}
1440  };
1442  cData.pch_search = NULL;
1443  cData.pch_service_name = NULL;
1444 
1445  gOptions = g_option_context_new ("UDP message display service for IOT.");
1446  g_option_context_add_group (gOptions, (GOptionGroup *) gtk_get_option_group(TRUE) );
1447  g_option_context_add_main_entries (gOptions, pgmOptions, NULL);
1448 
1449  g_option_context_parse (gOptions, &argc, &argv, &error);
1450  if (error != NULL) {
1451  g_error("g_option_context_parse() => %s", error->message);
1452  g_clear_error(&error);
1453  exit(EXIT_FAILURE);
1454  }
1455  g_option_context_free(gOptions);
1456 
1457  if (gUDPPort == 0) {
1458  gUDPPort = cData.gUDPPort = UDP_COMM_PORT;
1459  } else {
1460  cData.gUDPPort = gUDPPort;
1461  }
1462  if (NULL == cData.pch_search) {
1463  cData.pch_search = "urn:rpilocator";
1464  }
1465  if (NULL == cData.pch_service_name) {
1466  cData.pch_service_name = "gtk_display_service";
1467  }
1468 
1469  cData.paB = paB = skn_get_default_interface_name_and_ipv4_address((char *)&cData.ch_intfName, (char *)&cData.ch_this_ip);
1470  if (NULL == paB) {
1471  g_error("skn_skn_get_default_interface_name_and_ipv4_address() => Unable to discover network interface or non-available.");
1472  exit(EXIT_FAILURE);
1473  }
1474 
1475  winDestroy.loop = sigTerm.loop = sigInt.loop = sigHup.loop = cData.loop = loop = g_main_loop_new(NULL, FALSE);
1476  sigTerm.signalName = "SIGTERM";
1477  sigInt.signalName = "SIGINT";
1478  sigHup.signalName = "SIGHUP";
1479  winDestroy.signalName = "gtkDestroyWindow";
1480  cData.resolver = g_resolver_get_default();
1481  cData.queueMessage = g_async_queue_new();
1482  cData.queueRegistry = g_async_queue_new();
1483  cData.queueGSSDPRegistry = g_async_queue_new();
1484  cData.gMsgCount = 0;
1485  cData.gRegCount = 0;
1486  cData.gGSSDPRegCount = 0;
1487 
1488 
1489  /*
1490  * Create and Add MessageQueue to main loop for service (i.e. incoming messages) */
1491  gMsgSource = message_queue_source_new (cData.queueMessage, (GDestroyNotify) g_free, NULL);
1492  g_source_ref(gMsgSource);
1493  g_source_set_callback (gMsgSource, (GSourceFunc)cb_message_request_handler, &cData, NULL);
1494  cData.gMsgSourceId = g_source_attach (gMsgSource, NULL);
1495 
1496  gRegSource = message_queue_source_new(cData.queueRegistry, (GDestroyNotify) g_free, NULL);
1497  g_source_ref(gRegSource);
1498  g_source_set_callback (gRegSource, (GSourceFunc)cb_registry_request_handler, &cData, NULL);
1499  cData.gRegSourceId = g_source_attach (gRegSource, NULL);
1500 
1501  gGSSDPRegSource = message_queue_source_new(cData.queueGSSDPRegistry, (GDestroyNotify) g_free, NULL);
1502  g_source_ref(gGSSDPRegSource);
1503  g_source_set_callback (gGSSDPRegSource, (GSourceFunc)cb_gssdp_registry_request_handler, &cData, NULL);
1504  cData.gGSSDPRegSourceId = g_source_attach (gGSSDPRegSource, NULL);
1505 
1506  /*
1507  * Create regular UDP Socket for receiving messages */
1508  gSock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
1509  if (error != NULL) {
1510  g_error("g_socket_new() => %s", error->message);
1511  g_clear_error(&error);
1512  exit(EXIT_FAILURE);
1513  }
1514 
1515  anyAddr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
1516  gsAddr = g_inet_socket_address_new(anyAddr, gUDPPort);
1517 
1518  g_socket_bind(gSock, gsAddr, TRUE, &error);
1519  if (error != NULL) {
1520  g_error("g_socket_bind() => %s", error->message);
1521  g_clear_error(&error);
1522  exit(EXIT_FAILURE);
1523  }
1524 
1525  gCommSource = g_socket_create_source (gSock, G_IO_IN, NULL);
1526  g_source_ref(gCommSource);
1527  g_source_set_callback (gCommSource, (GSourceFunc) cb_udp_comm_request_handler, &cData, NULL); // its really a GSocketSourceFunc
1528  cData.gCommSourceId = g_source_attach (gCommSource, NULL);
1529 
1530  /*
1531  * Create broadcast UDP Socket for receiving messages */
1532  cData.gbSock = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
1533  if (error != NULL) {
1534  g_error("g_socket_new(broadcast) => %s", error->message);
1535  g_clear_error(&error);
1536  exit(EXIT_FAILURE);
1537  }
1538  g_socket_set_broadcast(cData.gbSock, TRUE);
1539 
1540  gbAddr = g_inet_socket_address_new(anyAddr, UDP_BROADCAST_PORT);
1541  g_object_unref(anyAddr);
1542 
1543  g_socket_bind(cData.gbSock, gbAddr, TRUE, &error);
1544  if (error != NULL) {
1545  g_error("g_socket_bind() => %s", error->message);
1546  g_clear_error(&error);
1547  exit(EXIT_FAILURE);
1548  }
1549 
1550  gBroadSource = g_socket_create_source(cData.gbSock, G_IO_IN, NULL);
1551  g_source_ref(gBroadSource);
1552  g_source_set_callback (gBroadSource, (GSourceFunc) cb_udp_broadcast_response_handler, &cData, NULL); // its really a GSocketSourceFunc
1553  cData.gBroadSourceId = g_source_attach (gBroadSource, NULL);
1554 
1555  g_timeout_add(MS_TEN_MINUTES, (GSourceFunc)cb_registry_refresh, &cData);
1556 
1557  /*
1558  * Handle ctrl-break and kill signals cleanly */
1559  g_unix_signal_add (SIGINT, (GSourceFunc) cb_unix_signal_handler, &sigInt); // SIGINT signal (Ctrl+C)
1560  g_unix_signal_add (SIGTERM,(GSourceFunc) cb_unix_signal_handler, &sigTerm);
1561  g_unix_signal_add (SIGHUP, (GSourceFunc) cb_unix_signal_handler, &sigHup);
1562 
1563  /*
1564  * Create a GTK+3 Page to show messages */
1565  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1566  gtk_window_set_title (GTK_WINDOW (window), "Gtk Display Service");
1567  gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1568  gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
1569  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(cb_gtk_shutdown), &winDestroy);
1570 
1571  /*
1572  * Create body of main page */
1573  ui_page_layout(GTK_WIDGET(window), &cData);
1574 
1575  gtk_widget_show_all(GTK_WIDGET(window));
1576 
1577 
1578  /*
1579  * Broadcast Registry Request: 10.100.1.255 */
1580  if ( gssdp_publish(&cData, gUDPPort) && gssdp_browse(&cData) && skn_udp_network_broadcast_all_interfaces(cData.gbSock, paB) ) {
1581  g_message("gtkDS: Ready to do Good, on %s:%s:%d...\n", cData.ch_intfName, cData.ch_this_ip, gUDPPort);
1582 
1583  g_main_loop_run(loop);
1584  }
1585 
1586  gssdp_resource_browser_set_active(cData.resource_browser, FALSE);
1587  gssdp_resource_group_set_available (cData.resource_group, FALSE);
1588 
1589  g_source_unref(gCommSource);
1590  g_source_unref(gBroadSource);
1591  g_source_unref(gRegSource);
1592  g_source_unref(gMsgSource);
1593  g_source_unref(gGSSDPRegSource);
1594  g_object_unref(gSock);
1595  g_object_unref(cData.gbSock);
1596  g_object_unref(gsAddr);
1597  g_object_unref(gbAddr);
1598  g_object_unref(cData.resolver);
1599  g_async_queue_unref(cData.queueRegistry);
1600  g_async_queue_unref(cData.queueMessage);
1601  g_async_queue_unref(cData.queueGSSDPRegistry);
1602  g_object_unref (cData.resource_browser);
1603  g_object_unref (cData.resource_group);
1604  g_object_unref (cData.gssdp_rgroup_client);
1605 
1606  g_main_loop_unref(loop);
1607 
1608  g_message("gtkDS: shutdown...");
1609 
1610  exit(EXIT_SUCCESS);
1611 }
char ifNameStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:68
gboolean ui_add_message_entry(GtkWidget *treeview, PMsgData msg, gboolean limiter)
Definition: gtkDS.c:1172
struct _registryData RegData
struct _ipBroadcastArray * PIPBroadcastArray
GSSDPResourceBrowser * resource_browser
Definition: gssdpDC.c:108
#define MS_TEN_MINUTES
Definition: gtkDS.c:58
struct _gssdpRegistryData * PGSSDPRegData
#define UDP_BROADCAST_PORT
Definition: gtkDS.c:56
guint gMsgCount
Definition: gtkDS.c:119
gint skn_get_default_interface_name(char *pchDefaultInterfaceName)
Definition: gtkDS.c:438
char ipAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:69
#define UDP_COMM_PORT
Definition: gtkDS.c:55
#define ARY_MAX_INTF
Definition: gtkDS.c:72
gchar * pch_service_name
Definition: cmdDS.c:101
gchar ch_timestamp[SZ_TIMESTAMP_BUFF]
Definition: gtkDS.c:87
#define PLATFORM_ERROR
Definition: gtkDS.c:73
GDestroyNotify destroy_message
Definition: gtkDS.c:224
struct _ipBroadcastArray IPBroadcastArray
char maskAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:70
gchar ch_ip[SZ_PARAMS_BUFF]
Definition: cmdDC.c:85
guint gCommSourceId
Definition: gtkDS.c:116
_messages
Definition: gtkDS.c:146
GAsyncQueue * queueMessage
Definition: gtkDS.c:131
#define SZ_RESPONSE_BUFF
Definition: gtkDS.c:53
#define SZ_CHAR_BUFF
Definition: gtkDS.c:67
gint gStatusContextId
Definition: gtkDS.c:122
GAsyncQueue * queueGSSDPRegistry
Definition: gtkDS.c:133
static gboolean message_queue_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
Definition: gtkDS.c:241
guint gRegCount
Definition: cmdDC.c:104
gchar ch_message[SZ_MESSAGE_BUFF]
Definition: cmdDS.c:80
#define FALSE
static gboolean cb_message_request_handler(PMsgData msg, PControlData pctrl)
Definition: gtkDS.c:754
gchar ch_timestamp[SZ_TIMESTAMP_BUFF]
Definition: gssdpDC.c:92
GtkWidget * ui_registry_page_new(GtkWidget *parent, guint gSmall)
Definition: gtkDS.c:1029
gchar * skn_gio_condition_to_string(GIOCondition condition)
Definition: gtkDS.c:801
gchar * skn_strip(gchar *alpha)
Definition: gtkDS.c:834
char cbName[SZ_CHAR_BUFF]
Definition: cmdDC.c:66
gchar ch_remoteAddress[SZ_RMTADDR_BUFF]
Definition: gtkDS.c:88
_registry
Definition: gtkDS.c:153
gchar ch_port[SZ_PARAMS_BUFF]
Definition: cmdDC.c:86
gboolean ui_add_registry_entry(GtkWidget *treeview, PRegData msg, gboolean limiter)
Definition: gtkDS.c:1195
GtkWidget * pg2Target
Definition: gtkDS.c:136
static gboolean cb_udp_broadcast_response_handler(GSocket *gSock, GIOCondition condition, PControlData pctrl)
Definition: gtkDS.c:550
_gssdp_registry
Definition: gtkDS.c:162
#define SZ_TIMESTAMP_BUFF
Definition: gtkDS.c:49
guint ui_update_status_bar(PControlData pctrl)
Definition: gtkDS.c:522
gboolean(* MessageQueueSourceFunc)(gpointer message, gpointer user_data)
Definition: gtkDS.c:234
int main(int argc, char **argv)
Definition: gtkDS.c:1412
static gboolean cb_unix_signal_handler(PUSignalData psig)
Definition: gtkDS.c:535
#define TRUE
gboolean gssdp_browse(PControlData pctrl)
Definition: gtkDS.c:1401
#define SZ_INFO_BUFF
Definition: gtkDS.c:66
gboolean gssdp_publish(PControlData pctrl, guint udp_port)
Definition: gtkDS.c:1364
static GSourceFuncs message_queue_source_funcs
Definition: gtkDS.c:299
gchar ch_status[SZ_PARAMS_BUFF]
Definition: gssdpDC.c:95
GtkWidget * statusBar
Definition: gtkDS.c:134
static void cb_gssdp_resource_unavailable(GSSDPResourceBrowser *resource_browser, const char *usn, PControlData pctrl)
Definition: gtkDS.c:1337
GMainLoop * loop
Definition: cmdDC.c:91
static void cb_gtk_shutdown(GtkWidget *object, gpointer data)
Definition: gtkDS.c:1296
#define SZ_RMTADDR_BUFF
Definition: gtkDS.c:51
#define G_OPTION_FLAG_NONE
Definition: gtkDS.c:45
gchar * signalName
Definition: cmdDC.c:78
struct _registryData ** PPRegData
gchar ch_name[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:84
GSource parent
Definition: gtkDS.c:222
gchar ch_urn[SZ_RMTADDR_BUFF]
Definition: gssdpDC.c:93
int defaultIndex
Definition: cmdDC.c:72
GSocket * gbSock
Definition: cmdDS.c:95
guint gUDPPort
Definition: cmdDS.c:102
PPRegData udp_registry_response_parser(PRegData msg, gchar *response)
Definition: gtkDS.c:870
PIPBroadcastArray skn_get_default_interface_name_and_ipv4_address(char *intf, char *ipv4)
struct _messageData MsgData
guint gMsgSourceId
Definition: gtkDS.c:114
gchar ch_this_ip[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:109
static gboolean cb_registry_refresh(PControlData pctrl)
Definition: gtkDS.c:541
gchar ch_message[SZ_MESSAGE_BUFF]
Definition: gtkDS.c:89
struct _controlData ControlData
char chDefaultIntfName[SZ_CHAR_BUFF]
Definition: cmdDC.c:67
static gboolean cb_gssdp_registry_request_handler(PGSSDPRegData msg, PControlData pctrl)
Definition: gtkDS.c:786
struct _controlData * PControlData
#define SKN_SMALL_DISPLAY_MODE_OFF
Definition: gtkDS.c:61
guint gGSSDPRegCount
Definition: gtkDS.c:120
static void message_queue_source_finalize(GSource *source)
Definition: gtkDS.c:272
struct _signalData * PUSignalData
guint gSmall
Definition: gtkDS.c:124
PIPBroadcastArray paB
Definition: cmdDC.c:102
gboolean ui_add_gssdp_registry_entry(GtkWidget *treeview, PGSSDPRegData msg, gboolean limiter)
Definition: gtkDS.c:1220
static gboolean message_queue_source_prepare(GSource *source, gint *timeout_)
Definition: gtkDS.c:236
GAsyncQueue * queueRegistry
Definition: gtkDS.c:132
gchar ch_from[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:83
GAsyncQueue * queue
Definition: gtkDS.c:223
#define SZ_PARAMS_BUFF
Definition: gtkDS.c:50
GtkWidget * ui_page_layout(GtkWidget *parent, PControlData pctrl)
Definition: gtkDS.c:1244
static gboolean message_queue_source_closure_callback(gpointer message, gpointer user_data)
Definition: gtkDS.c:277
#define SZ_MESSAGE_BUFF
Definition: gtkDS.c:52
struct _registryData * PRegData
enum _messages EMessages
struct _signalData USignalData
enum _registry EUDPRegistry
GSource * message_queue_source_new(GAsyncQueue *queue, GDestroyNotify destroy_message, GCancellable *cancellable)
Definition: gtkDS.c:326
struct _gssdpRegistryData GSSDPRegData
static void cb_gssdp_resource_available(GSSDPResourceBrowser *resource_browser, const char *usn, GList *locations, PControlData pctrl)
Definition: gtkDS.c:1303
guint gBroadSourceId
Definition: cmdDS.c:91
gchar ch_location[SZ_RMTADDR_BUFF]
Definition: gssdpDC.c:94
gchar ch_timestamp[SZ_TIMESTAMP_BUFF]
Definition: cmdDC.c:82
GMainLoop * loop
Definition: cmdDC.c:77
guint gGSSDPRegSourceId
Definition: gtkDS.c:118
static gboolean cb_udp_comm_request_handler(GSocket *socket, GIOCondition condition, PControlData pctrl)
Definition: gtkDS.c:659
guint gRegSourceId
Definition: gtkDS.c:115
GtkWidget * ui_message_page_new(GtkWidget *parent, guint gSmall)
Definition: gtkDS.c:970
char broadAddrStr[ARY_MAX_INTF][SZ_CHAR_BUFF]
Definition: cmdDC.c:71
GSSDPResourceGroup * resource_group
Definition: gtkDS.c:127
GResolver * resolver
Definition: cmdDC.c:100
GtkWidget * ui_gssdp_registry_page_new(GtkWidget *parent, guint gSmall)
Definition: gtkDS.c:1104
gchar * pch_search
Definition: gssdpDC.c:118
enum _gssdp_registry EGSSDPRegistry
gint skn_get_broadcast_ip_array(PIPBroadcastArray paB)
Definition: gtkDS.c:377
GtkWidget * pg1Target
Definition: gtkDS.c:135
#define MAX_MESSAGES_VIEWABLE
Definition: gtkDS.c:63
struct _messageData * PMsgData
gboolean skn_udp_network_broadcast_all_interfaces(GSocket *gSock, PIPBroadcastArray pab)
Definition: gtkDS.c:489
gchar * skn_get_timestamp()
Definition: gtkDS.c:515
GSSDPClient * gssdp_rgroup_client
Definition: gssdpDC.c:107
gchar ch_intfName[SZ_RMTADDR_BUFF]
Definition: cmdDC.c:108
static gboolean cb_registry_request_handler(PRegData msg, PControlData pctrl)
Definition: gtkDS.c:770
GtkWidget * pg3Target
Definition: gtkDS.c:137