gmyth/src/gmyth_socket.c
author renatofilho
Fri Feb 01 14:30:21 2008 +0000 (2008-02-01)
branchtrunk
changeset 905 d2d226b5a4bd
parent 817 888b9724f601
permissions -rw-r--r--
[svn r911] created release 0.7; moved debian dir to packages project
     1 /**
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_socket.c
     5  * 
     6  * @brief <p> MythTV socket implementation, according to the MythTV Project
     7  * (www.mythtv.org). 
     8  * 
     9  * This component provides basic socket functionalities to interact with
    10  * the Mythtv backend.
    11  * <p>
    12  *
    13  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    14  * @author Rosfran Lins Borges <rosfran.borges@indt.org.br> 
    15  *
    16  * 
    17  * This program is free software; you can redistribute it and/or modify
    18  * it under the terms of the GNU Lesser General Public License as published by
    19  * the Free Software Foundation; either version 2 of the License, or
    20  * (at your option) any later version.
    21  *
    22  * This program is distributed in the hope that it will be useful,
    23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    25  * GNU General Public License for more details.
    26  *
    27  * You should have received a copy of the GNU Lesser General Public License
    28  * along with this program; if not, write to the Free Software
    29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    30  */
    31 
    32 #ifdef HAVE_CONFIG_H
    33 #include "config.h"
    34 #endif
    35 
    36 #include "gmyth_socket.h"
    37 
    38 #include <glib.h>
    39 #include <glib/gprintf.h>
    40 
    41 #include <arpa/inet.h>
    42 #include <sys/types.h>
    43 #include <sys/socket.h>
    44 #include <sys/param.h>
    45 #include <netdb.h>
    46 #include <net/if.h>
    47 #include <errno.h>
    48 #include <assert.h>
    49 #include <stdlib.h>
    50 
    51 #include <unistd.h>
    52 #include <netinet/in.h>
    53 #include <fcntl.h>
    54 #include <signal.h>
    55 
    56 #include <sys/ioctl.h>
    57 
    58 #include "gmyth_stringlist.h"
    59 #include "gmyth_uri.h"
    60 #include "gmyth_debug.h"
    61 
    62 #define BUFLEN 				   	512
    63 #define MYTH_SEPARATOR 			    	"[]:[]"
    64 #define MYTH_PROTOCOL_FIELD_SIZE		8
    65 
    66 /*
    67  * max number of iterations 
    68  */
    69 #define MYTHTV_MAX_VERSION_CHECKS		40
    70 
    71 // FIXME: put this in the right place
    72 #define  MYTHTV_VERSION_DEFAULT			31
    73 
    74 /*
    75  * static GStaticMutex mutex = G_STATIC_MUTEX_INIT; 
    76  */
    77 
    78 /*
    79  * static GStaticRWLock rwlock = G_STATIC_RW_LOCK_INIT;
    80  */
    81 
    82 static gchar   *local_hostname = NULL;
    83 
    84 static void     gmyth_socket_class_init(GMythSocketClass * klass);
    85 static void     gmyth_socket_init(GMythSocket * object);
    86 
    87 static void     gmyth_socket_dispose(GObject * object);
    88 static void     gmyth_socket_finalize(GObject * object);
    89 
    90 G_DEFINE_TYPE(GMythSocket, gmyth_socket, G_TYPE_OBJECT)
    91     static void     gmyth_socket_class_init(GMythSocketClass * klass)
    92 {
    93     GObjectClass   *gobject_class;
    94 
    95     gobject_class = (GObjectClass *) klass;
    96 
    97     gobject_class->dispose = gmyth_socket_dispose;
    98     gobject_class->finalize = gmyth_socket_finalize;
    99 }
   100 
   101 static void
   102 gmyth_socket_init(GMythSocket * gmyth_socket)
   103 {
   104 
   105     /*
   106      * gmyth_socket->local_hostname = NULL; 
   107      */
   108 
   109 }
   110 
   111 /** Gets the some important address translation info, from the client socket
   112  * that will open a connection.
   113  * 
   114  * @return gint that represents the error number from getaddrinfo(). 
   115  */
   116 static          gint
   117 gmyth_socket_toaddrinfo(const gchar * addr, gint port,
   118                         struct addrinfo **addrInfo)
   119 {
   120     struct addrinfo hints;
   121     gchar          *portStr = NULL;
   122     gint            errorn = EADDRNOTAVAIL;
   123 
   124     g_return_val_if_fail(addr != NULL, -1);
   125 
   126     memset(&hints, 0, sizeof(struct addrinfo));
   127     hints.ai_family = AF_INET;
   128     hints.ai_socktype = SOCK_STREAM;
   129     /*
   130      * hints.ai_flags = AI_NUMERICHOST; 
   131      */
   132 
   133     if (port != -1)
   134         portStr = g_strdup_printf("%d", port);
   135     else
   136         portStr = NULL;
   137 
   138     gmyth_debug("Getting name resolution for: %s, %d\n", addr, port);
   139 
   140     if ((errorn = getaddrinfo(addr, portStr, &hints, addrInfo)) != 0) {
   141         gmyth_debug("[%s] Socket ERROR: %s\n", __FUNCTION__,
   142                     gai_strerror(errorn));
   143     }
   144 
   145     g_free(portStr);
   146 
   147     return errorn;
   148 }
   149 
   150 /*
   151  * static gint gmyth_socket_find_match_address_uri( GMythURI* uri, gchar
   152  * *address ) { if ( g_ascii_strcasecmp( gmyth_uri_get_host( uri ),
   153  * address ) == 0 ) { //gmyth_debug( "Found URI: %s !!!\n",
   154  * rui_uri_getvalue(uri) ); return 0; } else { return -1; } } 
   155  */
   156 
   157 const gchar    *PATH_PROC_NET_DEV = "/proc/net/dev";
   158 
   159 /** Gets the list of all local network interfaces (using the /proc/net/dev directory).
   160  * 
   161  * @param current_connections	A list with all the network interfaces are valid, 
   162  * 		to be applied just like a filter.
   163  * @return List with all the local net interfaces. 
   164  */
   165 GList          *
   166 gmyth_socket_get_local_addrs(GList * current_connections)
   167 {
   168 
   169     GList          *local_addrs = NULL;
   170     FILE           *fd;
   171     gint            s;
   172     gchar           buffer[256 + 1];
   173     gchar           ifaddr[20 + 1];
   174     gchar          *ifname;
   175     gchar          *sep;
   176 
   177     s = socket(AF_INET, SOCK_DGRAM, 0);
   178     if (s < 0)
   179         return 0;
   180     fd = fopen(PATH_PROC_NET_DEV, "r");
   181     fgets(buffer, sizeof(buffer) - 1, fd);
   182     fgets(buffer, sizeof(buffer) - 1, fd);
   183     while (!feof(fd)) {
   184         ifname = buffer;
   185 
   186         if (fgets(buffer, sizeof(buffer) - 1, fd) == NULL)
   187             break;
   188         sep = strrchr(buffer, ':');
   189         if (sep)
   190             *sep = 0;
   191         while (*ifname == ' ')
   192             ifname++;
   193         struct ifreq    req;
   194 
   195         strcpy(req.ifr_name, ifname);
   196         if (ioctl(s, SIOCGIFFLAGS, &req) < 0)
   197             continue;
   198         if (!(req.ifr_flags & IFF_UP))
   199             continue;
   200         if (req.ifr_flags & IFF_LOOPBACK)
   201             continue;
   202         if (ioctl(s, SIOCGIFADDR, &req) < 0)
   203             continue;
   204         g_strlcpy(ifaddr,
   205                   inet_ntoa(((struct sockaddr_in *) &req.ifr_addr)->
   206                             sin_addr), sizeof(struct ifaddr) - 1);
   207         local_addrs = g_list_append(local_addrs, g_strdup(ifaddr));
   208 
   209         gmyth_debug
   210             ("( from the /proc/net/dev) Interface name: %s, address: %s\n",
   211              ifname, ifaddr);
   212     }
   213     fclose(fd);
   214     close(s);
   215     return local_addrs;
   216 }
   217 
   218 /**
   219  * Get only the local addresses from the primary interface
   220  */
   221 gchar          *
   222 gmyth_socket_get_primary_addr(void)
   223 {
   224     gchar          *if_eth0 = g_new0(gchar, sizeof(struct ifaddr) - 1);
   225     GList          *if_tmp = NULL;
   226 
   227     GList          *interfs = gmyth_socket_get_local_addrs(NULL);
   228 
   229     if (interfs != NULL && (g_list_length(interfs) > 0)) {
   230         // get the first occurrence (primary interface) 
   231         if_tmp = g_list_first(interfs);
   232 
   233         if (if_tmp != NULL)
   234             g_strlcpy(if_eth0, (gchar *) if_tmp->data,
   235                       sizeof(struct ifaddr) - 1);
   236 
   237     }
   238 
   239     if (interfs != NULL)
   240         g_list_free(interfs);
   241 
   242     return if_eth0;
   243 }
   244 
   245 /** This function retrieves the local hostname of the 
   246  * client machine.
   247  *
   248  * @return GString* get local hostname.
   249  */
   250 GString        *
   251 gmyth_socket_get_local_hostname(void)
   252 {
   253     char            hname[50];
   254     gint            res = gethostname(hname, 50);
   255 
   256     if (res == -1) {
   257         gmyth_debug("Error while getting hostname");
   258         return g_string_new("default");
   259     }
   260 
   261     return g_string_new(hname);
   262 
   263 #if 0
   264     GString        *str = NULL;
   265 
   266     if (local_hostname != NULL && strlen(local_hostname) > 0)
   267         return g_string_new(local_hostname);
   268 
   269     gchar          *localaddr = NULL;
   270     gboolean        found_addr = FALSE;
   271     struct addrinfo *addr_info_data = NULL,
   272         *addr_info0 = NULL;
   273     struct sockaddr_in *sa = NULL;
   274     gchar           localhostname[MAXHOSTNAMELEN];
   275 
   276 
   277     if (gethostname(localhostname, MAXHOSTNAMELEN) != 0) {
   278         gmyth_debug("Error on gethostname");
   279     }
   280     localhostname[MAXHOSTNAMELEN - 1] = 0;
   281 
   282     gint            err =
   283         gmyth_socket_toaddrinfo(localhostname, -1, &addr_info_data);
   284 
   285     if (err == EADDRNOTAVAIL) {
   286         gmyth_debug("[%s] Address (%s) not available. (reason = %d)\n",
   287                     __FUNCTION__, localhostname, err);
   288         return str;
   289     }
   290 
   291     g_mutex_lock(gmyth_socket->mutex);
   292 
   293     addr_info0 = addr_info_data;
   294 
   295     while (addr_info0 != NULL && addr_info0->ai_addr != NULL &&
   296            (sa = (struct sockaddr_in *) addr_info0->ai_addr) != NULL
   297            && !found_addr) {
   298         localaddr = inet_ntoa(sa->sin_addr);
   299 
   300         if (localaddr != NULL && (g_strrstr(localaddr, "127") == NULL)) {
   301             str = g_string_new(localaddr);
   302             found_addr = TRUE;
   303             g_free(localaddr);
   304             break;
   305         }
   306         /*
   307          * if (localaddr != NULL) { g_free (localaddr); localaddr = NULL;
   308          * } 
   309          */
   310 
   311         addr_info0 = addr_info0->ai_next;
   312     };
   313 
   314     freeaddrinfo(addr_info_data);
   315     addr_info_data = NULL;
   316 
   317     if (found_addr == FALSE) {
   318         gchar          *prim_addr = gmyth_socket_get_primary_addr();
   319 
   320         if (prim_addr != NULL) {
   321             gmyth_debug
   322                 ("[%s] Could not determine the local alphanumerical hostname. Setting to %s\n",
   323                  __FUNCTION__, prim_addr);
   324 
   325             str = g_string_new(prim_addr);
   326             g_free(prim_addr);
   327         } else {
   328             str = g_string_new(localhostname);
   329         }
   330     }
   331 
   332     g_mutex_unlock(gmyth_socket->mutex);
   333 
   334     if (str != NULL && str->str != NULL)
   335         local_hostname = g_strdup(str->str);
   336 
   337     return str;
   338 #endif
   339 }
   340 
   341 static void
   342 gmyth_socket_dispose(GObject * object)
   343 {
   344     GMythSocket    *gmyth_socket = GMYTH_SOCKET(object);
   345 
   346     /*
   347      * disconnect socket 
   348      */
   349     gmyth_socket_close_connection(gmyth_socket);
   350 
   351     g_free(gmyth_socket->hostname);
   352 
   353     g_free(local_hostname);
   354 
   355     local_hostname = NULL;
   356 
   357     if (gmyth_socket->mutex != NULL) {
   358         g_mutex_free(gmyth_socket->mutex);
   359         gmyth_socket->mutex = NULL;
   360     }
   361 
   362     G_OBJECT_CLASS(gmyth_socket_parent_class)->dispose(object);
   363 }
   364 
   365 static void
   366 gmyth_socket_finalize(GObject * object)
   367 {
   368     g_signal_handlers_destroy(object);
   369 
   370     G_OBJECT_CLASS(gmyth_socket_parent_class)->finalize(object);
   371 }
   372 
   373 /** Creates a new instance of GMythSocket.
   374  * 
   375  * @return a new instance of GMythSocket.
   376  */
   377 GMythSocket    *
   378 gmyth_socket_new()
   379 {
   380     GMythSocket    *gmyth_socket =
   381         GMYTH_SOCKET(g_object_new(GMYTH_SOCKET_TYPE, NULL));
   382 
   383     gmyth_socket->mythtv_version = MYTHTV_VERSION_DEFAULT;
   384 
   385     gmyth_socket->mutex = g_mutex_new();
   386 
   387     return gmyth_socket;
   388 }
   389 
   390 /** Try to open an asynchronous connection to the MythTV backend.
   391  * 
   392  * @param fd 		Socket descriptor.
   393  * @param remote 	Remote address.
   394  * @param len 		Newly created socket length field.
   395  * @param timeout	Timeval argument with the time interval to timeout before closing.
   396  * @param err		Error message number.
   397  * @return Any numerical value below 0, if an error had been found.
   398  */
   399 static          gint
   400 gmyth_socket_try_connect(gint fd, struct sockaddr *remote, gint len,
   401                          struct timeval *timeout, gint * err)
   402 {
   403     /*
   404      * g_return_val_if_fail( timeout != NULL, 0 ); 
   405      */
   406     gint            saveflags,
   407                     ret,
   408                     back_err;
   409 
   410     fd_set          fd_w;
   411 
   412     saveflags = fcntl(fd, F_GETFL, 0);
   413     if (saveflags < 0) {
   414         gmyth_debug("[%s] Problems when getting socket flags on fcntl.\n",
   415                     __FUNCTION__);
   416         *err = errno;
   417         return -1;
   418     }
   419 
   420     /*
   421      * Set non blocking 
   422      */
   423     if (fcntl(fd, F_SETFL, saveflags | O_NONBLOCK) < 0) {
   424         gmyth_debug
   425             ("[%s] Problems when setting non-blocking using fcntl.\n",
   426              __FUNCTION__);
   427         *err = errno;
   428         return -1;
   429     }
   430 
   431     /*
   432      * This will return immediately 
   433      */
   434     *err = connect(fd, remote, len);
   435     back_err = errno;
   436 
   437     /*
   438      * restore flags 
   439      */
   440     if (fcntl(fd, F_SETFL, saveflags) < 0) {
   441         gmyth_debug
   442             ("[%s] Problems when trying to restore flags with fcntl.\n",
   443              __FUNCTION__);
   444         *err = errno;
   445         return -1;
   446     }
   447 
   448     /*
   449      * return unless the connection was successful or the connect is still 
   450      * in progress. 
   451      */
   452     if (*err < 0 && back_err != EINPROGRESS) {
   453         gmyth_debug
   454             ("[%s] Connection unsucessfully (it is not in progress).\n",
   455              __FUNCTION__);
   456         *err = errno;
   457         return -1;
   458     }
   459 
   460     FD_ZERO(&fd_w);
   461     FD_SET(fd, &fd_w);
   462 
   463     *err = select(FD_SETSIZE, NULL, &fd_w, NULL, timeout);
   464     if (*err < 0) {
   465         gmyth_debug("[%s] Connection unsucessfull (timed out).\n",
   466                     __FUNCTION__);
   467         *err = errno;
   468         return -1;
   469     }
   470 
   471     /*
   472      * 0 means it timeout out & no fds changed 
   473      */
   474     if (*err == 0) {
   475         gmyth_debug
   476             ("[%s] Connection unsucessfull [%d] - 0 means it timeout out & no fds changed\n",
   477              __FUNCTION__, *err);
   478         close(fd);
   479         *err = ETIMEDOUT;
   480         return -1;
   481     }
   482 
   483     /*
   484      * Get the return code from the connect 
   485      */
   486     len = sizeof(ret);
   487     *err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, (socklen_t *) & len);
   488 
   489     if (*err < 0) {
   490         gmyth_debug("[%s] Connection unsucessfull.\n", __FUNCTION__);
   491         *err = errno;
   492         return -1;
   493     }
   494 
   495     /*
   496      * ret=0 means success, otherwise it contains the errno 
   497      */
   498     if (ret) {
   499         gmyth_debug
   500             ("[%s] Connection unsucessfull - Couldn't connect to remote host!!!\n",
   501              __FUNCTION__);
   502         *err = ret;
   503         return -1;
   504     }
   505 
   506     *err = 0;
   507     return 0;
   508 }
   509 
   510 /** Connects to the backend.
   511  * 
   512  * @param gmyth_socket The GMythSocket instance.
   513  * @param hostname The backend hostname or IP address.
   514  * @param port The backend port.
   515  * @return TRUE if success, FALSE if error.
   516  */
   517 
   518 
   519 gboolean
   520 gmyth_socket_connect(GMythSocket * gmyth_socket,
   521                      const gchar * hostname, gint port)
   522 {
   523     return gmyth_socket_connect_with_timeout(gmyth_socket, hostname, port,
   524                                              30);
   525 }
   526 
   527 gboolean
   528 gmyth_socket_connect_with_timeout(GMythSocket * gmyth_socket,
   529                                   const gchar * hostname, gint port,
   530                                   guint timeout)
   531 {
   532     struct addrinfo *addr_info_data = NULL,
   533         *addr_info0 = NULL;
   534     struct linger   ling;
   535     gchar          *tmp_str;
   536     gint            ret_code = 0;   /* -1 */
   537 
   538     /*
   539      * FIXME: add as function parameter 
   540      */
   541     gint            err;
   542     gint            errno;
   543     gboolean        ret = TRUE;
   544 
   545     gmyth_debug("CONNECTING %s:%d", hostname, port);
   546 
   547     if (hostname == NULL)
   548         gmyth_debug("Invalid hostname parameter!\n");
   549 
   550     /*
   551      * store hostname and port number 
   552      */
   553     gmyth_debug("CONNECTING %s:%d", hostname, port);
   554 
   555     errno = gmyth_socket_toaddrinfo(hostname, port, &addr_info_data);
   556 
   557     g_return_val_if_fail(addr_info_data != NULL
   558                          && hostname != NULL, FALSE);
   559 
   560     /*
   561      * hack to avoid deleting the hostname when gmyth_socket->hostname ==
   562      * hostname 
   563      */
   564     tmp_str = gmyth_socket->hostname;
   565 
   566     gmyth_socket->hostname = g_strdup(hostname);
   567     gmyth_socket->port = port;
   568 
   569     g_free(tmp_str);
   570 
   571     for (addr_info0 = addr_info_data; addr_info0;
   572          addr_info0 = addr_info_data->ai_next) {
   573         /*
   574          * init socket descriptor 
   575          */
   576 
   577         g_debug ("FAMILY: %d, TYPE: %d, PROTOCOL: %d", 
   578                  addr_info0->ai_family,
   579                  addr_info0->ai_socktype,
   580                  addr_info0->ai_protocol);
   581         gmyth_socket->sd =
   582             socket(addr_info0->ai_family, addr_info0->ai_socktype,
   583                    addr_info0->ai_protocol);
   584 
   585         if (gmyth_socket->sd < 0)
   586             continue;
   587 
   588         struct timeval *timeout_val = g_new0(struct timeval, 1);
   589 
   590         if (timeout != 0) {
   591             timeout_val->tv_sec = timeout;
   592             timeout_val->tv_usec = 0;
   593         } else {
   594             timeout_val->tv_sec = 5;
   595             timeout_val->tv_usec = 100;
   596         }
   597 
   598         if (gmyth_socket_try_connect
   599             (gmyth_socket->sd, (struct sockaddr *) addr_info0->ai_addr,
   600              addr_info0->ai_addrlen, timeout_val, &ret_code) < 0) {
   601             gmyth_debug("[%s] Error connecting to backend!\n",
   602                         __FUNCTION__);
   603             if (ret_code == ETIMEDOUT)
   604                 gmyth_debug("[%s]\tBackend host unreachable!\n",
   605                             __FUNCTION__);
   606 
   607             close(gmyth_socket->sd);
   608             gmyth_socket->sd = -1;
   609             gmyth_debug("ERROR: %s\n", gai_strerror(ret_code));
   610             g_free(timeout_val);
   611             continue;
   612         }
   613 
   614         g_free(timeout_val);
   615 
   616         /*
   617          * only will be reached if none of the error above occurred 
   618          */
   619         break;
   620     }
   621 
   622     freeaddrinfo(addr_info_data);
   623     addr_info_data = NULL;
   624 
   625     if (gmyth_socket->sd_io_ch != NULL) {
   626         g_io_channel_unref(gmyth_socket->sd_io_ch);
   627         gmyth_socket->sd_io_ch = NULL;
   628     }
   629 
   630 
   631     memset(&ling, 0, sizeof(struct linger));
   632     ling.l_onoff = TRUE;
   633     ling.l_linger = 1;
   634 
   635     err =
   636         setsockopt(gmyth_socket->sd, SOL_SOCKET, SO_LINGER, &ling,
   637                    sizeof(struct linger));
   638 
   639     if (err < 0) {
   640         gmyth_debug("[%s] Setting connection unsucessfull.\n",
   641                     __FUNCTION__);
   642         err = errno;
   643         ret = FALSE;
   644         goto cleanup;
   645     }
   646 
   647     gmyth_socket->sd_io_ch = g_io_channel_unix_new(gmyth_socket->sd);
   648 
   649     g_io_channel_set_close_on_unref(gmyth_socket->sd_io_ch, TRUE);
   650     // g_io_channel_set_encoding (gmyth_socket->sd_io_ch, NULL, NULL );
   651 
   652     GIOFlags        flags = g_io_channel_get_flags(gmyth_socket->sd_io_ch);
   653 
   654     /*
   655      * unset the nonblock flag 
   656      */
   657     flags &= ~G_IO_FLAG_NONBLOCK;
   658     /*
   659      * unset the nonblocking stuff for some time, because GNUTLS doesn't
   660      * like that 
   661      */
   662     g_io_channel_set_flags(gmyth_socket->sd_io_ch, flags, NULL);
   663 
   664     ret = (ret_code == 0) ? TRUE : FALSE;
   665 
   666   cleanup:
   667     if (!ret)
   668         gmyth_debug("GMythSocket error - return code error!");
   669 
   670     return ret;
   671 }
   672 
   673 /** Gets the GIOChannel associated to the given GMythSocket.
   674  * 
   675  * @param gmyth_socket The GMythSocket instance.
   676  */
   677 GIOChannel     *
   678 gmyth_socket_get_io_channel(GMythSocket * gmyth_socket)
   679 {
   680     g_return_val_if_fail(gmyth_socket != NULL, NULL);
   681 
   682     return gmyth_socket->sd_io_ch;
   683 }
   684 
   685 /** Verifies if the socket is able to read.
   686  * 
   687  * @param gmyth_socket The GMythSocket instance.
   688  * @return TRUE if the socket is able to read, FALSE if not.
   689  */
   690 gboolean
   691 gmyth_socket_is_able_to_read(GMythSocket * gmyth_socket)
   692 {
   693     gboolean        ret = TRUE;
   694 
   695     /*
   696      * verify if the input (read) buffer is ready to receive data 
   697      */
   698     GIOCondition    io_cond =
   699         g_io_channel_get_buffer_condition(gmyth_socket->sd_io_ch);
   700 
   701     if ((io_cond & G_IO_IN) == 0) {
   702         gmyth_debug("[%s] IO channel is not able to send data!\n",
   703                     __FUNCTION__);
   704         ret = FALSE;
   705     }
   706 
   707     return ret;
   708 
   709 }
   710 
   711 /** Verifies if the socket is able to write.
   712  * 
   713  * @param gmyth_socket The GMythSocket instance.
   714  * @return TRUE if the socket is able to write, FALSE if not.
   715  */
   716 gboolean
   717 gmyth_socket_is_able_to_write(GMythSocket * gmyth_socket)
   718 {
   719     gboolean        ret = TRUE;
   720 
   721     /*
   722      * verify if the input (read) buffer is ready to receive data 
   723      */
   724     GIOCondition    io_cond =
   725         g_io_channel_get_buffer_condition(gmyth_socket->sd_io_ch);
   726 
   727     if (((io_cond & G_IO_OUT) == 0) || ((io_cond & G_IO_HUP) == 0)) {
   728         gmyth_debug("[%s] IO channel is not able to send data!\n",
   729                     __FUNCTION__);
   730         ret = FALSE;
   731     }
   732 
   733     return ret;
   734 
   735 }
   736 
   737 /** Sends a command to the backend.
   738  * 
   739  * @param gmyth_socket the GMythSocket instance.
   740  * @param command The string command to be sent.
   741  */
   742 gboolean
   743 gmyth_socket_send_command(GMythSocket * gmyth_socket, GString * command)
   744 {
   745     gboolean        ret = TRUE;
   746 
   747     GIOStatus       io_status = G_IO_STATUS_NORMAL;
   748 
   749     // GIOCondition io_cond;
   750     GError         *error = NULL;
   751 
   752     gchar          *buffer = NULL;
   753 
   754     gsize           bytes_written = 0;
   755 
   756     g_return_val_if_fail(gmyth_socket->sd_io_ch != NULL, FALSE);
   757 
   758     if (command == NULL || (command->len <= 0) || command->str == NULL) {
   759         gmyth_debug("[%s] Invalid NULL command parameter!\n",
   760                     __FUNCTION__);
   761         ret = FALSE;
   762         goto done;
   763     }
   764 
   765     g_mutex_lock(gmyth_socket->mutex);
   766     gmyth_debug("Sending command to backend: %s\n", command->str);
   767 
   768     buffer = g_strnfill(BUFLEN, ' ');
   769     g_snprintf(buffer, MYTH_PROTOCOL_FIELD_SIZE + 1, "%-8d", command->len);
   770 
   771     command = g_string_prepend(command, buffer);
   772 
   773     /*
   774      * write bytes to socket 
   775      */
   776     io_status =
   777         g_io_channel_write_chars(gmyth_socket->sd_io_ch, command->str,
   778                                  command->len, &bytes_written, &error);
   779 
   780 
   781     if ((io_status == G_IO_STATUS_ERROR) || (bytes_written <= 0)) {
   782         gmyth_debug("[%s] Error while writing to socket", __FUNCTION__);
   783         ret = FALSE;
   784     } else if (bytes_written < command->len) {
   785         gmyth_debug("[%s] Not all data was written socket", __FUNCTION__);
   786         ret = FALSE;
   787     }
   788 
   789     io_status = g_io_channel_flush(gmyth_socket->sd_io_ch, &error);
   790 
   791     if ((bytes_written != command->len)
   792         || (io_status == G_IO_STATUS_ERROR)) {
   793         gmyth_debug
   794             ("[%s] Some problem occurred when sending data to the socket\n",
   795              __FUNCTION__);
   796 
   797         ret = TRUE;
   798     }
   799 
   800     g_mutex_unlock(gmyth_socket->mutex);
   801   done:
   802     if (error != NULL) {
   803         gmyth_debug
   804             ("[%s] Error found reading data from IO channel: (%d, %s)\n",
   805              __FUNCTION__, error->code, error->message);
   806         ret = FALSE;
   807         g_error_free(error);
   808     }
   809 
   810     if (buffer != NULL)
   811         g_free(buffer);
   812 
   813     return ret;
   814 }
   815 
   816 /** Starts Mythtv protocol level connection. Checks Mythtv protocol version
   817  * supported by the backend and send the "ANN" command.
   818  * 
   819  * @param gmyth_socket the GMythSocket instance.
   820  * @param hostname_backend The backend hostname or IP address.
   821  * @param port The backend port to connect.
   822  * @param blocking_client A flag to choose between blocking and non-blocking
   823  * @param with_events	Sets the connection flag to receive events.
   824  * 										backend connection. 
   825  */
   826 static          gboolean
   827 gmyth_socket_connect_to_backend_and_events(GMythSocket * gmyth_socket,
   828                                            const gchar * hostname_backend,
   829                                            gint port,
   830                                            gboolean blocking_client,
   831                                            gboolean with_events)
   832 {
   833     if (!gmyth_socket_connect(gmyth_socket, hostname_backend, port)) {
   834         gmyth_debug("[%s] Could not open socket to backend machine [%s]\n",
   835                     __FUNCTION__, hostname_backend);
   836         return FALSE;
   837     }
   838 
   839     if (gmyth_socket_check_protocol_version(gmyth_socket)) {
   840         GString        *result;
   841         GString        *base_str = g_string_new("");
   842         GString        *hostname = NULL;
   843 
   844         hostname = gmyth_socket_get_local_hostname();
   845         if (hostname == NULL) {
   846             gmyth_debug
   847                 ("Hostname not available, setting to n800frontend\n");
   848             hostname = g_string_new("n800frontend");
   849         }
   850 
   851         g_string_printf(base_str, "ANN %s %s %u",
   852                         (blocking_client ? "Playback" : "Monitor"),
   853                         hostname->str, with_events);
   854 
   855         gmyth_socket_send_command(gmyth_socket, base_str);
   856         result = gmyth_socket_receive_response(gmyth_socket);
   857 
   858         if (result != NULL) {
   859             gmyth_debug("Response received from backend: %s", result->str);
   860             g_string_free(result, TRUE);
   861         }
   862 
   863         g_string_free(hostname, TRUE);
   864         g_string_free(base_str, TRUE);
   865 
   866         return TRUE;
   867     } else {
   868         gmyth_debug("[%s] GMythSocket could not connect to the backend",
   869                     __FUNCTION__);
   870         return FALSE;
   871     }
   872 }
   873 
   874 /** Starts Mythtv protocol level connection. Checks Mythtv protocol version
   875  * supported by the backend and send the "ANN" command.
   876  * 
   877  * @param gmyth_socket the GMythSocket instance.
   878  * @param hostname_backend The backend hostname or IP address.
   879  * @param port The backend port to connect.
   880  * @param blocking_client A flag to choose between blocking and non-blocking 
   881  */
   882 gboolean
   883 gmyth_socket_connect_to_backend(GMythSocket * gmyth_socket,
   884                                 const gchar * hostname_backend, gint port,
   885                                 gboolean blocking_client)
   886 {
   887     if (!gmyth_socket_connect_to_backend_and_events
   888         (gmyth_socket, hostname_backend, port, blocking_client, FALSE)) {
   889         gmyth_debug("Could not open socket to backend machine [%s]\n",
   890                     hostname_backend);
   891         return FALSE;
   892     }
   893 
   894     return TRUE;
   895 
   896 }
   897 
   898 /** Starts Mythtv protocol level connection. Checks Mythtv protocol version
   899  * supported by the backend and send the "ANN" command.
   900  * 
   901  * @param gmyth_socket the GMythSocket instance.
   902  * @param hostname_backend The backend hostname or IP address.
   903  * @param port The backend port to connect.
   904  * @param blocking_client A flag to choose between blocking and non-blocking 
   905  */
   906 gboolean
   907 gmyth_socket_connect_to_backend_events(GMythSocket * gmyth_socket,
   908                                        const gchar * hostname_backend,
   909                                        gint port, gboolean blocking_client)
   910 {
   911     if (!gmyth_socket_connect_to_backend_and_events
   912         (gmyth_socket, hostname_backend, port, blocking_client, TRUE)) {
   913         gmyth_debug
   914             ("Could not open socket to backend machine in order to receive events [%s]\n",
   915              hostname_backend);
   916         return FALSE;
   917     }
   918 
   919     return TRUE;
   920 }
   921 
   922 /** Closes the socket connection to the backend.
   923  * 
   924  * @param gmyth_socket The GMythSocket instance.
   925  */
   926 void
   927 gmyth_socket_close_connection(GMythSocket * gmyth_socket)
   928 {
   929     /*
   930      * if ( gmyth_socket->sd != -1 ) { close (gmyth_socket->sd);
   931      * gmyth_socket->sd = -1; } 
   932      */
   933 
   934     if (gmyth_socket->sd_io_ch != NULL) {
   935         g_io_channel_shutdown(gmyth_socket->sd_io_ch, TRUE, NULL);
   936         g_io_channel_unref(gmyth_socket->sd_io_ch);
   937         gmyth_socket->sd_io_ch = NULL;
   938         gmyth_socket->sd = -1;
   939     }
   940 
   941 }
   942 
   943 
   944 /** Try the MythTV version numbers, and get the version returned by
   945  * the possible REJECT message, in order to contruct a new
   946  * MythTV version request.
   947  * 
   948  * @param gmyth_socket The GMythSocket instance.
   949  * @param mythtv_version The Mythtv protocol version to be tested
   950  * 
   951  * @return The actual MythTV the client is connected to.
   952  */
   953 gint
   954 gmyth_socket_check_protocol_version_number(GMythSocket * gmyth_socket,
   955                                            gint mythtv_version)
   956 {
   957     GString        *response = NULL;
   958     GString        *payload = NULL;
   959     gboolean        res = TRUE;
   960     gint            mythtv_new_version = MYTHTV_CANNOT_NEGOTIATE_VERSION;
   961     guint           max_iterations = MYTHTV_MAX_VERSION_CHECKS;
   962 
   963     assert(gmyth_socket);
   964 
   965   try_new_version:
   966     payload = g_string_new("MYTH_PROTO_VERSION");
   967     g_string_append_printf(payload, " %d", mythtv_version);
   968 
   969     gmyth_socket_send_command(gmyth_socket, payload);
   970     response = gmyth_socket_receive_response(gmyth_socket);
   971 
   972     if (response == NULL) {
   973         gmyth_debug("[%s] Check protocol version error! Not answered!",
   974                     __FUNCTION__);
   975         res = FALSE;
   976         goto done;
   977     }
   978 
   979     res = g_str_has_prefix(response->str, "ACCEPT");
   980     if (!res) {
   981         gmyth_debug("[%s] Protocol version request error: %s",
   982                     __FUNCTION__, response->str);
   983         /*
   984          * get the version number returned by the REJECT message 
   985          */
   986         if ((res = g_str_has_prefix(response->str, "REJECT")) == TRUE) {
   987             gchar          *new_version = NULL;
   988 
   989             new_version = g_strrstr(response->str, "]");
   990             if (new_version != NULL) {
   991                 ++new_version;  /* skip ']' character */
   992                 if (new_version != NULL) {
   993                     gmyth_debug("[%s] got MythTV version = %s.\n",
   994                                 __FUNCTION__, new_version);
   995                     mythtv_version =
   996                         (gint) g_ascii_strtoull(new_version, NULL, 10);
   997                     /*
   998                      * do reconnection to the socket (socket is closed if
   999                      * the MythTV version was wrong) 
  1000                      */
  1001                     gmyth_socket_connect(gmyth_socket,
  1002                                          gmyth_socket->hostname,
  1003                                          gmyth_socket->port);
  1004                     new_version = NULL;
  1005                     if (--max_iterations > 0) {
  1006                         g_string_free(payload, TRUE);
  1007                         g_string_free(response, TRUE);
  1008                         goto try_new_version;
  1009                     } else
  1010                         goto done;
  1011                 }
  1012             }
  1013         }
  1014     }
  1015 
  1016     /*
  1017      * change the return value to a valid one 
  1018      */
  1019     if (res) {
  1020         mythtv_new_version = mythtv_version;
  1021         gmyth_socket->mythtv_version = mythtv_new_version;
  1022     }
  1023 
  1024   done:
  1025     g_string_free(payload, TRUE);
  1026     g_string_free(response, TRUE);
  1027 
  1028     return mythtv_new_version;
  1029 }
  1030 
  1031 /** Verifies if the Mythtv backend supported the GMyth supported version.
  1032  * 
  1033  * @param gmyth_socket The GMythSocket instance.
  1034  * @return TRUE if supports, FALSE if not.
  1035  */
  1036 gboolean
  1037 gmyth_socket_check_protocol_version(GMythSocket * gmyth_socket)
  1038 {
  1039     return ((gmyth_socket->mythtv_version =
  1040              gmyth_socket_check_protocol_version_number(gmyth_socket,
  1041                                                         MYTHTV_VERSION_DEFAULT))
  1042             != MYTHTV_CANNOT_NEGOTIATE_VERSION);
  1043 }
  1044 
  1045 /** Returns the Mythtv backend supported version.
  1046  * 
  1047  * @param gmyth_socket The GMythSocket instance.
  1048  * @return The actual MythTV version number.
  1049  */
  1050 gint
  1051 gmyth_socket_get_protocol_version(GMythSocket * gmyth_socket)
  1052 {
  1053     return gmyth_socket->mythtv_version;
  1054 }
  1055 
  1056 /** Receives a backend answer after a gmyth_socket_send_command_call ().
  1057  * 
  1058  * @param gmyth_socket The GMythSocket instance.
  1059  * @return The response received, or NULL if error or nothing was received.
  1060  */
  1061 GString        *
  1062 gmyth_socket_receive_response(GMythSocket * gmyth_socket)
  1063 {
  1064     GIOStatus       io_status = G_IO_STATUS_NORMAL;
  1065     GError         *error = NULL;
  1066     gchar          *buffer = NULL;
  1067 
  1068     GString        *str = NULL;
  1069 
  1070     gsize           bytes_read = 0;
  1071     gint            len = 0;
  1072 
  1073     if (gmyth_socket == NULL)
  1074         return NULL;
  1075 
  1076     GIOCondition    io_cond;
  1077 
  1078     /*
  1079      * verify if the input (read) buffer is ready to receive data
  1080      */
  1081     g_mutex_lock(gmyth_socket->mutex);
  1082 
  1083     buffer = g_strnfill(MYTH_PROTOCOL_FIELD_SIZE, ' ');
  1084     if (NULL == gmyth_socket->sd_io_ch) {
  1085         gmyth_socket_connect(gmyth_socket, gmyth_socket->hostname,
  1086                              gmyth_socket->port);
  1087     }
  1088 
  1089     io_cond = g_io_channel_get_buffer_condition(gmyth_socket->sd_io_ch);
  1090     /*
  1091      * if ( NULL == gmyth_socket->sd_io_ch->read_buf || ( NULL ==
  1092      * gmyth_socket->sd_io_ch->read_buf->str ) ) gmyth_socket->sd_io_ch =
  1093      * g_io_channel_unix_new( gmyth_socket->sd );
  1094      */
  1095 
  1096     if (gmyth_socket->sd_io_ch->is_readable /* && !( ( io_cond & G_IO_IN )
  1097                                              * == 0 ) */ )
  1098         io_status =
  1099             g_io_channel_read_chars(gmyth_socket->sd_io_ch, buffer,
  1100                                     MYTH_PROTOCOL_FIELD_SIZE, &bytes_read,
  1101                                     &error);
  1102     else
  1103         return g_string_new("");
  1104 
  1105     /*
  1106      * verify if the input (read) buffer is ready to receive data 
  1107      */
  1108     io_cond = g_io_channel_get_buffer_condition(gmyth_socket->sd_io_ch);
  1109 
  1110     // if ( ( io_cond & G_IO_IN ) == 0 ) 
  1111     // return NULL; 
  1112 
  1113     gmyth_debug("[%s] Bytes read = %d\n", __FUNCTION__, bytes_read);
  1114 
  1115     if ((io_status == G_IO_STATUS_ERROR) || (bytes_read <= 0)) {
  1116         gmyth_debug("[%s] Error in mythprotocol response from backend\n",
  1117                     __FUNCTION__);
  1118         str = NULL;
  1119         // return NULL;
  1120     } else if (buffer != NULL && strlen(buffer) > 0) {
  1121 
  1122         // io_status = g_io_channel_flush( gmyth_socket->sd_io_ch, &error
  1123         // );
  1124         /*
  1125          * verify if the input (read) buffer is ready to receive data 
  1126          */
  1127         // io_cond = g_io_channel_get_buffer_condition(
  1128         // gmyth_socket->sd_io_ch );
  1129 
  1130         // if ( ( io_cond & G_IO_IN ) != 0 ) {
  1131         // gchar *buffer_aux = NULL;
  1132 
  1133         /*
  1134          * removes trailing whitespace 
  1135          */
  1136         // buffer_aux = g_strstrip (buffer);
  1137         len = (gint) g_ascii_strtoull(g_strstrip(buffer), NULL, 10);
  1138 
  1139         g_free(buffer);
  1140 
  1141         /*
  1142          * if (buffer_aux != NULL) { g_free (buffer_aux); buffer_aux =
  1143          * NULL; } 
  1144          */
  1145 
  1146         buffer = g_new0(gchar, len + 1);
  1147 
  1148         bytes_read = 0;
  1149         if (!(gmyth_socket != NULL && gmyth_socket->sd_io_ch != NULL))
  1150             return NULL;
  1151 
  1152         if (gmyth_socket->sd_io_ch->is_readable)
  1153             io_status =
  1154                 g_io_channel_read_chars(gmyth_socket->sd_io_ch, buffer,
  1155                                         len, &bytes_read, &error);
  1156         else
  1157             return g_string_new("");
  1158 
  1159         buffer[bytes_read] = '\0';
  1160         // }
  1161     }
  1162 
  1163     g_mutex_unlock(gmyth_socket->mutex);
  1164     // g_static_rw_lock_reader_unlock (&rwlock);
  1165 
  1166     gmyth_debug("Response received from backend: ----- {%s}\n", buffer);
  1167     if ((bytes_read != len) || (io_status == G_IO_STATUS_ERROR))
  1168         str = NULL;
  1169     else
  1170         str = g_string_new(buffer);
  1171 
  1172     if (error != NULL) {
  1173         gmyth_debug
  1174             ("[%s] Error found receiving response from the IO channel: (%d, %s)\n",
  1175              __FUNCTION__, error->code, error->message);
  1176         str = NULL;
  1177         g_error_free(error);
  1178     }
  1179 
  1180     g_free(buffer);
  1181     return str;
  1182 }
  1183 
  1184 /** Format a Mythtv command from the str_list entries and send it to backend.
  1185  * 
  1186  * @param gmyth_socket The GMythSocket instance.
  1187  * @param str_list The string list to form the command
  1188  * @return TRUE if command was sent, FALSE if any error happens.
  1189  */
  1190 gboolean
  1191 gmyth_socket_write_stringlist(GMythSocket * gmyth_socket,
  1192                               GMythStringList * str_list)
  1193 {
  1194 
  1195     GList          *tmp_list = NULL;
  1196     GPtrArray      *ptr_array = NULL;
  1197     gchar          *str_array = NULL;
  1198 
  1199     g_mutex_lock(gmyth_socket->mutex);
  1200     // g_static_rw_lock_writer_lock (&rwlock);
  1201 
  1202     ptr_array = g_ptr_array_sized_new(g_list_length(str_list->glist));
  1203 
  1204     // FIXME: change this implementation!
  1205     tmp_list = str_list->glist;
  1206     for (; tmp_list; tmp_list = tmp_list->next) {
  1207         if (tmp_list->data != NULL) {
  1208             g_ptr_array_add(ptr_array, ((GString *) tmp_list->data)->str);
  1209         } else {
  1210             g_ptr_array_add(ptr_array, "");
  1211         }
  1212     }
  1213     g_ptr_array_add(ptr_array, NULL);   // g_str_joinv() needs a NULL
  1214     // terminated string
  1215 
  1216     str_array = g_strjoinv(MYTH_SEPARATOR, (gchar **) (ptr_array->pdata));
  1217 
  1218     g_mutex_unlock(gmyth_socket->mutex);
  1219     // g_static_rw_lock_writer_unlock (&rwlock);
  1220 
  1221     gmyth_debug("[%s] Sending socket request: %s\n", __FUNCTION__,
  1222                 str_array);
  1223 
  1224     // Sends message to backend 
  1225     // TODO: implement looping to send remaining data, and add timeout
  1226     // testing! 
  1227     GString        *command = g_string_new(str_array);
  1228 
  1229     gmyth_socket_send_command(gmyth_socket, command);
  1230 
  1231     g_string_free(command, TRUE);
  1232 
  1233     g_free(str_array);
  1234 
  1235     /*
  1236      * ptr_array is pointing to data inside str_list->glist 
  1237      */
  1238     g_ptr_array_free(ptr_array, TRUE);
  1239 
  1240     return TRUE;
  1241 }
  1242 
  1243 /*
  1244  * Receives a backend command response and split it into the given string
  1245  * list. @param gmyth_socket The GMythSocket instance. @param str_list
  1246  * the string list to be filled. @return The number of received strings. 
  1247  */
  1248 gint
  1249 gmyth_socket_read_stringlist(GMythSocket * gmyth_socket,
  1250                              GMythStringList * str_list)
  1251 {
  1252     GString        *response;
  1253     gint            i;
  1254 
  1255     gmyth_string_list_clear_all(str_list);
  1256 
  1257     response = gmyth_socket_receive_response(gmyth_socket);
  1258     if (response != NULL && response->str != NULL && response->len > 0) {
  1259         gchar         **str_array;
  1260 
  1261         g_mutex_lock(gmyth_socket->mutex);
  1262 
  1263         str_array = g_strsplit(response->str, MYTH_SEPARATOR, -1);
  1264 
  1265         for (i = 0; i < g_strv_length(str_array); i++) {
  1266             // if ( str_array[i] != NULL && strlen( str_array[i] ) > 0 )
  1267             gmyth_string_list_append_char_array(str_list, str_array[i]);
  1268         }
  1269 
  1270         g_mutex_unlock(gmyth_socket->mutex);
  1271         g_strfreev(str_array);
  1272     }
  1273 
  1274     g_string_free(response, TRUE);
  1275 
  1276     return gmyth_string_list_length(str_list);
  1277 }
  1278 
  1279 /** Formats a Mythtv protocol command based on str_list and sends it to
  1280  * the connected backend. The backend response is overwritten into str_list.
  1281  *
  1282  * @param gmyth_socket The GMythSocket instance.
  1283  * @param str_list The string list to be sent, and on which the answer 
  1284  * will be written.
  1285  * @return TRUE if command was sent and an answer was received, FALSE if any
  1286  * error happens.
  1287  */
  1288 gint
  1289 gmyth_socket_sendreceive_stringlist(GMythSocket * gmyth_socket,
  1290                                     GMythStringList * str_list)
  1291 {
  1292     gmyth_socket_write_stringlist(gmyth_socket, str_list);
  1293 
  1294     return gmyth_socket_read_stringlist(gmyth_socket, str_list);
  1295 }