gmyth-upnp/src/gmyth_upnp.c
author melunko
Wed Apr 11 21:20:44 2007 +0100 (2007-04-11)
branchtrunk
changeset 526 c65fa0ad8e5a
parent 250 ac3ca128dbca
child 696 7afeec40ed62
permissions -rw-r--r--
[svn r531] Some fixes in the scheduling
melunko@250
     1
/**
melunko@250
     2
 * GMyth Library
melunko@250
     3
 *
melunko@250
     4
 * @file gmyth/gmyth_upnp.c
melunko@250
     5
 * 
melunko@250
     6
 * @brief <p> GMythUPnP allows that a MythTV frontend discovers a 
melunko@250
     7
 * MythTV backend, using the UPnP architecture.
melunko@250
     8
 *
melunko@250
     9
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
melunko@250
    10
 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
melunko@250
    11
 *
melunko@250
    12
 *//*
melunko@250
    13
 * 
melunko@250
    14
 * This program is free software; you can redistribute it and/or modify
melunko@250
    15
 * it under the terms of the GNU Lesser General Public License as published by
melunko@250
    16
 * the Free Software Foundation; either version 2 of the License, or
melunko@250
    17
 * (at your option) any later version.
melunko@250
    18
 *
melunko@250
    19
 * This program is distributed in the hope that it will be useful,
melunko@250
    20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
melunko@250
    21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
melunko@250
    22
 * GNU General Public License for more details.
melunko@250
    23
 *
melunko@250
    24
 * You should have received a copy of the GNU Lesser General Public License
melunko@250
    25
 * along with this program; if not, write to the Free Software
melunko@250
    26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
melunko@250
    27
 *   
melunko@250
    28
 */
melunko@250
    29
melunko@250
    30
#ifdef HAVE_CONFIG_H
melunko@250
    31
#include "config.h"
melunko@250
    32
#endif
melunko@250
    33
melunko@250
    34
#include "gmyth_upnp.h"
melunko@250
    35
melunko@250
    36
#include <arpa/inet.h>
melunko@250
    37
#include <sys/types.h>
melunko@250
    38
#include <sys/socket.h>
melunko@250
    39
#include <netdb.h>
melunko@250
    40
#include <errno.h>
melunko@250
    41
#include <stdlib.h>
melunko@250
    42
rosfran@260
    43
#include <gmyth/gmyth_backendinfo.h>
rosfran@260
    44
#include <gmyth/gmyth_socket.h>
rosfran@260
    45
#include <gmyth/gmyth_uri.h>
rosfran@260
    46
#include <gmyth/gmyth_debug.h>
melunko@250
    47
melunko@250
    48
#define GMYTH_UPNP_MAX_SEARCHS		10
melunko@250
    49
melunko@250
    50
static void gmyth_upnp_class_init          (GMythUPnPClass *klass);
melunko@250
    51
static void gmyth_upnp_init                (GMythUPnP *object);
melunko@250
    52
melunko@250
    53
static void gmyth_upnp_dispose  (GObject *object);
melunko@250
    54
static void gmyth_upnp_finalize (GObject *object);
melunko@250
    55
melunko@250
    56
static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info );
melunko@250
    57
melunko@250
    58
static gboolean gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, 
melunko@250
    59
						GList **mythtv_servers_lst );
melunko@250
    60
melunko@250
    61
G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT)
melunko@250
    62
melunko@250
    63
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
melunko@250
    64
melunko@250
    65
static void
melunko@250
    66
gmyth_upnp_class_init (GMythUPnPClass *klass)
melunko@250
    67
{
melunko@250
    68
	GObjectClass *gobject_class;
melunko@250
    69
melunko@250
    70
	gobject_class = (GObjectClass *) klass;
melunko@250
    71
melunko@250
    72
	gobject_class->dispose  = gmyth_upnp_dispose;
melunko@250
    73
	gobject_class->finalize = gmyth_upnp_finalize;	
melunko@250
    74
}
melunko@250
    75
melunko@250
    76
static void
melunko@250
    77
gmyth_upnp_init ( GMythUPnP *gmyth_upnp )
melunko@250
    78
{
melunko@250
    79
	gmyth_upnp->upnp_dev_found = FALSE;
melunko@250
    80
	
melunko@250
    81
	gmyth_upnp->uri = NULL;
melunko@250
    82
	gmyth_upnp->host = NULL;
melunko@250
    83
	gmyth_upnp->port = 0;
melunko@250
    84
	gmyth_upnp->protocol = NULL;
melunko@250
    85
	
melunko@250
    86
	gmyth_upnp->gmyth_backend_info = NULL;
melunko@250
    87
	
melunko@250
    88
	gmyth_upnp->control_point = NULL;
melunko@250
    89
	
melunko@250
    90
}
melunko@250
    91
