1.1 --- a/branches/gmyth-0.1b/src/gmyth_socket.c Wed Feb 14 23:06:17 2007 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1082 +0,0 @@
1.4 -/**
1.5 - * GMyth Library
1.6 - *
1.7 - * @file gmyth/gmyth_socket.c
1.8 - *
1.9 - * @brief <p> MythTV socket implementation, according to the MythTV Project
1.10 - * (www.mythtv.org).
1.11 - *
1.12 - * This component provides basic socket functionalities to interact with
1.13 - * the Mythtv backend.
1.14 - * <p>
1.15 - *
1.16 - * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
1.17 - * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
1.18 - *
1.19 - *//*
1.20 - *
1.21 - * This program is free software; you can redistribute it and/or modify
1.22 - * it under the terms of the GNU Lesser General Public License as published by
1.23 - * the Free Software Foundation; either version 2 of the License, or
1.24 - * (at your option) any later version.
1.25 - *
1.26 - * This program is distributed in the hope that it will be useful,
1.27 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.28 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.29 - * GNU General Public License for more details.
1.30 - *
1.31 - * You should have received a copy of the GNU Lesser General Public License
1.32 - * along with this program; if not, write to the Free Software
1.33 - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.34 - */
1.35 -
1.36 -#ifdef HAVE_CONFIG_H
1.37 -#include "config.h"
1.38 -#endif
1.39 -
1.40 -#include "gmyth_socket.h"
1.41 -
1.42 -#include <glib.h>
1.43 -#include <glib/gprintf.h>
1.44 -
1.45 -#include <arpa/inet.h>
1.46 -#include <sys/types.h>
1.47 -#include <sys/socket.h>
1.48 -#include <sys/param.h>
1.49 -#include <netdb.h>
1.50 -#include <net/if.h>
1.51 -#include <errno.h>
1.52 -#include <stdlib.h>
1.53 -
1.54 -#include <unistd.h>
1.55 -#include <netinet/in.h>
1.56 -#include <fcntl.h>
1.57 -#include <signal.h>
1.58 -
1.59 -#include <sys/ioctl.h>
1.60 -
1.61 -#include "gmyth_stringlist.h"
1.62 -#include "gmyth_uri.h"
1.63 -#include "gmyth_debug.h"
1.64 -
1.65 -#define BUFLEN 512
1.66 -#define MYTH_SEPARATOR "[]:[]"
1.67 -#define MYTH_PROTOCOL_FIELD_SIZE 8
1.68 -
1.69 -/* max number of iterations */
1.70 -#define MYTHTV_MAX_VERSION_CHECKS 40
1.71 -
1.72 -// FIXME: put this in the right place
1.73 -#define MYTHTV_VERSION_DEFAULT 30
1.74 -
1.75 -static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
1.76 -
1.77 -static gchar* local_hostname = NULL;
1.78 -
1.79 -static void gmyth_socket_class_init (GMythSocketClass *klass);
1.80 -static void gmyth_socket_init (GMythSocket *object);
1.81 -
1.82 -static void gmyth_socket_dispose (GObject *object);
1.83 -static void gmyth_socket_finalize (GObject *object);
1.84 -
1.85 -G_DEFINE_TYPE(GMythSocket, gmyth_socket, G_TYPE_OBJECT)
1.86 -
1.87 -static void
1.88 -gmyth_socket_class_init (GMythSocketClass *klass)
1.89 -{
1.90 - GObjectClass *gobject_class;
1.91 -
1.92 - gobject_class = (GObjectClass *) klass;
1.93 -
1.94 - gobject_class->dispose = gmyth_socket_dispose;
1.95 - gobject_class->finalize = gmyth_socket_finalize;
1.96 -}
1.97 -
1.98 -static void
1.99 -gmyth_socket_init (GMythSocket *gmyth_socket)
1.100 -{
1.101 -
1.102 - /* gmyth_socket->local_hostname = NULL; */
1.103 -
1.104 -}
1.105 -
1.106 -/** Gets the some important address translation info, from the client socket
1.107 - * that will open a connection.
1.108 - *
1.109 - * @return gint that represents the error number from getaddrinfo().
1.110 - */
1.111 -static gint
1.112 -gmyth_socket_toaddrinfo (const gchar *addr, gint port, struct addrinfo **addrInfo )
1.113 -{
1.114 - struct addrinfo hints;
1.115 - gchar *portStr = NULL;
1.116 - gint errorn = EADDRNOTAVAIL;
1.117 -
1.118 - g_return_val_if_fail ( addr != NULL, -1 );
1.119 - g_debug ("Calling %s\n", __FUNCTION__);
1.120 -
1.121 - /* hints = g_malloc0 ( sizeof(struct addrinfo) ); */
1.122 - memset ( &hints, 0, sizeof(struct addrinfo) );
1.123 - hints.ai_family = AF_INET;
1.124 - hints.ai_socktype = SOCK_STREAM;
1.125 - /* hints.ai_flags = AI_NUMERICHOST; */
1.126 -
1.127 - if ( port != -1 )
1.128 - portStr = g_strdup_printf ( "%d", port );
1.129 - else
1.130 - portStr = NULL;
1.131 -
1.132 - gmyth_debug ("Getting name resolution for: %s, %d\n", addr, port);
1.133 -
1.134 - if ( ( errorn = getaddrinfo(addr, portStr, &hints, addrInfo) ) != 0 ) {
1.135 - g_printerr( "[%s] Socket ERROR: %s\n", __FUNCTION__, gai_strerror(errorn) );
1.136 - }
1.137 - g_free (portStr);
1.138 - /* g_free (hints); */
1.139 - return errorn;
1.140 -}
1.141 -
1.142 -static gint
1.143 -gmyth_socket_find_match_address_uri( GMythURI* uri, gchar *address ) {
1.144 -
1.145 - if ( g_ascii_strcasecmp( gmyth_uri_get_host( uri ), address ) == 0 ) {
1.146 - //g_printerr( "Found URI: %s !!!\n", rui_uri_getvalue(uri) );
1.147 - return 0;
1.148 - } else {
1.149 - return -1;
1.150 - }
1.151 -
1.152 -}
1.153 -
1.154 -static const gchar *PATH_PROC_NET_DEV = "/proc/net/dev";
1.155 -
1.156 -/** Gets the list of all local network interfaces (using the /proc/net/dev directory).
1.157 - *
1.158 - * @param current_connections A list with all the network interfaces are valid,
1.159 - * to be applied just like a filter.
1.160 - * @return List with all the local net interfaces.
1.161 - */
1.162 -static GList *
1.163 -gmyth_socket_get_local_addrs( GList *current_connections )
1.164 -{
1.165 -
1.166 - GList *local_addrs = NULL;
1.167 - FILE *fd;
1.168 - gint s;
1.169 - gchar buffer[256+1];
1.170 - gchar ifaddr[20+1];
1.171 - gchar *ifname;
1.172 - gchar *sep;
1.173 -
1.174 - s = socket(AF_INET, SOCK_DGRAM, 0);
1.175 - if (s < 0)
1.176 - return 0;
1.177 - fd = fopen(PATH_PROC_NET_DEV, "r");
1.178 - fgets(buffer, sizeof(buffer)-1, fd);
1.179 - fgets(buffer, sizeof(buffer)-1, fd);
1.180 - while (!feof(fd)) {
1.181 - ifname = buffer;
1.182 - sep;
1.183 - if (fgets(buffer, sizeof(buffer)-1, fd) == NULL)
1.184 - break;
1.185 - sep = strrchr(buffer, ':');
1.186 - if (sep)
1.187 - *sep = 0;
1.188 - while (*ifname == ' ')
1.189 - ifname++;
1.190 - struct ifreq req;
1.191 - strcpy(req.ifr_name, ifname);
1.192 - if (ioctl(s, SIOCGIFFLAGS, &req) < 0)
1.193 - continue;
1.194 - if (!(req.ifr_flags & IFF_UP))
1.195 - continue;
1.196 - if (req.ifr_flags & IFF_LOOPBACK)
1.197 - continue;
1.198 - if (ioctl(s, SIOCGIFADDR, &req) < 0)
1.199 - continue;
1.200 - g_strlcpy( ifaddr, inet_ntoa(((struct sockaddr_in*)&req.ifr_addr)->sin_addr), sizeof(struct ifaddr)-1 );
1.201 - local_addrs = g_list_append( local_addrs, g_strdup( ifaddr ) );
1.202 -
1.203 - gmyth_debug( "( from the /proc/net/dev) Interface name: %s, address: %s\n",
1.204 - ifname, ifaddr );
1.205 - }
1.206 - fclose(fd);
1.207 - close(s);
1.208 - return local_addrs;
1.209 -
1.210 -}
1.211 -
1.212 -
1.213 -/**
1.214 - * Get only the local addresses from the primary interface
1.215 - */
1.216 -static gchar *
1.217 -gmyth_socket_get_primary_addr()
1.218 -{
1.219 -
1.220 - gchar *if_eth0 = g_new0( gchar, sizeof(struct ifaddr)-1 );
1.221 - GList *if_tmp = NULL;
1.222 -
1.223 - GList *interfs = gmyth_socket_get_local_addrs( NULL );
1.224 -
1.225 - if ( interfs != NULL && ( g_list_length( interfs ) > 0 ) )
1.226 - {
1.227 - /* get the first occurrence (primary interface) */
1.228 - if_tmp = g_list_first( interfs );
1.229 -
1.230 - if ( if_tmp != NULL )
1.231 - g_strlcpy (if_eth0, (gchar *)if_tmp->data, sizeof(struct ifaddr)-1 );
1.232 -
1.233 - }
1.234 -
1.235 - if ( interfs != NULL )
1.236 - g_list_free( interfs );
1.237 -
1.238 - return if_eth0;
1.239 -}
1.240 -
1.241 -/** This function retrieves the local hostname of the
1.242 - * client machine.
1.243 - *
1.244 - * @return GString* get local hostname.
1.245 - */
1.246 -GString *
1.247 -gmyth_socket_get_local_hostname ()
1.248 -{
1.249 -
1.250 - char hname[50];
1.251 - gint res = gethostname (hname, 50);
1.252 -
1.253 - if (res == -1) {
1.254 - g_debug ("Error while getting hostname");
1.255 - return NULL;
1.256 - }
1.257 -
1.258 - return g_string_new (hname);
1.259 -
1.260 -#if 0
1.261 - GString *str = NULL;
1.262 -
1.263 - if ( local_hostname != NULL && strlen(local_hostname) > 0 )
1.264 - return g_string_new( local_hostname );
1.265 -
1.266 - gchar *localaddr = NULL;
1.267 - gboolean found_addr = FALSE;
1.268 - struct addrinfo* addr_info_data = NULL, *addr_info0 = NULL;
1.269 - struct sockaddr_in* sa = NULL;
1.270 - gchar localhostname[MAXHOSTNAMELEN];
1.271 -
1.272 -
1.273 - if (gethostname (localhostname, MAXHOSTNAMELEN) != 0 ) {
1.274 - gmyth_debug ( "Error on gethostname" );
1.275 - }
1.276 - localhostname[MAXHOSTNAMELEN-1] = 0;
1.277 -
1.278 - gint err = gmyth_socket_toaddrinfo (localhostname, -1, &addr_info_data );
1.279 -
1.280 - if ( err == EADDRNOTAVAIL )
1.281 - {
1.282 - g_warning( "[%s] Address (%s) not available. (reason = %d)\n", __FUNCTION__, localhostname, err );
1.283 - return str;
1.284 - }
1.285 -
1.286 - g_static_mutex_lock( &mutex );
1.287 -
1.288 - addr_info0 = addr_info_data;
1.289 -
1.290 - while( addr_info0 != NULL && addr_info0->ai_addr != NULL &&
1.291 - ( sa = (struct sockaddr_in*)addr_info0->ai_addr ) != NULL && !found_addr ) {
1.292 - localaddr = inet_ntoa( sa->sin_addr );
1.293 -
1.294 - if ( localaddr != NULL && ( g_strrstr( localaddr, "127" ) == NULL ) ) {
1.295 - str = g_string_new (localaddr);
1.296 - found_addr = TRUE;
1.297 - g_free (localaddr);
1.298 - break;
1.299 - }
1.300 -/*
1.301 - if (localaddr != NULL) {
1.302 - g_free (localaddr);
1.303 - localaddr = NULL;
1.304 - }
1.305 - */
1.306 -
1.307 - addr_info0 = addr_info0->ai_next;
1.308 - };
1.309 -
1.310 - freeaddrinfo (addr_info_data);
1.311 - addr_info_data = NULL;
1.312 -
1.313 - if ( found_addr == FALSE ) {
1.314 - gchar *prim_addr = gmyth_socket_get_primary_addr();
1.315 -
1.316 - if ( prim_addr != NULL ) {
1.317 - g_warning("[%s] Could not determine the local alphanumerical hostname. Setting to %s\n",
1.318 - __FUNCTION__, prim_addr );
1.319 -
1.320 - str = g_string_new (prim_addr);
1.321 - g_free (prim_addr);
1.322 - } else {
1.323 - str = g_string_new (localhostname);
1.324 - }
1.325 - }
1.326 -
1.327 - g_static_mutex_unlock (&mutex);
1.328 -
1.329 - if ( str != NULL && str->str != NULL )
1.330 - local_hostname = g_strdup( str->str );
1.331 -
1.332 - return str;
1.333 -#endif
1.334 -}
1.335 -
1.336 -static void
1.337 -gmyth_socket_dispose (GObject *object)
1.338 -{
1.339 - GMythSocket *gmyth_socket = GMYTH_SOCKET(object);
1.340 -
1.341 - /* disconnect socket */
1.342 - gmyth_socket_close_connection (gmyth_socket);
1.343 -
1.344 - g_free (gmyth_socket->hostname);
1.345 - gmyth_socket->hostname = NULL;
1.346 -
1.347 - g_free (local_hostname);
1.348 -
1.349 - local_hostname = NULL;
1.350 -
1.351 - G_OBJECT_CLASS (gmyth_socket_parent_class)->dispose (object);
1.352 -}
1.353 -
1.354 -static void
1.355 -gmyth_socket_finalize (GObject *object)
1.356 -{
1.357 - g_signal_handlers_destroy (object);
1.358 -
1.359 - G_OBJECT_CLASS (gmyth_socket_parent_class)->finalize (object);
1.360 -}
1.361 -
1.362 -/** Creates a new instance of GMythSocket.
1.363 - *
1.364 - * @return a new instance of GMythSocket.
1.365 - */
1.366 -GMythSocket*
1.367 -gmyth_socket_new ()
1.368 -{
1.369 - GMythSocket *gmyth_socket = GMYTH_SOCKET (g_object_new(GMYTH_SOCKET_TYPE, NULL));
1.370 -
1.371 - gmyth_socket->mythtv_version = MYTHTV_VERSION_DEFAULT;
1.372 -
1.373 - return gmyth_socket;
1.374 -}
1.375 -
1.376 -/** Try to open an asynchronous connection to the MythTV backend.
1.377 - *
1.378 - * @param fd Socket descriptor.
1.379 - * @param remote Remote address.
1.380 - * @param len Newly created socket length field.
1.381 - * @param timeout Timeval argument with the time interval to timeout before closing.
1.382 - * @param err Error message number.
1.383 - * @return Any numerical value below 0, if an error had been found.
1.384 - */
1.385 -static gint
1.386 -gmyth_socket_try_connect ( gint fd, struct sockaddr *remote, gint len,
1.387 - struct timeval *timeout, gint *err)
1.388 -{
1.389 - /*g_return_val_if_fail( timeout != NULL, 0 );*/
1.390 - gint saveflags, ret, back_err;
1.391 -
1.392 - fd_set fd_w;
1.393 -
1.394 - saveflags = fcntl( fd, F_GETFL, 0 );
1.395 - if( saveflags < 0 ) {
1.396 - g_warning( "[%s] Problems when getting socket flags on fcntl.\n", __FUNCTION__ );
1.397 - *err=errno;
1.398 - return -1;
1.399 - }
1.400 -
1.401 - /* Set non blocking */
1.402 - if( fcntl( fd, F_SETFL, saveflags | O_NONBLOCK ) < 0) {
1.403 - g_warning( "[%s] Problems when setting non-blocking using fcntl.\n", __FUNCTION__ );
1.404 - *err=errno;
1.405 - return -1;
1.406 - }
1.407 -
1.408 - /* This will return immediately */
1.409 - *err= connect ( fd, remote, len );
1.410 - back_err=errno;
1.411 -
1.412 - /* restore flags */
1.413 - if( fcntl( fd, F_SETFL, saveflags ) < 0) {
1.414 - g_warning( "[%s] Problems when trying to restore flags with fcntl.\n", __FUNCTION__ );
1.415 - *err=errno;
1.416 - return -1;
1.417 - }
1.418 -
1.419 - /* return unless the connection was successful or the connect is
1.420 - still in progress. */
1.421 - if( *err < 0 && back_err != EINPROGRESS) {
1.422 - g_warning( "[%s] Connection unsucessfully (it is not in progress).\n", __FUNCTION__ );
1.423 - *err = errno;
1.424 - return -1;
1.425 - }
1.426 -
1.427 - FD_ZERO( &fd_w );
1.428 - FD_SET( fd, &fd_w );
1.429 -
1.430 - *err = select( FD_SETSIZE, NULL, &fd_w, NULL, timeout);
1.431 - if ( *err < 0 ) {
1.432 - g_warning( "[%s] Connection unsucessfull (timed out).\n", __FUNCTION__ );
1.433 - *err=errno;
1.434 - return -1;
1.435 - }
1.436 -
1.437 - /* 0 means it timeout out & no fds changed */
1.438 - if(*err==0) {
1.439 - close(fd);
1.440 - *err=ETIMEDOUT;
1.441 - return -1;
1.442 - }
1.443 -
1.444 - /* Get the return code from the connect */
1.445 - len = sizeof( ret );
1.446 - *err=getsockopt( fd, SOL_SOCKET, SO_ERROR, &ret, (socklen_t *) &len);
1.447 -
1.448 - if( *err < 0 ) {
1.449 - g_warning( "[%s] Connection usnsucessfull.\n", __FUNCTION__ );
1.450 - *err=errno;
1.451 - return -1;
1.452 - }
1.453 -
1.454 - /* ret=0 means success, otherwise it contains the errno */
1.455 - if (ret) {
1.456 - *err=ret;
1.457 - return -1;
1.458 - }
1.459 -
1.460 - *err=0;
1.461 - return 0;
1.462 -}
1.463 -
1.464 -/** Connects to the backend.
1.465 - *
1.466 - * @param gmyth_socket The GMythSocket instance.
1.467 - * @param hostname The backend hostname or IP address.
1.468 - * @param port The backend port.
1.469 - * @return TRUE if success, FALSE if error.
1.470 - */
1.471 -
1.472 -
1.473 -gboolean
1.474 -gmyth_socket_connect (GMythSocket *gmyth_socket,
1.475 - const gchar *hostname, gint port)
1.476 -{
1.477 - return gmyth_socket_connect_with_timeout (gmyth_socket,
1.478 - hostname, port, 0);
1.479 -}
1.480 -
1.481 -gboolean
1.482 -gmyth_socket_connect_with_timeout (GMythSocket *gmyth_socket,
1.483 - const gchar *hostname, gint port, guint timeout)
1.484 -{
1.485 - struct addrinfo *addr_info_data = NULL, *addr_info0 = NULL;
1.486 - gint ret_code = -1;
1.487 - gint errno;
1.488 - gboolean ret = TRUE;
1.489 -
1.490 - gmyth_debug ("CONNECTING %s:%d", hostname, port);
1.491 -
1.492 - if ( hostname == NULL )
1.493 - gmyth_debug ( "Invalid hostname parameter!\n");
1.494 -
1.495 - /* store hostname and port number */
1.496 - if (gmyth_socket->hostname != NULL) {
1.497 - //g_free (gmyth_socket->hostname);
1.498 - gmyth_socket->hostname = NULL;
1.499 - }
1.500 -
1.501 - errno = gmyth_socket_toaddrinfo ( hostname, port, &addr_info_data );
1.502 -
1.503 - g_return_val_if_fail( addr_info_data != NULL && hostname != NULL, FALSE );
1.504 -
1.505 - gmyth_socket->hostname = g_strdup( hostname );
1.506 - gmyth_socket->port = port;
1.507 -
1.508 - for ( addr_info0 = addr_info_data; addr_info0; addr_info0 = addr_info_data->ai_next ) {
1.509 - /* init socket descriptor */
1.510 - gmyth_socket->sd = socket( addr_info0->ai_family, addr_info0->ai_socktype,
1.511 - addr_info0->ai_protocol );
1.512 -
1.513 - if ( gmyth_socket->sd < 0 )
1.514 - continue;
1.515 -
1.516 - struct timeval *timeout_val = g_new0 (struct timeval, 1);
1.517 - if (timeout != 0) {
1.518 - /*timeout_val = g_new0 (struct timeval, 1);*/
1.519 -
1.520 - timeout_val->tv_sec = timeout;
1.521 - timeout_val->tv_usec = 0;
1.522 - } else {
1.523 - timeout_val->tv_sec = 5;
1.524 - timeout_val->tv_usec = 100;
1.525 - }
1.526 -
1.527 - if (gmyth_socket_try_connect (gmyth_socket->sd, (struct sockaddr *)addr_info0->ai_addr,
1.528 - addr_info0->ai_addrlen, timeout_val, &ret_code ) < 0 )
1.529 - {
1.530 - g_printerr( "[%s] Error connecting to backend!\n", __FUNCTION__ );
1.531 - if (ret_code == ETIMEDOUT)
1.532 - g_printerr( "[%s]\tBackend host unreachable!\n", __FUNCTION__ );
1.533 -
1.534 - close (gmyth_socket->sd);
1.535 - gmyth_socket->sd = -1;
1.536 - g_printerr ("ERROR: %s\n", gai_strerror(ret_code));
1.537 - g_free (timeout_val);
1.538 - continue;
1.539 - }
1.540 -
1.541 - g_free (timeout_val);
1.542 -
1.543 - /* only will be reached if none of the error above occurred */
1.544 - break;
1.545 - }
1.546 -
1.547 - freeaddrinfo (addr_info_data);
1.548 - addr_info_data = NULL;
1.549 -
1.550 - if (gmyth_socket->sd_io_ch != NULL) {
1.551 - g_io_channel_unref (gmyth_socket->sd_io_ch);
1.552 - gmyth_socket->sd_io_ch = NULL;
1.553 - }
1.554 -
1.555 - gmyth_socket->sd_io_ch = g_io_channel_unix_new (gmyth_socket->sd);
1.556 -
1.557 - //GIOFlags flags = g_io_channel_get_flags (gmyth_socket->sd_io_ch);
1.558 - /* unset the nonblock flag */
1.559 - //flags &= ~G_IO_FLAG_NONBLOCK;
1.560 - /* unset the nonblocking stuff for some time, because GNUTLS doesn't like
1.561 - * that */
1.562 - //g_io_channel_set_flags (gmyth_socket->sd_io_ch, flags, NULL);
1.563 -
1.564 - ret = ( ret_code == 0 ) ? TRUE : FALSE ;
1.565 - return ret;
1.566 -}
1.567 -
1.568 -/** Gets the GIOChannel associated to the given GMythSocket.
1.569 - *
1.570 - * @param gmyth_socket The GMythSocket instance.
1.571 - */
1.572 -GIOChannel *
1.573 -gmyth_socket_get_io_channel( GMythSocket *gmyth_socket )
1.574 -{
1.575 - g_return_val_if_fail( gmyth_socket != NULL, NULL );
1.576 -
1.577 - return gmyth_socket->sd_io_ch;
1.578 -}
1.579 -
1.580 -/** Verifies if the socket is able to read.
1.581 - *
1.582 - * @param gmyth_socket The GMythSocket instance.
1.583 - * @return TRUE if the socket is able to read, FALSE if not.
1.584 - */
1.585 -gboolean
1.586 -gmyth_socket_is_able_to_read( GMythSocket *gmyth_socket )
1.587 -{
1.588 - gboolean ret = TRUE;
1.589 -
1.590 - /* verify if the input (read) buffer is ready to receive data */
1.591 - GIOCondition io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch );
1.592 -
1.593 - if ( ( io_cond & G_IO_IN ) == 0 ) {
1.594 - g_warning ("[%s] IO channel is not able to send data!\n", __FUNCTION__);
1.595 - ret = FALSE;
1.596 - }
1.597 -
1.598 - return ret;
1.599 -
1.600 -}
1.601 -
1.602 -/** Verifies if the socket is able to write.
1.603 - *
1.604 - * @param gmyth_socket The GMythSocket instance.
1.605 - * @return TRUE if the socket is able to write, FALSE if not.
1.606 - */
1.607 -gboolean
1.608 -gmyth_socket_is_able_to_write( GMythSocket *gmyth_socket )
1.609 -{
1.610 - gboolean ret = TRUE;
1.611 -
1.612 - /* verify if the input (read) buffer is ready to receive data */
1.613 - GIOCondition io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch );
1.614 -
1.615 - if ( ( ( io_cond & G_IO_OUT ) == 0 ) || ( ( io_cond & G_IO_HUP ) == 0 ) ) {
1.616 - g_warning ("[%s] IO channel is not able to send data!\n", __FUNCTION__);
1.617 - ret = FALSE;
1.618 - }
1.619 -
1.620 - return ret;
1.621 -
1.622 -}
1.623 -
1.624 -/** Sends a command to the backend.
1.625 - *
1.626 - * @param gmyth_socket the GMythSocket instance.
1.627 - * @param command The string command to be sent.
1.628 - */
1.629 -gboolean
1.630 -gmyth_socket_send_command(GMythSocket *gmyth_socket, GString *command)
1.631 -{
1.632 - gboolean ret = TRUE;
1.633 -
1.634 - GIOStatus io_status = G_IO_STATUS_NORMAL;
1.635 - //GIOCondition io_cond;
1.636 - GError* error = NULL;
1.637 -
1.638 -
1.639 - gchar *buffer = NULL;
1.640 -
1.641 - gsize bytes_written = 0;
1.642 -
1.643 - if( command == NULL || ( command->len <= 0 ) || command->str == NULL ) {
1.644 - g_warning ("[%s] Invalid NULL command parameter!\n", __FUNCTION__);
1.645 - ret = FALSE;
1.646 - goto done;
1.647 - }
1.648 -
1.649 - //g_static_mutex_lock( &mutex );
1.650 - gmyth_debug ("Sending command to backend: %s\n", command->str);
1.651 -
1.652 - buffer = g_strnfill( BUFLEN, ' ' );
1.653 - g_snprintf( buffer, MYTH_PROTOCOL_FIELD_SIZE+1, "%-8d", command->len);
1.654 -
1.655 - command = g_string_prepend(command, buffer);
1.656 -
1.657 - /* write bytes to socket */
1.658 - io_status = g_io_channel_write_chars( gmyth_socket->sd_io_ch, command->str,
1.659 - command->len, &bytes_written, &error );
1.660 -
1.661 -
1.662 - if( (io_status == G_IO_STATUS_ERROR) || ( bytes_written <= 0 ) ) {
1.663 - g_warning ("[%s] Error while writing to socket", __FUNCTION__);
1.664 - ret = FALSE;
1.665 - } else if ( bytes_written < command->len ) {
1.666 - g_warning ("[%s] Not all data was written socket", __FUNCTION__);
1.667 - ret = FALSE;
1.668 - }
1.669 -
1.670 - io_status = g_io_channel_flush( gmyth_socket->sd_io_ch, &error );
1.671 -
1.672 - if ( ( bytes_written != command->len ) || ( io_status == G_IO_STATUS_ERROR ) )
1.673 - {
1.674 - g_warning ("[%s] Some problem occurred when sending data to the socket\n", __FUNCTION__);
1.675 -
1.676 - ret = TRUE;
1.677 - }
1.678 -
1.679 - //g_static_mutex_unlock( &mutex );
1.680 -done:
1.681 - if ( error != NULL ) {
1.682 - g_printerr( "[%s] Error found reading data from IO channel: (%d, %s)\n", __FUNCTION__, error->code, error->message );
1.683 - ret = FALSE;
1.684 - g_error_free( error );
1.685 - }
1.686 -
1.687 - if ( buffer!= NULL )
1.688 - g_free( buffer );
1.689 -
1.690 - return ret;
1.691 -}
1.692 -
1.693 -/** Starts Mythtv protocol level connection. Checks Mythtv protocol version
1.694 - * supported by the backend and send the "ANN" command.
1.695 - *
1.696 - * @param gmyth_socket the GMythSocket instance.
1.697 - * @param hostname_backend The backend hostname or IP address.
1.698 - * @param port The backend port to connect.
1.699 - * @param blocking_client A flag to choose between blocking and non-blocking
1.700 - * @param with_events Sets the connection flag to receive events.
1.701 - * backend connection.
1.702 - */
1.703 -static gboolean
1.704 -gmyth_socket_connect_to_backend_and_events (GMythSocket *gmyth_socket,
1.705 - const gchar *hostname_backend, gint port, gboolean blocking_client,
1.706 - gboolean with_events)
1.707 -{
1.708 - if (!gmyth_socket_connect (gmyth_socket, hostname_backend, port)) {
1.709 - g_warning ("[%s] Could not open socket to backend machine [%s]\n", __FUNCTION__,
1.710 - hostname_backend );
1.711 - return FALSE;
1.712 - }
1.713 -
1.714 - if ( gmyth_socket_check_protocol_version (gmyth_socket) ) {
1.715 -
1.716 - GString *result;
1.717 - GString *base_str = g_string_new("");
1.718 - GString *hostname = NULL;
1.719 -
1.720 - hostname = gmyth_socket_get_local_hostname();
1.721 - if (hostname == NULL) {
1.722 - g_debug ("Hostname not available, setting to n800frontend\n");
1.723 - hostname = g_strdup ("n800frontend");
1.724 - }
1.725 -
1.726 - g_string_printf(base_str, "ANN %s %s %u",
1.727 - (blocking_client ? "Playback" : "Monitor"),
1.728 - hostname->str, with_events);
1.729 -
1.730 - gmyth_socket_send_command (gmyth_socket, base_str);
1.731 - result = gmyth_socket_receive_response (gmyth_socket);
1.732 -
1.733 - if (result != NULL) {
1.734 - gmyth_debug ("Response received from backend: %s", result->str);
1.735 - g_string_free (result, TRUE);
1.736 - }
1.737 -
1.738 - g_string_free (hostname, TRUE);
1.739 - g_string_free (base_str, TRUE);
1.740 -
1.741 - return TRUE;
1.742 - } else {
1.743 - g_warning ("[%s] GMythSocket could not connect to the backend", __FUNCTION__);
1.744 - return FALSE;
1.745 - }
1.746 -}
1.747 -
1.748 -/** Starts Mythtv protocol level connection. Checks Mythtv protocol version
1.749 - * supported by the backend and send the "ANN" command.
1.750 - *
1.751 - * @param gmyth_socket the GMythSocket instance.
1.752 - * @param hostname_backend The backend hostname or IP address.
1.753 - * @param port The backend port to connect.
1.754 - * @param blocking_client A flag to choose between blocking and non-blocking
1.755 - */
1.756 -gboolean
1.757 -gmyth_socket_connect_to_backend (GMythSocket *gmyth_socket,
1.758 - const gchar *hostname_backend, gint port, gboolean blocking_client)
1.759 -{
1.760 - if (!gmyth_socket_connect_to_backend_and_events ( gmyth_socket, hostname_backend, port,
1.761 - blocking_client, FALSE) ) {
1.762 - gmyth_debug ("Could not open socket to backend machine [%s]\n",
1.763 - hostname_backend );
1.764 - return FALSE;
1.765 - }
1.766 -
1.767 - return TRUE;
1.768 -
1.769 -}
1.770 -
1.771 -/** Starts Mythtv protocol level connection. Checks Mythtv protocol version
1.772 - * supported by the backend and send the "ANN" command.
1.773 - *
1.774 - * @param gmyth_socket the GMythSocket instance.
1.775 - * @param hostname_backend The backend hostname or IP address.
1.776 - * @param port The backend port to connect.
1.777 - * @param blocking_client A flag to choose between blocking and non-blocking
1.778 - */
1.779 -gboolean
1.780 -gmyth_socket_connect_to_backend_events (GMythSocket *gmyth_socket,
1.781 - const gchar *hostname_backend, gint port, gboolean blocking_client)
1.782 -{
1.783 - if (!gmyth_socket_connect_to_backend_and_events ( gmyth_socket, hostname_backend, port,
1.784 - blocking_client, TRUE) ) {
1.785 - gmyth_debug ("Could not open socket to backend machine in order to receive events [%s]\n",
1.786 - hostname_backend );
1.787 - return FALSE;
1.788 - }
1.789 -
1.790 - return TRUE;
1.791 -}
1.792 -
1.793 -/** Closes the socket connection to the backend.
1.794 - *
1.795 - * @param gmyth_socket The GMythSocket instance.
1.796 - */
1.797 -void
1.798 -gmyth_socket_close_connection (GMythSocket *gmyth_socket)
1.799 -{
1.800 - close (gmyth_socket->sd);
1.801 - gmyth_socket->sd = -1;
1.802 -
1.803 - if (gmyth_socket->sd_io_ch != NULL) {
1.804 - g_io_channel_unref (gmyth_socket->sd_io_ch);
1.805 - gmyth_socket->sd_io_ch = NULL;
1.806 - }
1.807 -}
1.808 -
1.809 -
1.810 -/** Try the MythTV version numbers, and get the version returned by
1.811 - * the possible REJECT message, in order to contruct a new
1.812 - * MythTV version request.
1.813 - *
1.814 - * @param gmyth_socket The GMythSocket instance.
1.815 - * @param mythtv_version The Mythtv protocol version to be tested
1.816 - *
1.817 - * @return The actual MythTV the client is connected to.
1.818 - */
1.819 -gint
1.820 -gmyth_socket_check_protocol_version_number (GMythSocket *gmyth_socket, gint mythtv_version)
1.821 -{
1.822 - GString *response = NULL;
1.823 - GString *payload = NULL;
1.824 - gboolean res = TRUE;
1.825 - gint mythtv_new_version = MYTHTV_CANNOT_NEGOTIATE_VERSION;
1.826 - guint max_iterations = MYTHTV_MAX_VERSION_CHECKS;
1.827 -
1.828 -try_new_version:
1.829 - payload = g_string_new ("MYTH_PROTO_VERSION");
1.830 - g_string_append_printf( payload, " %d", mythtv_version );
1.831 -
1.832 - gmyth_socket_send_command(gmyth_socket, payload);
1.833 - response = gmyth_socket_receive_response(gmyth_socket);
1.834 -
1.835 - if (response == NULL) {
1.836 - g_warning ("[%s] Check protocol version error! Not answered!", __FUNCTION__);
1.837 - res = FALSE;
1.838 - goto done;
1.839 - }
1.840 -
1.841 - res = g_str_has_prefix (response->str, "ACCEPT");
1.842 - if (!res) {
1.843 - g_warning ("[%s] Protocol version request error: %s", __FUNCTION__, response->str);
1.844 - /* get the version number returned by the REJECT message */
1.845 - if ( ( res = g_str_has_prefix (response->str, "REJECT") ) == TRUE ) {
1.846 - gchar *new_version = NULL;
1.847 - new_version = g_strrstr( response->str, "]" );
1.848 - if (new_version!=NULL) {
1.849 - ++new_version; /* skip ']' character */
1.850 - if ( new_version != NULL ) {
1.851 - gmyth_debug ( "[%s] got MythTV version = %s.\n", __FUNCTION__, new_version );
1.852 - mythtv_version = (gint)g_ascii_strtoull (new_version, NULL, 10 );
1.853 - /* do reconnection to the socket (socket is closed if the MythTV version was wrong) */
1.854 - gmyth_socket_connect( gmyth_socket, gmyth_socket->hostname, gmyth_socket->port );
1.855 - new_version =NULL;
1.856 - if ( --max_iterations > 0 )
1.857 - goto try_new_version;
1.858 - else
1.859 - goto done;
1.860 - }
1.861 - }
1.862 - }
1.863 - }
1.864 -
1.865 - /* change the return value to a valid one */
1.866 - if ( res ) {
1.867 - mythtv_new_version = mythtv_version;
1.868 - gmyth_socket->mythtv_version = mythtv_new_version;
1.869 - }
1.870 -
1.871 -done:
1.872 - if ( payload != NULL )
1.873 - g_string_free (payload, TRUE);
1.874 - if ( response != NULL )
1.875 - g_string_free (response, TRUE);
1.876 -
1.877 - return mythtv_new_version;
1.878 -}
1.879 -
1.880 -/** Verifies if the Mythtv backend supported the GMyth supported version.
1.881 - *
1.882 - * @param gmyth_socket The GMythSocket instance.
1.883 - * @return TRUE if supports, FALSE if not.
1.884 - */
1.885 -gboolean
1.886 -gmyth_socket_check_protocol_version (GMythSocket *gmyth_socket)
1.887 -{
1.888 - return ( ( gmyth_socket->mythtv_version =
1.889 - gmyth_socket_check_protocol_version_number ( gmyth_socket,
1.890 - MYTHTV_VERSION_DEFAULT ) ) != MYTHTV_CANNOT_NEGOTIATE_VERSION );
1.891 -}
1.892 -
1.893 -/** Returns the Mythtv backend supported version.
1.894 - *
1.895 - * @param gmyth_socket The GMythSocket instance.
1.896 - * @return The actual MythTV version number.
1.897 - */
1.898 -gint
1.899 -gmyth_socket_get_protocol_version (GMythSocket *gmyth_socket)
1.900 -{
1.901 - return gmyth_socket->mythtv_version;
1.902 -}
1.903 -
1.904 -/** Receives a backend answer after a gmyth_socket_send_command_call ().
1.905 - *
1.906 - * @param gmyth_socket The GMythSocket instance.
1.907 - * @return The response received, or NULL if error or nothing was received.
1.908 - */
1.909 -GString*
1.910 -gmyth_socket_receive_response(GMythSocket *gmyth_socket)
1.911 -{
1.912 - GIOStatus io_status = G_IO_STATUS_NORMAL;
1.913 - GError* error = NULL;
1.914 - gchar *buffer;
1.915 -
1.916 - GString *str = NULL;
1.917 -
1.918 - gsize bytes_read = 0;
1.919 - gint len = 0;
1.920 - GIOCondition io_cond = g_io_channel_get_buffer_condition (gmyth_socket->sd_io_ch);
1.921 -
1.922 - g_return_val_if_fail( gmyth_socket != NULL, NULL );
1.923 -
1.924 - /* verify if the input (read) buffer is ready to receive data */
1.925 -
1.926 - //g_static_mutex_lock( &mutex );
1.927 -
1.928 - //buffer = g_new0 (gchar, MYTH_PROTOCOL_FIELD_SIZE);
1.929 - buffer = g_strnfill (MYTH_PROTOCOL_FIELD_SIZE, ' ');
1.930 - io_status = g_io_channel_read_chars (gmyth_socket->sd_io_ch, buffer, MYTH_PROTOCOL_FIELD_SIZE, &bytes_read, &error);
1.931 -
1.932 - /* verify if the input (read) buffer is ready to receive data */
1.933 - io_cond = g_io_channel_get_buffer_condition (gmyth_socket->sd_io_ch);
1.934 -
1.935 - gmyth_debug ( "[%s] Bytes read = %d\n", __FUNCTION__, bytes_read );
1.936 -
1.937 - if( (io_status == G_IO_STATUS_ERROR) || (bytes_read <= 0) ) {
1.938 - g_warning ("[%s] Error in mythprotocol response from backend\n", __FUNCTION__);
1.939 - str = NULL;
1.940 - //return NULL;
1.941 - } else {
1.942 -
1.943 - io_status = g_io_channel_flush( gmyth_socket->sd_io_ch, &error );
1.944 - /* verify if the input (read) buffer is ready to receive data */
1.945 - io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch );
1.946 -
1.947 - //if ( ( io_cond & G_IO_IN ) != 0 ) {
1.948 - //gchar *buffer_aux = NULL;
1.949 -
1.950 - /* removes trailing whitespace */
1.951 - //buffer_aux = g_strstrip (buffer);
1.952 - len = (gint)g_ascii_strtoull ( g_strstrip (buffer), NULL, 10 );
1.953 -
1.954 - if (buffer != NULL) {
1.955 - g_free (buffer);
1.956 - buffer = NULL;
1.957 - }
1.958 -
1.959 - /*
1.960 - if (buffer_aux != NULL) {
1.961 - g_free (buffer_aux);
1.962 - buffer_aux = NULL;
1.963 - }
1.964 - */
1.965 -
1.966 - buffer = g_new0 (gchar, len+1);
1.967 -
1.968 - bytes_read = 0;
1.969 - io_status = g_io_channel_read_chars( gmyth_socket->sd_io_ch, buffer, len, &bytes_read, &error);
1.970 - buffer[bytes_read] = '\0';
1.971 - //}
1.972 - }
1.973 -
1.974 - //g_static_mutex_unlock( &mutex );
1.975 -
1.976 - gmyth_debug ("Response received from backend: {%s}\n", buffer);
1.977 -
1.978 - if ( ( bytes_read != len ) || ( io_status == G_IO_STATUS_ERROR ) )
1.979 - str = NULL;
1.980 - else
1.981 - str = g_string_new (buffer);
1.982 -
1.983 - if ( error != NULL ) {
1.984 - g_printerr( "[%s] Error found receiving response from the IO channel: (%d, %s)\n", __FUNCTION__, error->code, error->message );
1.985 - str = NULL;
1.986 - g_error_free (error);
1.987 - }
1.988 -
1.989 - g_free (buffer);
1.990 - return str;
1.991 -}
1.992 -
1.993 -/** Format a Mythtv command from the str_list entries and send it to backend.
1.994 - *
1.995 - * @param gmyth_socket The GMythSocket instance.
1.996 - * @param str_list The string list to form the command
1.997 - * @return TRUE if command was sent, FALSE if any error happens.
1.998 - */
1.999 -gboolean
1.1000 -gmyth_socket_write_stringlist(GMythSocket *gmyth_socket, GMythStringList* str_list)
1.1001 -{
1.1002 -
1.1003 - GList *tmp_list = NULL;
1.1004 - GPtrArray *ptr_array = NULL;
1.1005 - gchar *str_array = NULL;
1.1006 -
1.1007 - g_static_mutex_lock( &mutex );
1.1008 -
1.1009 - ptr_array = g_ptr_array_sized_new (g_list_length(str_list->glist));
1.1010 -
1.1011 - // FIXME: change this implementation!
1.1012 - tmp_list = str_list->glist;
1.1013 - for(; tmp_list; tmp_list = tmp_list->next) {
1.1014 - if ( tmp_list->data != NULL ) {
1.1015 - g_ptr_array_add(ptr_array, ((GString*)tmp_list->data)->str);
1.1016 - } else {
1.1017 - g_ptr_array_add (ptr_array, "");
1.1018 - }
1.1019 - }
1.1020 - g_ptr_array_add(ptr_array, NULL); // g_str_joinv() needs a NULL terminated string
1.1021 -
1.1022 - str_array = g_strjoinv (MYTH_SEPARATOR, (gchar **) (ptr_array->pdata));
1.1023 -
1.1024 - g_static_mutex_unlock( &mutex );
1.1025 -
1.1026 - gmyth_debug ( "[%s] Sending socket request: %s\n", __FUNCTION__, str_array );
1.1027 -
1.1028 - // Sends message to backend
1.1029 - // TODO: implement looping to send remaining data, and add timeout testing!
1.1030 - GString *command = g_string_new(str_array);
1.1031 - gmyth_socket_send_command(gmyth_socket, command);
1.1032 - g_string_free (command, TRUE);
1.1033 -
1.1034 - g_free (str_array);
1.1035 - g_ptr_array_free (ptr_array, TRUE);
1.1036 -
1.1037 - return TRUE;
1.1038 -}
1.1039 -
1.1040 -/* Receives a backend command response and split it into the given string list.
1.1041 - *
1.1042 - * @param gmyth_socket The GMythSocket instance.
1.1043 - * @param str_list the string list to be filled.
1.1044 - * @return The number of received strings.
1.1045 - */
1.1046 -gint
1.1047 -gmyth_socket_read_stringlist (GMythSocket *gmyth_socket, GMythStringList* str_list)
1.1048 -{
1.1049 - GString *response;
1.1050 - gchar **str_array;
1.1051 - gint i;
1.1052 -
1.1053 - response = gmyth_socket_receive_response(gmyth_socket);
1.1054 - g_static_mutex_lock( &mutex );
1.1055 -
1.1056 - gmyth_string_list_clear_all (str_list);
1.1057 - str_array = g_strsplit (response->str, MYTH_SEPARATOR, -1);
1.1058 -
1.1059 - for (i=0; i< g_strv_length (str_array); i++) {
1.1060 - gmyth_string_list_append_char_array (str_list, str_array[i] );
1.1061 - }
1.1062 - g_static_mutex_unlock( &mutex );
1.1063 -
1.1064 - g_string_free (response, TRUE);
1.1065 - g_strfreev (str_array);
1.1066 -
1.1067 - return gmyth_string_list_length (str_list);
1.1068 -}
1.1069 -
1.1070 -/** Formats a Mythtv protocol command based on str_list and sends it to
1.1071 - * the connected backend. The backend response is overwritten into str_list.
1.1072 - *
1.1073 - * @param gmyth_socket The GMythSocket instance.
1.1074 - * @param str_list The string list to be sent, and on which the answer
1.1075 - * will be written.
1.1076 - * @return TRUE if command was sent and an answer was received, FALSE if any
1.1077 - * error happens.
1.1078 - */
1.1079 -gint
1.1080 -gmyth_socket_sendreceive_stringlist (GMythSocket *gmyth_socket, GMythStringList *str_list)
1.1081 -{
1.1082 - gmyth_socket_write_stringlist (gmyth_socket, str_list);
1.1083 -
1.1084 - return gmyth_socket_read_stringlist (gmyth_socket, str_list);
1.1085 -}