gmyth/src/gmyth_monitor_handler.c
author renatofilho
Thu Jun 14 18:19:52 2007 +0100 (2007-06-14)
branchtrunk
changeset 750 312d6bc514f3
parent 701 2f28edb4d804
child 754 cb885ee44618
permissions -rw-r--r--
[svn r756] fixed indent using GNU Style
     1 /**
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_monitor_handler.c
     5  * 
     6  * @brief <p> GMythMonitorHandler deals with the streaming media events remote/local
     7  * that are sent to the MythTV frontend.
     8  *
     9  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    10  * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
    11  *
    12  * 
    13  * This program is free software; you can redistribute it and/or modify
    14  * it under the terms of the GNU Lesser General Public License as published by
    15  * the Free Software Foundation; either version 2 of the License, or
    16  * (at your option) any later version.
    17  *
    18  * This program is distributed in the hope that it will be useful,
    19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    21  * GNU General Public License for more details.
    22  *
    23  * You should have received a copy of the GNU Lesser General Public License
    24  * along with this program; if not, write to the Free Software
    25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    26  *
    27  * GStreamer MythTV plug-in properties:
    28  * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
    29  * - path (qurl - remote file to be opened)
    30  * - port number *   
    31  */
    32 
    33 #ifdef HAVE_CONFIG_H
    34 #include "config.h"
    35 #endif
    36 
    37 #include <unistd.h>
    38 #include <glib.h>
    39 #include <arpa/inet.h>
    40 #include <sys/types.h>
    41 #include <sys/socket.h>
    42 #include <netdb.h>
    43 #include <errno.h>
    44 #include <stdlib.h>
    45 #include <assert.h>
    46 
    47 #include "gmyth_marshal.h"
    48 
    49 #include "gmyth_monitor_handler.h"
    50 #include "gmyth_debug.h"
    51 
    52 #define GMYTHTV_QUERY_HEADER		"QUERY_FILETRANSFER "
    53 
    54 #define GMYTHTV_VERSION							30
    55 
    56 #define GMYTHTV_TRANSFER_MAX_WAITS	700
    57 
    58 #define GMYTHTV_BUFFER_SIZE					8*1024
    59 
    60 #ifdef GMYTHTV_ENABLE_DEBUG
    61 #define GMYTHTV_ENABLE_DEBUG				1
    62 #else
    63 #undef GMYTHTV_ENABLE_DEBUG
    64 #endif
    65 
    66 /* this NDEBUG is to maintain compatibility with GMyth library */
    67 #ifndef NDEBUG
    68 #define GMYTHTV_ENABLE_DEBUG				1
    69 #endif
    70 
    71 gpointer gmyth_monitor_handler_listener(gpointer data);
    72 
    73 static void gmyth_monitor_handler_default_listener(GMythMonitorHandler *
    74 												   monitor, gint msg_code,
    75 												   gchar * message);
    76 
    77 static void gmyth_monitor_handler_class_init(GMythMonitorHandlerClass *
    78 											 klass);
    79 static void gmyth_monitor_handler_init(GMythMonitorHandler * object);
    80 
    81 static void gmyth_monitor_handler_dispose(GObject * object);
    82 static void gmyth_monitor_handler_finalize(GObject * object);
    83 
    84 static gboolean gmyth_connect_to_backend_monitor(GMythMonitorHandler *
    85 												 monitor);
    86 
    87 static gboolean gmyth_monitor_handler_setup(GMythMonitorHandler * monitor,
    88 											GIOChannel * channel);
    89 
    90 void gmyth_monitor_handler_close(GMythMonitorHandler * monitor);
    91 
    92 G_DEFINE_TYPE(GMythMonitorHandler, gmyth_monitor_handler, G_TYPE_OBJECT)
    93 	 static void
    94 	   gmyth_monitor_handler_class_init(GMythMonitorHandlerClass * klass)
    95 {
    96   GObjectClass *gobject_class;
    97   GMythMonitorHandlerClass *gmonitor_class;
    98 
    99   gobject_class = (GObjectClass *) klass;
   100   gmonitor_class = (GMythMonitorHandlerClass *) gobject_class;
   101 
   102   gobject_class->dispose = gmyth_monitor_handler_dispose;
   103   gobject_class->finalize = gmyth_monitor_handler_finalize;
   104 
   105   gmonitor_class->backend_events_handler_signal_id =
   106 	g_signal_new("backend-events-handler",
   107 				 G_TYPE_FROM_CLASS(gmonitor_class),
   108 				 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
   109 				 G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
   110 				 gmyth_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
   111 				 G_TYPE_INT, G_TYPE_STRING);
   112 
   113   gmonitor_class->backend_events_handler =
   114 	gmyth_monitor_handler_default_listener;
   115 
   116 }
   117 
   118 static void
   119 gmyth_monitor_handler_init(GMythMonitorHandler * monitor)
   120 {
   121   g_return_if_fail(monitor != NULL);
   122 
   123   monitor->event_sock = NULL;
   124   monitor->hostname = NULL;
   125   monitor->port = 0;
   126   monitor->actual_index = 0;
   127 
   128   monitor->allow_msgs_listener = FALSE;
   129 
   130  /* monitor->backend_msgs = g_hash_table_new( g_int_hash, g_int_equal ); */
   131 
   132  /* it is used for signalizing the event socket consumer thread */
   133   monitor->mutex = g_mutex_new();
   134 
   135   monitor->th = NULL;
   136 
   137   monitor->gmyth_monitor_handler_listener = gmyth_monitor_handler_listener;
   138 }
   139 
   140 static void
   141 gmyth_monitor_handler_dispose(GObject * object)
   142 {
   143   GMythMonitorHandler *monitor = GMYTH_MONITOR_HANDLER(object);
   144 
   145   gmyth_monitor_handler_close(monitor);
   146 
   147   monitor->allow_msgs_listener = FALSE;
   148 
   149   if (monitor->th != NULL)
   150 	{
   151 	  gboolean *ret = (gboolean *) g_thread_join(monitor->th);
   152 
   153 	  if (*ret == FALSE)
   154 		gmyth_debug("Error closing GThread listener socket!");
   155 	  else
   156 		gmyth_debug("Closed GThread listener socket.");
   157 	 //g_object_unref( monitor->th );
   158 	}
   159 
   160  /* mutex to control access to the event socket consumer thread */
   161   if (monitor->mutex != NULL)
   162 	{
   163 	 //g_mutex_unlock( monitor->mutex );
   164 	  g_mutex_free(monitor->mutex);
   165 	  monitor->mutex = NULL;
   166 	}
   167 
   168   if (monitor->event_sock != NULL)
   169 	{
   170 	  g_object_unref(monitor->event_sock);
   171 	  monitor->event_sock = NULL;
   172 	}
   173 
   174   if (monitor->hostname != NULL)
   175 	{
   176 	  g_free(monitor->hostname);
   177 	  monitor->hostname = NULL;
   178 	}
   179 
   180   if (monitor->backend_msgs != NULL)
   181 	{
   182 	  g_hash_table_destroy(monitor->backend_msgs);
   183 	  monitor->backend_msgs = NULL;
   184 	}
   185 
   186  /*
   187     if ( io_watcher_cond != NULL )  
   188     {
   189     g_cond_free( io_watcher_cond );
   190     io_watcher_cond = NULL;
   191     }
   192   */
   193 
   194   G_OBJECT_CLASS(gmyth_monitor_handler_parent_class)->dispose(object);
   195 }
   196 
   197 static void
   198 gmyth_monitor_handler_finalize(GObject * object)
   199 {
   200   g_signal_handlers_destroy(object);
   201 
   202   G_OBJECT_CLASS(gmyth_monitor_handler_parent_class)->finalize(object);
   203 }
   204 
   205 /** 
   206  * Creates a new instance of GMyth Monitor Handler.
   207  * 
   208  * @return a new instance of the Monitor Handler. 
   209  */
   210 GMythMonitorHandler *
   211 gmyth_monitor_handler_new(void)
   212 {
   213   GMythMonitorHandler *monitor =
   214 	GMYTH_MONITOR_HANDLER(g_object_new(GMYTH_MONITOR_HANDLER_TYPE, FALSE));
   215 
   216   return monitor;
   217 }
   218 
   219 /** 
   220  * Acquire the mutex to have access to the IO Watcher listener.
   221  * 
   222  * @param monitor The GMythMonitorHandler instance.
   223  * @param do_wait Tells the IO Watcher to wait on the GCond. (obsolete)
   224  * 
   225  * @return <code>true</code>, if the access to IO Watcher was acquired. 
   226  */
   227 static gboolean
   228 myth_control_acquire_context(GMythMonitorHandler * monitor, gboolean do_wait)
   229 {
   230 
   231   gboolean ret = TRUE;
   232 
   233   g_mutex_lock(monitor->mutex);
   234 
   235   return ret;
   236 
   237 }
   238 
   239 /** 
   240  * Release the mutex to have access to the IO Watcher listener.
   241  * 
   242  * @param monitor The GMythMonitorHandler instance.
   243  * 
   244  * @return <code>true</code>, if the access to IO Watcher was released. 
   245  */
   246 static gboolean
   247 myth_control_release_context(GMythMonitorHandler * monitor)
   248 {
   249 
   250   gboolean ret = TRUE;
   251 
   252   g_mutex_unlock(monitor->mutex);
   253 
   254   return ret;
   255 }
   256 
   257 void
   258 gmyth_monitor_handler_close(GMythMonitorHandler * monitor)
   259 {
   260   monitor->allow_msgs_listener = FALSE;
   261 
   262 #if 0
   263   if (monitor->monitor_th != NULL)
   264 	{
   265 	  g_thread_pool_free(monitor->monitor_th, TRUE, FALSE);
   266 	 //g_thread_exit( monitor->monitor_th );
   267 	 /*if ( monitor->monitor_th != NULL )
   268 	    g_object_unref( monitor->monitor_th ); */
   269 	  monitor->monitor_th = NULL;
   270 	}
   271 
   272   if (monitor->event_sock != NULL)
   273 	{
   274 	  gmyth_socket_close_connection(monitor->event_sock);
   275 	}
   276 #endif
   277 
   278 }
   279 
   280 /** 
   281  * Opens connection the the Monitor socket on MythTV backend server,
   282  * where all status messages are notified to the client.
   283  * 
   284  * @param monitor The GMythMonitorHandler instance.
   285  * @param hostname The remote host name of the MythTV backend server.
   286  * @param port The remote port number of the MythTV backend server.
   287  * 
   288  * @return <code>true</code>, if the connection was successfully opened.
   289  */
   290 gboolean
   291 gmyth_monitor_handler_open(GMythMonitorHandler * monitor,
   292 						   const gchar * hostname, gint port)
   293 {
   294   gboolean ret = TRUE;
   295 
   296   g_return_val_if_fail(hostname != NULL, FALSE);
   297 
   298   if (monitor->hostname != NULL)
   299 	{
   300 	  g_free(monitor->hostname);
   301 	  monitor->hostname = NULL;
   302 	}
   303 
   304   monitor->hostname = g_strdup(hostname);
   305   monitor->port = port;
   306 
   307   gmyth_debug("Monitor event socket --- hostname: %s, port %d\n",
   308 			  monitor->hostname, monitor->port);
   309 
   310   if (NULL != monitor->event_sock)
   311 	{
   312 	  g_object_unref(monitor->event_sock);
   313 	  monitor->event_sock = NULL;
   314 	}
   315 
   316  /* configure the event socket */
   317   if (NULL == monitor->event_sock)
   318 	{
   319 	  if (!gmyth_connect_to_backend_monitor(monitor))
   320 		{
   321 		  gmyth_debug("Connection to backend failed (Event Socket)!");
   322 		  ret = FALSE;
   323 		}
   324 	  else
   325 		{
   326 		  gmyth_debug
   327 			("Remote monitor event socket had been succesfully created. (io_fd == %d)\n",
   328 			 g_io_channel_unix_get_fd(monitor->event_sock->sd_io_ch));
   329 		}
   330 	}
   331   else
   332 	{
   333 	  gmyth_debug
   334 		("ASSERT ERROR: Remote monitor event socket is not NULL at the setup...\n");
   335 	}
   336 
   337   return ret;
   338 
   339 }
   340 
   341 /** 
   342  * Reads the data got from the connection to the Monitor socket,
   343  * and looks for some important status messages.
   344  * 
   345  * @param monitor The GMythMonitorHandler instance.
   346  * @param strlist The GMythStringList instance got from the Monitor remote socket.
   347  * @param back_msg_action A string pointer to the status message detailed description.
   348  * 
   349  * @return The backend status message code ID.
   350  */
   351 static gint
   352 gmyth_monitor_handler_is_backend_message(GMythMonitorHandler * monitor,
   353 										 GMythStringList * strlist,
   354 										 gchar ** back_msg_action)
   355 {
   356   gint msg_type = GMYTH_BACKEND_NO_MESSAGE;
   357   GString *back_msg = NULL;
   358 
   359   if (gmyth_string_list_length(strlist) > 0)
   360 	{
   361 
   362 	  back_msg = gmyth_string_list_get_string(strlist, 0);
   363 	  if (back_msg != NULL && back_msg->str != NULL &&
   364 		  strstr(back_msg->str, "BACKEND") != NULL)
   365 		{
   366 		  gmyth_debug("MONITOR HANDLER - Received backend message = %s",
   367 					  back_msg->str);
   368 		  *back_msg_action = gmyth_string_list_get_char_array(strlist, 1);
   369 
   370 		  if (back_msg_action != NULL)
   371 			{
   372 
   373 			  if (g_strstr_len
   374 				  (*back_msg_action, strlen(*back_msg_action),
   375 				   "LIVETV_CHAIN")
   376 				  || g_strstr_len(*back_msg_action,
   377 								  strlen(*back_msg_action),
   378 								  "RECORDING_LIST_CHANGE")
   379 				  || g_strstr_len(*back_msg_action,
   380 								  strlen(*back_msg_action),
   381 								  "SCHEDULE_CHANGE")
   382 				  || g_strstr_len(*back_msg_action,
   383 								  strlen(*back_msg_action), "LIVETV_WATCH"))
   384 				{
   385 				  gmyth_debug
   386 					("MONITOR: message type == GMYTH_BACKEND_PROGRAM_INFO_CHANGED, msg = %s",
   387 					 *back_msg_action);
   388 				  msg_type = GMYTH_BACKEND_PROGRAM_INFO_CHANGED;
   389 				}
   390 			  else if (g_strstr_len
   391 					   (*back_msg_action, strlen(*back_msg_action),
   392 						"DONE_RECORDING"))
   393 				{
   394 				  gmyth_debug
   395 					("MONITOR: message type == GMYTH_BACKEND_DONE_RECORDING, msg = %s",
   396 					 *back_msg_action);
   397 				  msg_type = GMYTH_BACKEND_DONE_RECORDING;
   398 				}
   399 			  else if (g_strstr_len
   400 					   (*back_msg_action, strlen(*back_msg_action), "QUIT"))
   401 				{
   402 				  gmyth_debug
   403 					("MONITOR: message type == GMYTH_BACKEND_STOP_LIVETV, msg = %s",
   404 					 *back_msg_action);
   405 				  msg_type = GMYTH_BACKEND_STOP_LIVETV;
   406 				}
   407 
   408 			 /* g_hash_table_insert ( monitor->backend_msgs,
   409 			    &(monitor->actual_index), *back_msg_action ); */
   410 
   411 			}
   412 		 /*  if  */
   413 		}
   414 	 /* if */
   415 	  if (back_msg != NULL)
   416 		{
   417 		  g_string_free(back_msg, TRUE);
   418 		  back_msg = NULL;
   419 		}
   420 
   421 	}							/* if - Does Monitor got any message from backend? */
   422   else
   423 	{
   424 	  *back_msg_action = g_strdup("");
   425 	}
   426 
   427   return msg_type;
   428 
   429 }
   430 
   431 static void
   432 gmyth_monitor_handler_default_listener(GMythMonitorHandler * monitor,
   433 									   gint msg_code, gchar * message)
   434 {
   435  //assert( message!= NULL );  
   436   gmyth_debug("DEFAULT Signal handler ( msg = %s, code = %d )\n",
   437 			  message, msg_code);
   438 }
   439 
   440 static void
   441 gmyth_monitor_handler_print(GString * str, gpointer ptr)
   442 {
   443   gmyth_debug("Backend message event: %s --- ", str->str);
   444 }
   445 
   446 /** 
   447  * Opens connection the the Monitor socket on MythTV backend server,
   448  * where all status messages are notified to the client.
   449  * 
   450  * @param data Pointer to the GMythMonitorHandler.
   451  * 
   452  * @return Pointer to a gboolean <code>true</code> value, if the data was 
   453  * 	successfully read.
   454  */
   455 gpointer
   456 gmyth_monitor_handler_listener(gpointer data)
   457 {
   458   GMythMonitorHandler *monitor = (GMythMonitorHandler *) data;
   459   guint recv = 0;
   460   gboolean *ret = g_new0(gboolean, 1);
   461   gsize len = 0;
   462   GIOChannel *io_channel = monitor->event_sock->sd_io_ch;
   463   GIOCondition io_cond = g_io_channel_get_buffer_condition(io_channel);
   464   static guint count = 0;
   465 
   466   *ret = TRUE;
   467 
   468   gmyth_debug("Entering MONITOR handler listener...");
   469 
   470   myth_control_acquire_context(monitor, TRUE);
   471 
   472   if ((io_cond & G_IO_HUP) != 0)
   473 	{
   474 	  *ret = FALSE;
   475 	  goto clean_up;
   476 	}
   477 
   478   GMythStringList *strlist = NULL;
   479 
   480   if (NULL == io_channel)
   481 	{
   482 	  gmyth_debug("Monitor socket is NULL! (GIOChannel)");
   483 	  *ret = FALSE;
   484 	  goto clean_up;
   485 	}
   486 
   487   while (monitor->allow_msgs_listener)
   488 	{
   489 	  ++count;
   490 
   491 	  gmyth_debug("%d - Listening on Monitor socket...!\n", count);
   492 
   493 	  do
   494 		{
   495 
   496 		  gint bytes_sent = 0;
   497 
   498 		  strlist = gmyth_string_list_new();
   499 
   500 		  if (monitor->event_sock != NULL)
   501 			{
   502 
   503 			  len =
   504 				gmyth_socket_read_stringlist(monitor->event_sock, strlist);
   505 
   506 			  if ((len > 0) && strlist != NULL
   507 				  && gmyth_string_list_length(strlist) > 0)
   508 				{
   509 				  bytes_sent = gmyth_string_list_get_int(strlist, 0);	// -1 on backend error
   510 
   511 				  gmyth_debug
   512 					("[%s] MONITOR: received data buffer from IO event channel... %d strings gone!\n",
   513 					 __FUNCTION__, len);
   514 
   515 				  recv += len;
   516 
   517 				 /* debug purpose: prints out all the string list elements */
   518 				  g_list_foreach(strlist->glist,
   519 								 (GFunc) gmyth_monitor_handler_print, NULL);
   520 
   521 				  gchar *back_msg_action = g_new0(gchar, 1);
   522 				  gint msg_type =
   523 					gmyth_monitor_handler_is_backend_message(monitor,
   524 															 strlist,
   525 															 &back_msg_action);
   526 
   527 				  if (monitor != NULL && msg_type != GMYTH_BACKEND_NO_MESSAGE)
   528 					g_signal_emit(monitor, GMYTH_MONITOR_HANDLER_GET_CLASS(monitor)->backend_events_handler_signal_id, 0,	/* details */
   529 								  msg_type, back_msg_action);
   530 
   531 				  if (back_msg_action != NULL)
   532 					g_free(back_msg_action);
   533 
   534 				}
   535 
   536 			}
   537 
   538 		  if (strlist != NULL)
   539 			{
   540 			  g_object_unref(strlist);
   541 			  strlist = NULL;
   542 			}
   543 
   544 		  io_cond = g_io_channel_get_buffer_condition(io_channel);
   545 
   546 		  g_usleep(500);
   547 
   548 		}
   549 	  while (recv <= 0 && ((io_cond & G_IO_HUP) == 0));
   550 
   551 	  gmyth_debug("\tMONITOR EVENT: Read %d bytes\n", recv);
   552 
   553 	}							/* main GThread while */
   554 
   555 clean_up:
   556   myth_control_release_context(monitor);
   557 
   558   g_thread_exit(ret);
   559 
   560   return (gpointer) ret;
   561 
   562 }
   563 
   564 /** 
   565  * Opens connection events' socket the the Monitor socket on 
   566  * MythTV backend server.
   567  * 
   568  * @param monitor The GMythMonitorHandler instance.
   569  * 
   570  * @return <code>true</code>, if the socket was successfully opened.
   571  */
   572 static gboolean
   573 gmyth_connect_to_backend_monitor(GMythMonitorHandler * monitor)
   574 {
   575   gboolean ret = TRUE;
   576 
   577   monitor->event_sock = gmyth_socket_new();
   578 
   579  /* Connects the socket, send Mythtv ANN Monitor and verify Mythtv protocol version */
   580   if (!gmyth_socket_connect_to_backend_events(monitor->event_sock,
   581 											  monitor->hostname,
   582 											  monitor->port, FALSE))
   583 	{
   584 	  g_object_unref(monitor->event_sock);
   585 	  monitor->event_sock = NULL;
   586 	  ret = FALSE;
   587 	}
   588 
   589   return ret;
   590 }
   591 
   592 /** 
   593  * Opens connection the the Monitor socket on MythTV backend server,
   594  * where all status messages are notified to the client.
   595  * 
   596  * @param monitor The GMythMonitorHandler instance.
   597  * @param channel The GIOChannel instance to the Monitor socket.
   598  * 
   599  * @return Pointer to the boolean value, and it is <code>true</code> only if the 
   600  * 				 GMythMonitorHandler could be configured.
   601  */
   602 static gboolean
   603 gmyth_monitor_handler_setup(GMythMonitorHandler * monitor,
   604 							GIOChannel * channel)
   605 {
   606   gboolean ret = TRUE;
   607 
   608   if (channel != NULL)
   609 	{
   610 	  monitor->allow_msgs_listener = TRUE;
   611 
   612 	  monitor->th =
   613 		g_thread_create((GThreadFunc) gmyth_monitor_handler_listener,
   614 						monitor, TRUE, NULL);
   615 	  gmyth_debug("MONITOR GThread created!");
   616 	}
   617   else
   618 	{
   619 	  ret = FALSE;
   620 	  goto cleanup;
   621 	}
   622 
   623   if (NULL == monitor->th)
   624 	{
   625 	  gmyth_debug
   626 		("[%s] Error adding GThread listener function to the IO control channel!\n",
   627 		 __FUNCTION__);
   628 	  ret = FALSE;
   629 	  goto cleanup;
   630 	}
   631 
   632 cleanup:
   633 
   634   return ret;
   635 }
   636 
   637 /** 
   638  * Starts the MonitorHandler thread to the GIOWatcher.
   639  * 
   640  * @param monitor The GMythMonitorHandler instance.
   641  * 
   642  * @return <code>true</code>, if the MonitorHandler was started.
   643  */
   644 gboolean
   645 gmyth_monitor_handler_start(GMythMonitorHandler * monitor)
   646 {
   647   gboolean ret = TRUE;
   648 
   649   if (!(ret = g_thread_supported()))
   650 	{
   651 	  gmyth_debug("Thread system wasn't initialized, starting NOW!!!");
   652 	  g_thread_init(NULL);
   653 	}
   654 
   655   ret = gmyth_monitor_handler_setup(monitor, monitor->event_sock->sd_io_ch);
   656   if (ret)
   657 	{
   658 	  gmyth_debug
   659 		("\n[%s]\tOK! Starting listener on the MONITOR event socket...[thread location = %p]\n",
   660 		 __FUNCTION__, g_thread_self());
   661 	}
   662   else
   663 	{
   664 	  gmyth_debug
   665 		("\n[%s]\tERROR! Coudn't start listener on the MONITOR event socket...[thread location = %p]\n",
   666 		 __FUNCTION__, g_thread_self());
   667 	  ret = FALSE;
   668 	}
   669 
   670   gmyth_debug
   671 	("[%s] Watch listener function over the IO control channel? %s!!!\n",
   672 	 __FUNCTION__, (ret == TRUE ? "YES" : "NO"));
   673 
   674   return ret;
   675 }