melunko@250
    92
/** Creates a new instance of GMythUPnP.
melunko@250
    93
 * 
melunko@250
    94
 * @return a new instance of GMythUPnP. 
melunko@250
    95
 */
melunko@250
    96
GMythUPnP *
melunko@250
    97
gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info ) 
melunko@250
    98
{
melunko@250
    99
    GMythUPnP *gmyth_upnp = GMYTH_UPNP (g_object_new (GMYTH_UPNP_TYPE, NULL));
melunko@250
   100
    
melunko@250
   101
    gmyth_upnp->gmyth_backend_info = gmyth_backend_info;
melunko@250
   102
    
melunko@250
   103
    if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info ) )
melunko@250
   104
    	return NULL;
melunko@250
   105
    
melunko@250
   106
    return gmyth_upnp;
melunko@250
   107
}
melunko@250
   108
melunko@250
   109
static void
melunko@250
   110
gmyth_upnp_dispose  (GObject *object)
melunko@250
   111
{
melunko@250
   112
	GMythUPnP *gmyth_upnp = GMYTH_UPNP(object);
melunko@250
   113
melunko@250
   114
	if ( gmyth_upnp->control_point != NULL ) {
melunko@250
   115
		cg_upnp_controlpoint_stop( gmyth_upnp->control_point );
melunko@250
   116
		cg_upnp_controlpoint_delete( gmyth_upnp->control_point );
melunko@250
   117
		gmyth_upnp->control_point = NULL;
melunko@250
   118
	}
melunko@250
   119
melunko@250
   120
	if ( gmyth_upnp->uri != NULL ) {
melunko@250
   121
		g_free ( gmyth_upnp->uri );
melunko@250
   122
		gmyth_upnp->uri = NULL;
melunko@250
   123
	}
melunko@250
   124
	
melunko@250
   125
	if ( gmyth_upnp->host != NULL ) {
melunko@250
   126
		g_free ( gmyth_upnp->host );
melunko@250
   127
		gmyth_upnp->host = NULL;
melunko@250
   128
	}
melunko@250
   129
	
melunko@250
   130
	if ( gmyth_upnp->protocol != NULL ) {
melunko@250
   131
		g_free ( gmyth_upnp->protocol );
melunko@250
   132
		gmyth_upnp->protocol = NULL;
melunko@250
   133
	}
melunko@250
   134
	
melunko@250
   135
	if ( gmyth_upnp->mythtv_servers != NULL )	{
melunko@250
   136
		g_list_free( gmyth_upnp->mythtv_servers );
melunko@250
   137
		gmyth_upnp->mythtv_servers = NULL;
melunko@250
   138
	}
melunko@250
   139
	
melunko@250
   140
	G_OBJECT_CLASS (gmyth_upnp_parent_class)->dispose (object);
melunko@250
   141
}
melunko@250
   142
melunko@250
   143
static void
melunko@250
   144
gmyth_upnp_finalize (GObject *object)
melunko@250
   145
{
melunko@250
   146
	g_signal_handlers_destroy (object);
melunko@250
   147
melunko@250
   148
	G_OBJECT_CLASS (gmyth_upnp_parent_class)->finalize (object);
melunko@250
   149
}
melunko@250
   150
melunko@250
   151
/**
melunko@250
   152
 * Create a control point and start it.
melunko@250
   153
 */
melunko@250
   154
static gboolean
melunko@250
   155
gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info )
melunko@250
   156
{
melunko@250
   157
	
melunko@250
   158
	gboolean ret = FALSE;
melunko@250
   159
	
melunko@250
   160
	GMythURI* uri = NULL;
melunko@250
   161
	
melunko@250
   162
	guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
melunko@250
   163
	
melunko@250
   164
	g_return_val_if_fail( gmyth_backend_info != NULL, FALSE );
melunko@250
   165
	
melunko@250
   166
	/* Create the cybergarage control point */
melunko@250
   167
	gmyth_upnp->control_point = cg_upnp_controlpoint_new();
melunko@250
   168
	/* cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, device_listener ); */
melunko@250
   169
	
melunko@250
   170
	/* Start the control point */
melunko@250
   171
  if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
melunko@250
   172
	{
melunko@250
   173
	  gmyth_debug( "Unable to start UPnP control point!!!" );
melunko@250
   174
	  goto done;
melunko@250
   175
  }
melunko@250
   176
	else
melunko@250
   177
	{
melunko@250
   178
    gmyth_debug( "Control point started." );
melunko@250
   179
	}
melunko@250
   180
	
melunko@250
   181
	while ( gmyth_upnp->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
melunko@250
   182
		
melunko@250
   183
		gmyth_debug( "UPnP MythTV Client control point is searching MythTV AV Device server...\n" );
melunko@250
   184
       
melunko@250
   185
		if ( gmyth_upnp->control_point != NULL )
melunko@250
   186
			cg_upnp_controlpoint_search ( gmyth_upnp->control_point, 
melunko@250
   187
		        		"urn:schemas-upnp-org:service:ContentDirectory:1" );
melunko@250
   188
melunko@250
   189
		/* just to avoid clinkc pthread concurrency faults */
melunko@250
   190
		cg_wait( 1000 );
melunko@250
   191
		
melunko@250
   192
		/* discover if it was found */
melunko@250
   193
		gmyth_upnp->upnp_dev_found = gmyth_upnp_print_cp_device_list( gmyth_upnp->control_point, &gmyth_upnp->udn,
melunko@250
   194
									&gmyth_upnp->mythtv_servers );
melunko@250
   195
		
melunko@250
   196
	}
melunko@250
   197
	
melunko@250
   198
	if ( gmyth_upnp->upnp_dev_found ) {
melunko@250
   199
		
melunko@250
   200
		gmyth_debug( "Found UPnP MythTV AV Device...\n" );
melunko@250
   201
		
melunko@250
   202
		if ( g_list_first( gmyth_upnp->mythtv_servers ) != NULL && (g_list_first( gmyth_upnp->mythtv_servers ))->data != NULL )
melunko@250
   203
		{
melunko@250
   204
			gmyth_upnp->uri = (gchar*) (g_list_first( gmyth_upnp->mythtv_servers ))->data;
melunko@250
   205
			uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
melunko@250
   206
			
melunko@250
   207
			gmyth_upnp->host = gmyth_uri_get_host( uri );
melunko@250
   208
			gmyth_upnp->port = gmyth_uri_get_port( uri );
melunko@250
   209
			gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
melunko@250
   210
			
melunko@250
   211
			/* sets all the discovered data from the UPnP remote device, like host name, IP address, port,... */
melunko@250
   212
			if ( NULL != gmyth_upnp->host )
melunko@250
   213
				gmyth_backend_info_set_hostname ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->host );
melunko@250
   214
			
melunko@250
   215
			if ( gmyth_upnp->port > 0 )
melunko@250
   216
				 gmyth_backend_info_set_port ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->port );
melunko@250
   217
				 
melunko@250
   218
			ret = TRUE;
melunko@250
   219
		}
melunko@250
   220
	}	
melunko@250
   221
melunko@250
   222
done:
melunko@250
   223
melunko@250
   224
  if ( uri != NULL )
melunko@250
   225
  {
melunko@250
   226
  	g_object_unref( uri );
melunko@250
   227
  	uri = NULL;
melunko@250
   228
  }  	
melunko@250
   229
melunko@250
   230
	return ret;
melunko@250
   231
	
melunko@250
   232
}
melunko@250
   233
melunko@250
   234
/** 
melunko@250
   235
 * Prints the Control Point's device list
melunko@250
   236
 */
melunko@250
   237
static gboolean
melunko@250
   238
gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, GList **mythtv_servers_lst )
melunko@250
   239
{
melunko@250
   240
	
melunko@250
   241
	g_return_val_if_fail( mythtv_servers_lst != NULL, FALSE );	
melunko@250
   242
	g_return_val_if_fail( controlPt != NULL, FALSE );
melunko@250
   243
	
melunko@250
   244
	gchar* mythtvFriendlyName = "Myth";
melunko@250
   245
	/* begin assertion about the size of discovered devices */
melunko@250
   246
	gint numDevices = cg_upnp_controlpoint_getndevices(controlPt);
melunko@250
   247
	gint cntDevs = 0;	
melunko@250
   248
	//CgUpnpDeviceList *devList = NULL;
melunko@250
   249
	CgUpnpDevice *childDev;
melunko@250
   250
	gchar *devName = NULL, *dev_url = NULL;
melunko@250
   251
	gboolean upnp_dev_found = FALSE;
melunko@250
   252
	
melunko@250
   253
	gmyth_debug( "UPnP MythTV AV Device list size = %d\n", numDevices );
melunko@250
   254
	
melunko@250
   255
	for ( childDev = cg_upnp_controlpoint_getdevices(controlPt); childDev != NULL; 
melunko@250
   256
			childDev = cg_upnp_device_next(childDev) ) {
melunko@250
   257
		devName = cg_upnp_device_getfriendlyname(childDev);
melunko@250
   258
		dev_url = cg_upnp_device_getlocationfromssdppacket( childDev );
melunko@250
   259
		gmyth_debug( "Device's friendly name = %s, and  device's URL = %s\n", devName, dev_url );
melunko@250
   260
		if ( ( upnp_dev_found = ( g_strstr_len( devName, strlen( devName ), mythtvFriendlyName ) != NULL ) ) == TRUE ) 
melunko@250
   261
		{
melunko@250
   262
			*udn = cg_upnp_device_getudn( childDev );
melunko@250
   263
			*mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url ); 
melunko@250
   264
		}
melunko@250
   265
		++cntDevs;
melunko@250
   266
	}
