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