gmyth/src/gmyth_context.c
author renatofilho
Thu Sep 28 15:41:06 2006 +0100 (2006-09-28)
branchtrunk
changeset 18 79f6da40f6e9
parent 1 gmyth/src/libgmyth/gmyth_context.c@ffdf467315ec
child 105 ba9bf90e7c4b
permissions -rw-r--r--
[svn r19] - splited libgmyth;
     1 /**
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_context.c
     5  * 
     6  * @brief <p> GMythContext class contains general attributes and functions
     7  * that express the connection state of each mythtvfrontend.
     8  *
     9  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    10  * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
    11  *
    12  *//*
    13  * 
    14  * This program is free software; you can redistribute it and/or modify
    15  * it under the terms of the GNU Lesser General Public License as published by
    16  * the Free Software Foundation; either version 2 of the License, or
    17  * (at your option) any later version.
    18  *
    19  * This program is distributed in the hope that it will be useful,
    20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    22  * GNU General Public License for more details.
    23  *
    24  * You should have received a copy of the GNU Lesser General Public License
    25  * along with this program; if not, write to the Free Software
    26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    27  */
    28 
    29 #include "gmyth_context.h"
    30 
    31 #include <arpa/inet.h>
    32 #include <sys/types.h>
    33 #include <sys/socket.h>
    34 #include <netdb.h>
    35 #include <errno.h>
    36 #include <stdlib.h>
    37 
    38 #include "gmyth_query.h"
    39 #include "gmyth_socket.h"
    40 
    41 static void gmyth_context_class_init          (GMythContextClass *klass);
    42 static void gmyth_context_init                (GMythContext *object);
    43 
    44 static void gmyth_context_dispose  (GObject *object);
    45 static void gmyth_context_finalize (GObject *object);
    46 
    47 
    48 G_DEFINE_TYPE(GMythContext, gmyth_context, G_TYPE_OBJECT)
    49 
    50 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    51 
    52 static GMythContext *gcontext = NULL; 
    53 
    54 static void
    55 gmyth_context_class_init (GMythContextClass *klass)
    56 {
    57 	GObjectClass *gobject_class;
    58 
    59 	gobject_class = (GObjectClass *) klass;
    60 
    61 	gobject_class->dispose  = gmyth_context_dispose;
    62 	gobject_class->finalize = gmyth_context_finalize;	
    63 }
    64 
    65 static void
    66 gmyth_context_init (GMythContext *gmyth_context)
    67 {
    68 
    69 }
    70 
    71 static void
    72 gmyth_context_dispose  (GObject *object)
    73 {
    74 	GMythContext *gmyth_context = GMYTH_CONTEXT(object);
    75 
    76 	if ( gmyth_context->gmyth_settings != NULL ) {
    77 		g_object_unref (gmyth_context->gmyth_settings);	
    78 		gmyth_context->gmyth_settings = NULL;
    79 	}
    80 
    81 	if ( gmyth_context->localhostname != NULL ) {
    82 		g_string_free ( gmyth_context->localhostname, TRUE );
    83 		gmyth_context->localhostname = NULL;
    84 	}
    85 
    86 	if (gmyth_context->server_socket != NULL) {
    87 		g_object_unref (gmyth_context->server_socket);
    88 		gmyth_context->server_socket = NULL;
    89 	}
    90 
    91 	G_OBJECT_CLASS (gmyth_context_parent_class)->dispose (object);
    92 }
    93 
    94 static void
    95 gmyth_context_finalize (GObject *object)
    96 {
    97 	g_signal_handlers_destroy (object);
    98 
    99 	G_OBJECT_CLASS (gmyth_context_parent_class)->finalize (object);
   100 }
   101 
   102 /** Gets the some important address translation info, 
   103  * from the client socket that will open a connection.
   104  *
   105  * @return gint error number
   106  */
   107 static gint
   108 myth_context_toaddrinfo( gchar *addr, gint port, struct addrinfo **addrInfo )
   109 {
   110 	struct addrinfo hints;
   111 	gchar *portStr = g_strnfill( 32, ' ' );
   112 	gint errorn = EADDRNOTAVAIL;
   113 
   114 	memset( &hints, 0, sizeof(hints) );
   115 	hints.ai_family = AF_INET;
   116 	hints.ai_socktype = SOCK_STREAM;
   117 
   118 	/* hints.ai_flags = AI_NUMERICHOST; */
   119 	if ( port != -1 )
   120 		sprintf(portStr, "%d", port);
   121 	else
   122 		portStr = NULL;
   123 
   124 	g_debug( "[%s] Address: %s, port: %s\n", __FUNCTION__, addr, portStr );
   125 	if ( ( errorn = getaddrinfo(addr, portStr, &hints, addrInfo) ) != 0 ) {
   126 		g_printerr( "[%s] Socket ERROR: %s\n", __FUNCTION__, gai_strerror(errorn) );
   127 	}
   128 
   129 	return errorn;
   130 
   131 }
   132 
   133 /** Initializes the GMythContext object. It reads local system information
   134  * load gmyth user settings and start connection to the database.
   135  * 
   136  * @return TRUE if initialization was successfull, 
   137  * FALSE if any error happens.
   138  */
   139 gboolean
   140 gmyth_context_initialize ()
   141 {
   142 	GString *localhost = NULL;
   143 
   144 	if (gcontext == NULL) {
   145 		gcontext = GMYTH_CONTEXT ( g_object_new (GMYTH_CONTEXT_TYPE, FALSE));
   146 	}
   147 
   148 	localhost = gmyth_socket_get_local_hostname( );
   149 
   150 	if (localhost==NULL || localhost->len <=0 ) {
   151 		g_warning ("[%s] Could not determine local hostname. Setting to 127.0.0.1", __FUNCTION__);
   152 		gcontext->localhostname = g_string_new ("127.0.0.1");
   153 	} else {
   154 		gcontext->localhostname = localhost;
   155 	}
   156 
   157 	if (gcontext->gmyth_settings) {
   158 		g_object_unref (gcontext->gmyth_settings);	
   159 		gcontext->gmyth_settings = NULL;
   160 	}
   161 
   162 	gcontext->gmyth_settings = gmyth_settings_new ();
   163 	if (!gmyth_settings_load (gcontext->gmyth_settings)) {
   164 		g_warning ("GMythContext: Settings file not opened!\n");	
   165 	} else {
   166 		g_debug ("GMythContext: Settings file loaded");
   167 	}
   168 
   169 	if (gcontext->server_socket != NULL) {
   170 		g_object_unref (gcontext->server_socket);
   171 		gcontext->server_socket = NULL;
   172 	}
   173 
   174 	GString *server_hostname = 
   175         gmyth_settings_get_backend_hostname(gcontext->gmyth_settings);
   176 	int server_port = gmyth_settings_get_backend_port(gcontext->gmyth_settings);
   177 
   178 	gcontext->server_socket = gmyth_socket_new ();
   179 	if (!gmyth_socket_connect_to_backend (gcontext->server_socket,
   180 				server_hostname->str, server_port, FALSE)) {
   181 		g_warning ("[%s] Socket connection to backend error!", __FUNCTION__);
   182 		g_object_unref (gcontext->server_socket);
   183 		gcontext->server_socket = NULL;
   184 		return FALSE;	
   185 	}
   186 
   187 	return TRUE;
   188 }
   189 
   190 /** Formats a Mythtv protocol command based on strlist and sends it to
   191  * the connected backend. The backend response is overwritten into strlist.
   192  * 
   193  * @param strlist the string list to be sent, 
   194  * and on which the answer will be written.
   195  * @return TRUE if command was sent and an answer was received, FALSE if any
   196  * error happens.
   197  */
   198 gboolean
   199 gmyth_context_send_receive_stringlist (GMythStringList *strlist)
   200 {
   201 	gint ok = -1;
   202 
   203 	if (!gcontext || !(gcontext->server_socket)) {
   204 		g_warning ("[%s] GMythContext not initialized", __FUNCTION__);
   205 		return FALSE;
   206 	}
   207 
   208 	//g_static_mutex_lock( &mutex );
   209 
   210 	ok = gmyth_socket_sendreceive_stringlist (gcontext->server_socket, strlist);
   211 
   212 	//g_static_mutex_unlock( &mutex );
   213 
   214 	if (!ok) {
   215 		g_warning ("Connection to backend server lost");
   216 	}
   217 
   218 	return (ok ? TRUE : FALSE);
   219 }
   220 
   221 /** Gets the GMythSettings object associated to this context.
   222  * 
   223  * @return The GMythSettings object currently valid or NULL if the settings
   224  * were not opened.
   225  */
   226 GMythSettings*
   227 gmyth_context_get_settings ()
   228 {
   229 	if (!gcontext) {
   230 		g_warning ("[%s] GMythContext not initialized\n", __FUNCTION__);
   231 		return NULL;
   232 	}
   233 
   234 	return gcontext->gmyth_settings;
   235 }
   236 
   237 /** Gets the machine local hostname.
   238  * 
   239  * @param hostname a valid GString object to be overwritten with the local
   240  * hostname.
   241  * @return true if the hostname was read, false if any error happened.
   242  */
   243 gboolean
   244 gmyth_context_get_local_hostname (GString *hostname)
   245 {
   246 	if (!hostname) {
   247 		g_warning ("[%s] Received null argument", __FUNCTION__);
   248 		return FALSE;
   249 	}
   250 
   251 	g_string_assign (hostname, gcontext->localhostname->str);
   252 
   253 	return TRUE;
   254 }
   255 
   256 /** Gets a setting information from the backend mysql database.
   257  * 
   258  * @param key The setting key to be retrieved.
   259  * @param host the hostname associated to the desired setting.
   260  * @param default_value the default setting value if could not query from
   261  * backend database.
   262  * @return The setting value loaded from database, or the given default value
   263  * if the query fails.
   264  */
   265 GString*
   266 gmyth_context_get_setting_onhost (GString *key, GString *host, GString *default_value)
   267 {
   268 	GString *query_str;
   269 
   270 	// TODO: Reuse msql query in gmyth_context
   271 	GMythQuery *gmyth_query = gmyth_query_new ();
   272 
   273 	if (gmyth_query_connect (gmyth_query)) {
   274 		MYSQL_RES *msql_res;
   275 		MYSQL_ROW msql_row;
   276 
   277 		query_str = g_string_new ("");
   278 		g_string_printf (query_str, "SELECT data FROM settings WHERE value = \"%s\" "
   279 				"AND hostname = \"%s\" ;", key->str, host->str);
   280 
   281 		msql_res = gmyth_query_process_statement (gmyth_query, query_str->str);
   282 		if (msql_res) {
   283 			msql_row = mysql_fetch_row (msql_res);
   284 			if (msql_row != NULL) {
   285 				return g_string_new (msql_row[0]);
   286 			}
   287 		}
   288 
   289 		g_object_unref (gmyth_query);
   290 	} else {
   291 		g_warning ("Database not open while trying to load setting: %s", key->str);
   292 	}
   293 
   294 
   295 	return default_value;
   296 }
   297 
   298 /** Verify if the context is currently connected to a backend.
   299  * 
   300  * @return true if connection was opened, false if not.
   301  */
   302 gboolean
   303 gmyth_context_check_connection ()
   304 {
   305 	// FIXME: Check this based on socket states
   306 	if (!gcontext) {
   307 		g_warning ("[%s] GMythContext not initialized", __FUNCTION__);
   308 		return FALSE;
   309 	}
   310 
   311 	return (gcontext->server_socket != NULL);
   312 }