melunko@250
   267
	
melunko@250
   268
	if ( upnp_dev_found == TRUE ) {
melunko@250
   269
		gmyth_debug( "MythTV AV Device found, from a total of %d devices.\n", cntDevs );
melunko@250
   270
	} else if ( numDevices == cntDevs ) {
melunko@250
   271
		gmyth_debug( "MythTV AV Device not found, from a total of %d devices.\n", cntDevs );
melunko@250
   272
	} else {
melunko@250
   273
		gmyth_debug( "Control Point's MythTV AV Device count is wrong: iterated over %d devices, but there are %d registered devices.\n", cntDevs, numDevices );
melunko@250
   274
	}
melunko@250
   275
	
melunko@250
   276
	return upnp_dev_found;
melunko@250
   277
melunko@250
   278
}
melunko@250
   279
melunko@250
   280
/** Gets the GMythBackendInfo host object associated to this upnp.
melunko@250
   281
 * 
melunko@250
   282
 * @return The string host object currently valid or NULL if the settings
melunko@250
   283
 * were not opened.
melunko@250
   284
 */
melunko@250
   285
gchar*
melunko@250
   286
gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp )
melunko@250
   287
{
melunko@250
   288
	
melunko@250
   289
	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->host ) 
melunko@250
   290
	{
melunko@250
   291
		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
melunko@250
   292
		return NULL;
melunko@250
   293
	}
melunko@250
   294
melunko@250
   295
	return gmyth_upnp->host;
melunko@250
   296
}
melunko@250
   297
melunko@250
   298
/** Gets the GMythBackendInfo port object associated to this upnp.
melunko@250
   299
 * 
melunko@250
   300
 * @return The string object currently valid or NULL if the port number.
melunko@250
   301
 */
melunko@250
   302
gint
melunko@250
   303
gmyth_upnp_get_port( GMythUPnP *gmyth_upnp )
melunko@250
   304
{
melunko@250
   305
melunko@250
   306
	if ( NULL == gmyth_upnp || gmyth_upnp->port <= 0 ) 
melunko@250
   307
	{
melunko@250
   308
		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
melunko@250
   309
		return 0;
melunko@250
   310
	}
melunko@250
   311
melunko@250
   312
	return gmyth_upnp->port;
melunko@250
   313
}
melunko@250
   314
melunko@250
   315
/** Gets the UPnP AV devices server's list associated to this upnp.
melunko@250
   316
 * 
melunko@250
   317
 * @return The GList* containing all the URI values for each recognized UPnP device,
melunko@250
   318
 * 			or NULL if it couldn't recognize any MythTV AV device.
melunko@250
   319
 */
melunko@250
   320
GList*
melunko@250
   321
gmyth_upnp_get_servers ( GMythUPnP *gmyth_upnp )
melunko@250
   322
{
melunko@250
   323
	
melunko@250
   324
	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->mythtv_servers ) 
melunko@250
   325
	{
melunko@250
   326
		gmyth_debug ("[%s] GMythUPnP has no MythTV servers recognized.\n", __FUNCTION__);
melunko@250
   327
		return NULL;
melunko@250
   328
	}
melunko@250
   329
melunko@250
   330
	return gmyth_upnp->mythtv_servers;
melunko@250
   331
}
melunko@250
   332
melunko@250
   333
/** Gets the GMythBackendInfo object associated to this upnp.
melunko@250
   334
 * 
melunko@250
   335
 * @return The GMythBackendInfo object currently valid or NULL if the settings
melunko@250
   336
 * were not opened.
melunko@250
   337
 */
melunko@250
   338
GMythBackendInfo*
melunko@250
   339
gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp )
melunko@250
   340
{
melunko@250
   341
	
melunko@250
   342
	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->gmyth_backend_info ) 
melunko@250
   343
	{
melunko@250
   344
		gmyth_debug ("[%s] GMythUPnP not initialized\n", __FUNCTION__);
melunko@250
   345
		return NULL;
melunko@250
   346
	}
melunko@250
   347
melunko@250
   348
	return gmyth_upnp->gmyth_backend_info;
melunko@250
   349
}
melunko@250
   350