pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / api / upnpapi.c
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000-2003 Intel Corporation 
4 // All rights reserved. 
5 //
6 // Redistribution and use in source and binary forms, with or without 
7 // modification, are permitted provided that the following conditions are met: 
8 //
9 // * Redistributions of source code must retain the above copyright notice, 
10 // this list of conditions and the following disclaimer. 
11 // * Redistributions in binary form must reproduce the above copyright notice, 
12 // this list of conditions and the following disclaimer in the documentation 
13 // and/or other materials provided with the distribution. 
14 // * Neither name of Intel Corporation nor the names of its contributors 
15 // may be used to endorse or promote products derived from this software 
16 // without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 ///////////////////////////////////////////////////////////////////////////
31
32
33 #include "config.h"
34
35
36 #include <sys/stat.h>
37
38
39 #include <assert.h>
40 #include <signal.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44
45 #ifndef WIN32
46         #include <arpa/inet.h>
47         #include <net/if.h>
48         #include <netinet/in.h>
49         #include <sys/ioctl.h>
50         #include <sys/param.h>
51         #include <sys/socket.h>
52         #include <sys/types.h>
53         #include <sys/utsname.h>
54
55
56         #include <unistd.h>
57
58
59         #if defined(_sun)
60                 #include <sys/sockio.h>
61                 #include <fcntl.h>
62         #elif defined(BSD) && BSD >= 199306
63                 #include <ifaddrs.h>
64         #endif
65 #endif /* WIN32 */
66
67
68 #include "upnpapi.h"
69 #include "httpreadwrite.h"
70 #include "membuffer.h"
71 #include "ssdplib.h"
72 #include "soaplib.h"
73 #include "ThreadPool.h"
74
75
76 // Needed for GENA
77 #include "gena.h"
78 #include "miniserver.h"
79 #include "service_table.h"
80
81
82 #ifdef INTERNAL_WEB_SERVER
83         #include "webserver.h"
84         #include "urlconfig.h"
85 #endif // INTERNAL_WEB_SERVER
86
87
88 //
89 virtualDirList *pVirtualDirList;
90
91 // Mutex to synchronize the subscription handling at the client side
92 CLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex; )
93
94 // rwlock to synchronize handles (root device or control point handle)
95     ithread_rwlock_t GlobalHndRWLock;
96
97 // Mutex to synchronize the uuid creation process
98     ithread_mutex_t gUUIDMutex;
99
100     TimerThread gTimerThread;
101
102     ThreadPool gSendThreadPool;
103     ThreadPool gRecvThreadPool;
104     ThreadPool gMiniServerThreadPool;
105
106 //Flag to indicate the state of web server
107      WebServerState bWebServerState = WEB_SERVER_DISABLED;
108
109 // static buffer to store the local host ip address or host name
110      char LOCAL_HOST[LINE_SIZE];
111
112 // local port for the mini-server
113      unsigned short LOCAL_PORT;
114
115 // UPnP device and control point handle table 
116      void *HandleTable[NUM_HANDLE];
117
118 //This structure is for virtual directory callbacks
119      struct UpnpVirtualDirCallbacks virtualDirCallback;
120
121 // a local dir which serves as webserver root
122      extern membuffer gDocumentRootDir;
123
124 // Maximum content-length that the SDK will process on an incoming packet. 
125 // Content-Length exceeding this size will be not processed and error 413 
126 // (HTTP Error Code) will be returned to the remote end point.
127 size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; // in bytes
128
129 // Global variable to denote the state of Upnp SDK 
130 //    = 0 if uninitialized, = 1 if initialized.
131      int UpnpSdkInit = 0;
132
133 // Global variable to denote the state of Upnp SDK device registration.
134 // = 0 if unregistered, = 1 if registered.
135      int UpnpSdkDeviceRegistered = 0;
136
137 // Global variable to denote the state of Upnp SDK client registration.
138 // = 0 if unregistered, = 1 if registered.
139      int UpnpSdkClientRegistered = 0;
140
141 /****************************************************************************
142  * Function: UpnpInit
143  *
144  * Parameters:          
145  *      IN const char * HostIP: Local IP Address
146  *      IN short DestPort: Local Port to listen for incoming connections
147  * Description:
148  *      Initializes 
149  *              - Mutex objects, 
150  *              - Handle Table
151  *              - Thread Pool and Thread Pool Attributes
152  *              - MiniServer(starts listening for incoming requests) 
153  *                      and WebServer (Sends request to the 
154  *                      Upper Layer after HTTP Parsing)
155  *              - Checks for IP Address passed as an argument. IF NULL, 
156  *                gets local host name
157  *              - Sets GENA and SOAP Callbacks.
158  *              - Starts the timer thread.
159  *
160  * Returns:
161  *      UPNP_E_SUCCESS on success, nonzero on failure.
162  *      UPNP_E_INIT_FAILED if Initialization fails.
163  *      UPNP_E_INIT if UPnP is already initialized
164  *****************************************************************************/
165 int UpnpInit( IN const char *HostIP,
166               IN unsigned short DestPort )
167 {
168     int retVal = 0;
169     ThreadPoolAttr attr;
170 #ifdef WIN32
171         WORD wVersionRequested;
172         WSADATA wsaData;
173         int err;
174 #endif
175
176     if( UpnpSdkInit == 1 ) {
177         // already initialized
178         return UPNP_E_INIT;
179     }
180
181 #ifdef WIN32
182         wVersionRequested = MAKEWORD( 2, 2 );
183
184         err = WSAStartup( wVersionRequested, &wsaData );
185         if ( err != 0 ) {
186                 /* Tell the user that we could not find a usable */
187                 /* WinSock DLL.                                  */
188                 return UPNP_E_INIT_FAILED;
189         }
190
191         /* Confirm that the WinSock DLL supports 2.2.*/
192         /* Note that if the DLL supports versions greater    */
193         /* than 2.2 in addition to 2.2, it will still return */
194         /* 2.2 in wVersion since that is the version we      */
195         /* requested.                                        */
196          
197         if ( LOBYTE( wsaData.wVersion ) != 2 ||
198                         HIBYTE( wsaData.wVersion ) != 2 ) {
199                 /* Tell the user that we could not find a usable */
200                 /* WinSock DLL.                                  */
201                 WSACleanup( );
202                 return UPNP_E_INIT_FAILED; 
203         }
204
205         /* The WinSock DLL is acceptable. Proceed. */
206 #endif
207
208     membuffer_init( &gDocumentRootDir );
209
210     srand( time( NULL ) );      // needed by SSDP or other parts
211
212     if( UpnpInitLog() != UPNP_E_SUCCESS ) {
213              return UPNP_E_INIT_FAILED;
214     }
215
216     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInit\n" );
217     // initialize mutex
218 #ifdef __CYGWIN__
219         /* On Cygwin, pthread_mutex_init() fails without this memset. */
220         /* TODO: Fix Cygwin so we don't need this memset(). */
221         memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock));
222 #endif
223     if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) {
224         return UPNP_E_INIT_FAILED;
225     }
226
227     if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) {
228         return UPNP_E_INIT_FAILED;
229     }
230     // initialize subscribe mutex
231 #ifdef INCLUDE_CLIENT_APIS
232     if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) {
233         return UPNP_E_INIT_FAILED;
234     }
235 #endif
236
237     HandleLock();
238     if( HostIP != NULL ) {
239         strcpy( LOCAL_HOST, HostIP );
240     } else {
241         if( getlocalhostname( LOCAL_HOST ) != UPNP_E_SUCCESS ) {
242             HandleUnlock();
243             return UPNP_E_INIT_FAILED;
244         }
245     }
246
247     if( UpnpSdkInit != 0 ) {
248         HandleUnlock();
249         return UPNP_E_INIT;
250     }
251
252     InitHandleList();
253     HandleUnlock();
254
255     TPAttrInit( &attr );
256     TPAttrSetMaxThreads( &attr, MAX_THREADS );
257     TPAttrSetMinThreads( &attr, MIN_THREADS );
258     TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD );
259     TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME );
260     TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL );
261
262     if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) {
263         UpnpSdkInit = 0;
264         UpnpFinish();
265         return UPNP_E_INIT_FAILED;
266     }
267
268     if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) {
269         UpnpSdkInit = 0;
270         UpnpFinish();
271         return UPNP_E_INIT_FAILED;
272     }
273
274     if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) {
275         UpnpSdkInit = 0;
276         UpnpFinish();
277         return UPNP_E_INIT_FAILED;
278     }
279
280     UpnpSdkInit = 1;
281 #if EXCLUDE_SOAP == 0
282     SetSoapCallback( soap_device_callback );
283 #endif
284 #if EXCLUDE_GENA == 0
285     SetGenaCallback( genaCallback );
286 #endif
287
288     if( ( retVal = TimerThreadInit( &gTimerThread,
289                                     &gSendThreadPool ) ) !=
290         UPNP_E_SUCCESS ) {
291         UpnpSdkInit = 0;
292         UpnpFinish();
293         return retVal;
294     }
295 #if EXCLUDE_MINISERVER == 0
296     if( ( retVal = StartMiniServer( DestPort ) ) <= 0 ) {
297         UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
298             "Miniserver failed to start" );
299         UpnpFinish();
300         UpnpSdkInit = 0;
301         if( retVal != -1 )
302             return retVal;
303         else                    // if miniserver is already running for unknown reasons!
304             return UPNP_E_INIT_FAILED;
305     }
306 #endif
307     DestPort = retVal;
308     LOCAL_PORT = DestPort;
309
310 #if EXCLUDE_WEB_SERVER == 0
311     if( ( retVal =
312           UpnpEnableWebserver( WEB_SERVER_ENABLED ) ) != UPNP_E_SUCCESS ) {
313         UpnpFinish();
314         UpnpSdkInit = 0;
315         return retVal;
316     }
317 #endif
318
319     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
320         "Host Ip: %s Host Port: %d\n", LOCAL_HOST,
321         LOCAL_PORT );
322
323     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInit\n" );
324
325     return UPNP_E_SUCCESS;
326
327 } /***************** end of UpnpInit ******************/
328
329 #ifdef DEBUG
330 static void 
331 PrintThreadPoolStats(
332         ThreadPool *tp, 
333         const char *DbgFileName,
334         int DbgLineNo,
335         const char *msg)
336 {
337         ThreadPoolStats stats;
338         ThreadPoolGetStats(tp, &stats);
339         UpnpPrintf(UPNP_INFO, API, DbgFileName, DbgLineNo, 
340                 "%s\n"
341                 "High Jobs pending: %d\n"
342                 "Med Jobs Pending: %d\n"
343                 "Low Jobs Pending: %d\n"
344                 "Average wait in High Q in milliseconds: %lf\n"
345                 "Average wait in Med Q in milliseconds: %lf\n"
346                 "Average wait in Low Q in milliseconds: %lf\n"
347                 "Max Threads Used: %d\n"
348                 "Worker Threads: %d\n"
349                 "Persistent Threads: %d\n"
350                 "Idle Threads: %d\n"
351                 "Total Threads: %d\n"
352                 "Total Work Time: %lf\n"
353                 "Total Idle Time: %lf\n",
354                 msg,
355                 stats.currentJobsHQ,
356                 stats.currentJobsMQ,
357                 stats.currentJobsLQ,
358                 stats.avgWaitHQ,
359                 stats.avgWaitMQ,
360                 stats.avgWaitLQ,
361                 stats.maxThreads,
362                 stats.workerThreads,
363                 stats.persistentThreads,
364                 stats.idleThreads,
365                 stats.totalThreads,
366                 stats.totalWorkTime,
367                 stats.totalIdleTime);
368 }
369 #else /* DEBUG */
370 static UPNP_INLINE void 
371 PrintThreadPoolStats(
372         ThreadPool *tp, 
373         const char *DbgFileName,
374         int DbgLineNo,
375         const char *msg)
376 {
377 }
378 #endif /* DEBUG */
379
380
381 /****************************************************************************
382  * Function: UpnpFinish
383  *
384  * Parameters:  NONE
385  *
386  * Description:
387  *      Checks for pending jobs and threads 
388  *              Unregisters either the client or device 
389  *              Shuts down the Timer Thread
390  *              Stops the Mini Server
391  *              Uninitializes the Thread Pool
392  *              For Win32 cleans up Winsock Interface 
393  *              Cleans up mutex objects
394  *
395  * Return Values:
396  *      UPNP_E_SUCCESS on success, nonzero on failure.
397  *****************************************************************************/
398 int
399 UpnpFinish()
400 {
401 #ifdef INCLUDE_DEVICE_APIS
402     UpnpDevice_Handle device_handle;
403 #endif
404 #ifdef INCLUDE_CLIENT_APIS
405     UpnpClient_Handle client_handle;
406 #endif
407     struct Handle_Info *temp;
408
409 #ifdef WIN32
410 //      WSACleanup();
411 #endif
412
413     if( UpnpSdkInit != 1 ) {
414         return UPNP_E_FINISH;
415     }
416
417     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
418         "Inside UpnpFinish : UpnpSdkInit is :%d:\n", UpnpSdkInit );
419     if( UpnpSdkInit == 1 ) {
420         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
421             "UpnpFinish : UpnpSdkInit is ONE\n" );
422     }
423     PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool");
424     PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool");
425     PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool");
426
427 #ifdef INCLUDE_DEVICE_APIS
428     if( GetDeviceHandleInfo( &device_handle, &temp ) == HND_DEVICE )
429         UpnpUnRegisterRootDevice( device_handle );
430 #endif
431
432 #ifdef INCLUDE_CLIENT_APIS
433     if( GetClientHandleInfo( &client_handle, &temp ) == HND_CLIENT )
434         UpnpUnRegisterClient( client_handle );
435 #endif
436
437     TimerThreadShutdown( &gTimerThread );
438     StopMiniServer();
439
440 #if EXCLUDE_WEB_SERVER == 0
441     web_server_destroy();
442 #endif
443
444     ThreadPoolShutdown(&gMiniServerThreadPool);
445     ThreadPoolShutdown(&gRecvThreadPool);
446     ThreadPoolShutdown(&gSendThreadPool);
447
448     PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool");
449     PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool");
450     PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool");
451
452 #ifdef INCLUDE_CLIENT_APIS
453     ithread_mutex_destroy(&GlobalClientSubscribeMutex);
454 #endif
455     ithread_rwlock_destroy(&GlobalHndRWLock);
456     ithread_mutex_destroy(&gUUIDMutex);
457
458     // remove all virtual dirs
459     UpnpRemoveAllVirtualDirs();
460
461     // allow static linking
462 #ifdef WIN32
463 #ifdef PTW32_STATIC_LIB
464     pthread_win32_thread_detach_np();
465 #endif
466 #endif
467
468     UpnpSdkInit = 0;
469     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
470         "Exiting UpnpFinish : UpnpSdkInit is :%d:\n", UpnpSdkInit);
471     UpnpCloseLog();
472
473     return UPNP_E_SUCCESS;
474
475 }
476 /*************************** End of  UpnpFinish  *****************************/
477
478 /******************************************************************************
479  * Function: UpnpGetServerPort
480  *
481  * Parameters: NONE
482  *
483  * Description:
484  *      Gives back the miniserver port.
485  *
486  * Return Values:
487  *      local port on success, zero on failure.
488  *****************************************************************************/
489 unsigned short
490 UpnpGetServerPort( void )
491 {
492
493     if( UpnpSdkInit != 1 )
494         return 0;
495
496     return LOCAL_PORT;
497 }
498
499 /***************************************************************************
500  * Function: UpnpGetServerIpAddress
501  *
502  * Parameters: NONE
503  *
504  * Description:
505  *      Gives back the local ipaddress.
506  *
507  * Return Values: char *
508  *      return the IP address string on success else NULL of failure
509  ***************************************************************************/
510 char *
511 UpnpGetServerIpAddress( void )
512 {
513
514     if( UpnpSdkInit != 1 )
515         return NULL;
516
517     return LOCAL_HOST;
518 }
519
520 #ifdef INCLUDE_DEVICE_APIS
521 /****************************************************************************
522  * Function: UpnpRegisterRootDevice
523  *
524  * Parameters:  
525  *      IN const char *DescUrl:Pointer to a string containing the 
526  *              description URL for this root device instance. 
527  *      IN Upnp_FunPtr Callback: Pointer to the callback function for 
528  *              receiving asynchronous events. 
529  *      IN const void *Cookie: Pointer to user data returned with the 
530  *              callback function when invoked.
531  *      OUT UpnpDevice_Handle *Hnd: Pointer to a variable to store the 
532  *              new device handle.
533  *
534  * Description:
535  *      This function registers a device application with
536  *      the UPnP Library.  A device application cannot make any other API
537  *      calls until it registers using this function.  
538  *
539  * Return Values:
540  *      UPNP_E_SUCCESS on success, nonzero on failure.
541  *****************************************************************************/
542 int
543 UpnpRegisterRootDevice( IN const char *DescUrl,
544                         IN Upnp_FunPtr Fun,
545                         IN const void *Cookie,
546                         OUT UpnpDevice_Handle * Hnd )
547 {
548
549     struct Handle_Info *HInfo;
550     int retVal = 0;
551
552     if( UpnpSdkInit != 1 ) {
553         return UPNP_E_FINISH;
554     }
555
556     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
557         "Inside UpnpRegisterRootDevice\n" );
558     
559     HandleLock();
560     if( UpnpSdkDeviceRegistered ) {
561         HandleUnlock();
562         return UPNP_E_ALREADY_REGISTERED;
563     }
564
565     if( Hnd == NULL || Fun == NULL ||
566         DescUrl == NULL || strlen( DescUrl ) == 0 ) {
567         HandleUnlock();
568         return UPNP_E_INVALID_PARAM;
569     }
570
571     if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
572         HandleUnlock();
573         return UPNP_E_OUTOF_MEMORY;
574     }
575
576     HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
577     if( HInfo == NULL ) {
578         HandleUnlock();
579         return UPNP_E_OUTOF_MEMORY;
580     }
581     HandleTable[*Hnd] = HInfo;
582
583     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
584         "Root device URL is %s\n", DescUrl );
585
586     HInfo->aliasInstalled = 0;
587     HInfo->HType = HND_DEVICE;
588     strcpy( HInfo->DescURL, DescUrl );
589     HInfo->Callback = Fun;
590     HInfo->Cookie = ( void * )Cookie;
591     HInfo->MaxAge = DEFAULT_MAXAGE;
592     HInfo->DeviceList = NULL;
593     HInfo->ServiceList = NULL;
594     HInfo->DescDocument = NULL;
595     CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); )
596     CLIENTONLY( HInfo->ClientSubList = NULL; )
597     HInfo->MaxSubscriptions = UPNP_INFINITE;
598     HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
599
600     if( ( retVal =
601           UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) )
602         != UPNP_E_SUCCESS ) {
603         CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
604         FreeHandle( *Hnd );
605         HandleUnlock();
606         return retVal;
607     }
608
609     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
610         "UpnpRegisterRootDevice: Valid Description\n" );
611     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
612         "UpnpRegisterRootDevice: DescURL : %s\n",
613         HInfo->DescURL );
614
615     HInfo->DeviceList =
616         ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" );
617     if( !HInfo->DeviceList ) {
618         CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
619         ixmlDocument_free( HInfo->DescDocument );
620         FreeHandle( *Hnd );
621         HandleUnlock();
622         UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
623             "UpnpRegisterRootDevice: No devices found for RootDevice\n" );
624         return UPNP_E_INVALID_DESC;
625     }
626
627     HInfo->ServiceList = ixmlDocument_getElementsByTagName(
628         HInfo->DescDocument, "serviceList" );
629     if( !HInfo->ServiceList ) {
630         UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
631             "UpnpRegisterRootDevice: No services found for RootDevice\n" );
632     }
633
634     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
635         "UpnpRegisterRootDevice: Gena Check\n" );
636     //*******************************
637     // GENA SET UP
638     //*******************************
639     if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument,
640             &HInfo->ServiceTable, HInfo->DescURL ) ) {
641         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
642             "UpnpRegisterRootDevice: GENA Service Table \n" );
643         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
644             "Here are the known services: \n" );
645         printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API );
646     } else {
647         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
648             "\nUpnpRegisterRootDevice2: Empty service table\n" );
649     }
650
651     UpnpSdkDeviceRegistered = 1;
652     HandleUnlock();
653     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
654         "Exiting RegisterRootDevice Successfully\n" );
655
656     return UPNP_E_SUCCESS;
657 }
658 #endif // INCLUDE_DEVICE_APIS
659
660
661 #ifdef INCLUDE_DEVICE_APIS
662 /****************************************************************************
663  * Function: UpnpUnRegisterRootDevice
664  *
665  * Parameters:  
666  *      IN UpnpDevice_Handle Hnd: The handle of the device instance 
667  *              to unregister
668  * Description:
669  *      This function unregisters a root device registered with 
670  *      UpnpRegisterRootDevice} or UpnpRegisterRootDevice2. After this call, the 
671  *      UpnpDevice_Handle Hnd is no longer valid. For all advertisements that 
672  *      have not yet expired, the UPnP library sends a device unavailable message 
673  *      automatically. 
674  *
675  * Return Values:
676  *      UPNP_E_SUCCESS on success, nonzero on failure.
677  *****************************************************************************/
678 int
679 UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd )
680 {
681     int retVal = 0;
682     struct Handle_Info *HInfo = NULL;
683
684     // struct Handle_Info *info=NULL;
685
686     if( UpnpSdkInit != 1 ) {
687         return UPNP_E_FINISH;
688     }
689
690     HandleLock();
691     if( !UpnpSdkDeviceRegistered ) {
692         HandleUnlock();
693         return UPNP_E_INVALID_HANDLE;
694     }
695     HandleUnlock();
696
697     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
698         "Inside UpnpUnRegisterRootDevice \n" );
699 #if EXCLUDE_GENA == 0
700     if( genaUnregisterDevice( Hnd ) != UPNP_E_SUCCESS )
701         return UPNP_E_INVALID_HANDLE;
702 #endif
703
704     HandleLock();
705     if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
706         HandleUnlock();
707         return UPNP_E_INVALID_HANDLE;
708     }
709     HandleUnlock();
710
711 #if EXCLUDE_SSDP == 0
712     retVal = AdvertiseAndReply( -1, Hnd, 0, ( struct sockaddr_in * )NULL,
713                                 ( char * )NULL, ( char * )NULL,
714                                 ( char * )NULL, HInfo->MaxAge );
715 #endif
716
717     HandleLock();
718     if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
719         HandleUnlock();
720         return UPNP_E_INVALID_HANDLE;
721     }
722     //info = (struct Handle_Info *) HandleTable[Hnd];
723     ixmlNodeList_free( HInfo->DeviceList );
724     ixmlNodeList_free( HInfo->ServiceList );
725     ixmlDocument_free( HInfo->DescDocument );
726
727     CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ); )
728
729 #ifdef INTERNAL_WEB_SERVER
730     if( HInfo->aliasInstalled ) {
731         web_server_set_alias( NULL, NULL, 0, 0 );
732     }
733 #endif // INTERNAL_WEB_SERVER
734
735     FreeHandle( Hnd );
736     UpnpSdkDeviceRegistered = 0;
737     HandleUnlock();
738
739     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
740         "Exiting UpnpUnRegisterRootDevice \n" );
741
742     return retVal;
743
744 }  /****************** End of UpnpUnRegisterRootDevice *********************/
745
746 #endif //INCLUDE_DEVICE_APIS
747
748 // *************************************************************
749 #ifdef INCLUDE_DEVICE_APIS
750 #ifdef INTERNAL_WEB_SERVER
751
752 /**************************************************************************
753  * Function: GetNameForAlias
754  *
755  * Parameters:  
756  *      IN char *name: name of the file
757  *      OUT char** alias: pointer to alias string 
758  *
759  * Description:
760  *      This function determines alias for given name which is a file name 
761  *      or URL.
762  *
763  * Return Values:
764  *      UPNP_E_SUCCESS on success, nonzero on failure.
765  ***************************************************************************/
766 static int
767 GetNameForAlias( IN char *name,
768                  OUT char **alias )
769 {
770     char *ext;
771     char *al;
772
773     ext = strrchr( name, '.' );
774     if( ext == NULL || strcasecmp( ext, ".xml" ) != 0 ) {
775         return UPNP_E_EXT_NOT_XML;
776     }
777
778     al = strrchr( name, '/' );
779     if( al == NULL ) {
780         *alias = name;
781     } else {
782         *alias = al;
783     }
784
785     return UPNP_E_SUCCESS;
786 }
787
788 /**************************************************************************
789  * Function: get_server_addr
790  *
791  * Parameters:  
792  *      OUT struct sockaddr_in* serverAddr: pointer to server address
793  *              structure 
794  *
795  * Description:
796  *      This function fills the sockadr_in with miniserver information.
797  *
798  * Return Values: VOID
799  *      
800  ***************************************************************************/
801 static void
802 get_server_addr( OUT struct sockaddr_in *serverAddr )
803 {
804     memset( serverAddr, 0, sizeof( struct sockaddr_in ) );
805
806     serverAddr->sin_family = AF_INET;
807     serverAddr->sin_port = htons( LOCAL_PORT );
808     //inet_aton( LOCAL_HOST, &serverAddr->sin_addr );
809     serverAddr->sin_addr.s_addr = inet_addr( LOCAL_HOST );
810 }
811
812 /**************************************************************************
813  * Function: GetDescDocumentAndURL ( In the case of device)
814  *
815  * Parameters:  
816  *      IN Upnp_DescType descriptionType: pointer to server address
817  *              structure 
818  *      IN char* description:
819  *      IN unsigned int bufferLen:
820  *      IN int config_baseURL:
821  *      OUT IXML_Document **xmlDoc:
822  *      OUT char descURL[LINE_SIZE]: 
823  *
824  * Description:
825  *      This function fills the sockadr_in with miniserver information.
826  *
827  * Return Values: VOID
828  *      
829  ***************************************************************************/
830 static int
831 GetDescDocumentAndURL( IN Upnp_DescType descriptionType,
832                        IN char *description,
833                        IN unsigned int bufferLen,
834                        IN int config_baseURL,
835                        OUT IXML_Document ** xmlDoc,
836                        OUT char descURL[LINE_SIZE] )
837 {
838     int retVal = 0;
839     char *membuf = NULL;
840     char aliasStr[LINE_SIZE];
841     char *temp_str = NULL;
842     FILE *fp = NULL;
843     off_t fileLen;
844     size_t num_read;
845     time_t last_modified;
846     struct stat file_info;
847     struct sockaddr_in serverAddr;
848     int rc = UPNP_E_SUCCESS;
849
850     if( description == NULL ) {
851         return UPNP_E_INVALID_PARAM;
852     }
853     // non-URL description must have configuration specified
854     if( descriptionType != UPNPREG_URL_DESC && ( !config_baseURL ) ) {
855         return UPNP_E_INVALID_PARAM;
856     }
857     // get XML doc and last modified time
858     if( descriptionType == UPNPREG_URL_DESC ) {
859         if( ( retVal =
860               UpnpDownloadXmlDoc( description,
861                                   xmlDoc ) ) != UPNP_E_SUCCESS ) {
862             return retVal;
863         }
864         last_modified = time( NULL );
865     } else if( descriptionType == UPNPREG_FILENAME_DESC ) {
866         retVal = stat( description, &file_info );
867         if( retVal == -1 ) {
868             return UPNP_E_FILE_NOT_FOUND;
869         }
870         fileLen = file_info.st_size;
871         last_modified = file_info.st_mtime;
872
873         if( ( fp = fopen( description, "rb" ) ) == NULL ) {
874             return UPNP_E_FILE_NOT_FOUND;
875         }
876
877         if( ( membuf = ( char * )malloc( fileLen + 1 ) ) == NULL ) {
878             fclose( fp );
879             return UPNP_E_OUTOF_MEMORY;
880         }
881
882         num_read = fread( membuf, 1, fileLen, fp );
883         if( num_read != fileLen ) {
884             fclose( fp );
885             free( membuf );
886             return UPNP_E_FILE_READ_ERROR;
887         }
888
889         membuf[fileLen] = 0;
890         fclose( fp );
891         rc = ixmlParseBufferEx( membuf, xmlDoc );
892         free( membuf );
893     } else if( descriptionType == UPNPREG_BUF_DESC ) {
894         last_modified = time( NULL );
895         rc = ixmlParseBufferEx( description, xmlDoc );
896     } else {
897         return UPNP_E_INVALID_PARAM;
898     }
899
900     if( rc != IXML_SUCCESS && descriptionType != UPNPREG_URL_DESC ) {
901         if( rc == IXML_INSUFFICIENT_MEMORY ) {
902             return UPNP_E_OUTOF_MEMORY;
903         } else {
904             return UPNP_E_INVALID_DESC;
905         }
906     }
907     // determine alias
908     if( config_baseURL ) {
909         if( descriptionType == UPNPREG_BUF_DESC ) {
910             strcpy( aliasStr, "description.xml" );
911         } else                  // URL or filename
912         {
913             retVal = GetNameForAlias( description, &temp_str );
914             if( retVal != UPNP_E_SUCCESS ) {
915                 ixmlDocument_free( *xmlDoc );
916                 return retVal;
917             }
918             if( strlen( temp_str ) > ( LINE_SIZE - 1 ) ) {
919                 ixmlDocument_free( *xmlDoc );
920                 free( temp_str );
921                 return UPNP_E_URL_TOO_BIG;
922             }
923             strcpy( aliasStr, temp_str );
924         }
925
926         get_server_addr( &serverAddr );
927
928         // config
929         retVal = configure_urlbase( *xmlDoc, &serverAddr,
930                                     aliasStr, last_modified, descURL );
931         if( retVal != UPNP_E_SUCCESS ) {
932             ixmlDocument_free( *xmlDoc );
933             return retVal;
934         }
935     } else                      // manual
936     {
937         if( strlen( description ) > ( LINE_SIZE - 1 ) ) {
938             ixmlDocument_free( *xmlDoc );
939             return UPNP_E_URL_TOO_BIG;
940         }
941         strcpy( descURL, description );
942     }
943
944     assert( *xmlDoc != NULL );
945
946     return UPNP_E_SUCCESS;
947 }
948
949 #else // no web server
950
951 /**************************************************************************
952  * Function: GetDescDocumentAndURL ( In the case of control point)
953  *
954  *  Parameters: 
955  *      IN Upnp_DescType descriptionType: pointer to server address
956  *              structure 
957  *      IN char* description:
958  *      IN unsigned int bufferLen:
959  *      IN int config_baseURL:
960  *      OUT IXML_Document **xmlDoc:
961  *      OUT char *descURL: 
962  *
963  * Description:
964  *      This function fills the sockadr_in with miniserver information.
965  *
966  * Return Values: VOID
967  *      
968  ***************************************************************************/
969 static int
970 GetDescDocumentAndURL( IN Upnp_DescType descriptionType,
971                        IN char *description,
972                        IN unsigned int bufferLen,
973                        IN int config_baseURL,
974                        OUT IXML_Document ** xmlDoc,
975                        OUT char *descURL )
976 {
977     int retVal;
978
979     if( ( descriptionType != UPNPREG_URL_DESC ) || config_baseURL ) {
980         return UPNP_E_NO_WEB_SERVER;
981     }
982
983     if( description == NULL ) {
984         return UPNP_E_INVALID_PARAM;
985     }
986
987     if( strlen( description ) > ( LINE_SIZE - 1 ) ) {
988         return UPNP_E_URL_TOO_BIG;
989     }
990     strcpy( descURL, description );
991
992     if( ( retVal =
993           UpnpDownloadXmlDoc( description, xmlDoc ) ) != UPNP_E_SUCCESS ) {
994         return retVal;
995     }
996
997     return UPNP_E_SUCCESS;
998 }
999
1000 #endif // INTERNAL_WEB_SERVER
1001 // ********************************************************
1002
1003 /****************************************************************************
1004  * Function: UpnpRegisterRootDevice2
1005  *
1006  * Parameters:  
1007  *      IN Upnp_DescType descriptionType: The type of description document.
1008  *      IN const char* description:  Treated as a URL, file name or 
1009  *              memory buffer depending on description type. 
1010  *      IN size_t bufferLen: Length of memory buffer if passing a description
1011  *              in a buffer, otherwize ignored.
1012  *      IN int config_baseURL: If nonzero, URLBase of description document is 
1013  *              configured and the description is served using the internal
1014  *              web server.
1015  *      IN Upnp_FunPtr Fun: Pointer to the callback function for 
1016  *              receiving asynchronous events. 
1017  *      IN const void* Cookie: Pointer to user data returned with the 
1018  *              callback function when invoked. 
1019  *      OUT UpnpDevice_Handle* Hnd: Pointer to a variable to store 
1020  *              the new device handle.
1021  *
1022  * Description:
1023  *      This function is similar to  UpnpRegisterRootDevice except that
1024  *      it also allows the description document to be specified as a file or 
1025  *      a memory buffer. The description can also be configured to have the
1026  *      correct IP and port address.
1027  *
1028  * Return Values:
1029  *      UPNP_E_SUCCESS on success, nonzero on failure.
1030  *****************************************************************************/
1031 int
1032 UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType,
1033                          IN const char *description_const,
1034                          IN size_t bufferLen,   // ignored unless descType == UPNPREG_BUF_DESC
1035
1036                          IN int config_baseURL,
1037                          IN Upnp_FunPtr Fun,
1038                          IN const void *Cookie,
1039                          OUT UpnpDevice_Handle * Hnd )
1040 {
1041     struct Handle_Info *HInfo;
1042     int retVal = 0;
1043     char *description = ( char * )description_const;
1044     if( UpnpSdkInit != 1 ) {
1045         return UPNP_E_FINISH;
1046     }
1047
1048     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
1049         "Inside UpnpRegisterRootDevice2\n" );
1050
1051     if( Hnd == NULL || Fun == NULL ) {
1052         return UPNP_E_INVALID_PARAM;
1053     }
1054
1055     HandleLock();
1056     if( UpnpSdkDeviceRegistered ) {
1057         HandleUnlock();
1058         return UPNP_E_ALREADY_REGISTERED;
1059     }
1060
1061     if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
1062         HandleUnlock();
1063         return UPNP_E_OUTOF_MEMORY;
1064     }
1065
1066     HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
1067     if( HInfo == NULL ) {
1068         HandleUnlock();
1069         return UPNP_E_OUTOF_MEMORY;
1070     }
1071     HandleTable[*Hnd] = HInfo;
1072
1073     // prevent accidental removal of a non-existent alias
1074     HInfo->aliasInstalled = 0;
1075
1076     retVal = GetDescDocumentAndURL(
1077         descriptionType, description, bufferLen,
1078         config_baseURL, &HInfo->DescDocument, HInfo->DescURL );
1079
1080     if( retVal != UPNP_E_SUCCESS ) {
1081         FreeHandle( *Hnd );
1082         HandleUnlock();
1083         return retVal;
1084     }
1085
1086     HInfo->aliasInstalled = ( config_baseURL != 0 );
1087     HInfo->HType = HND_DEVICE;
1088
1089     HInfo->Callback = Fun;
1090     HInfo->Cookie = ( void * )Cookie;
1091     HInfo->MaxAge = DEFAULT_MAXAGE;
1092     HInfo->DeviceList = NULL;
1093     HInfo->ServiceList = NULL;
1094
1095     CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); )
1096     CLIENTONLY( HInfo->ClientSubList = NULL; )
1097     HInfo->MaxSubscriptions = UPNP_INFINITE;
1098     HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
1099
1100     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1101         "UpnpRegisterRootDevice2: Valid Description\n" );
1102     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1103         "UpnpRegisterRootDevice2: DescURL : %s\n",
1104         HInfo->DescURL );
1105
1106     HInfo->DeviceList =
1107         ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" );
1108
1109     if( !HInfo->DeviceList ) {
1110         CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ); )
1111         ixmlDocument_free( HInfo->DescDocument );
1112         FreeHandle( *Hnd );
1113         HandleUnlock();
1114         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
1115             "UpnpRegisterRootDevice2: No devices found for RootDevice\n" );
1116         return UPNP_E_INVALID_DESC;
1117     }
1118
1119     HInfo->ServiceList = ixmlDocument_getElementsByTagName(
1120         HInfo->DescDocument, "serviceList" );
1121     if( !HInfo->ServiceList ) {
1122         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
1123             "UpnpRegisterRootDevice2: No services found for RootDevice\n" );
1124     }
1125
1126     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1127         "UpnpRegisterRootDevice2: Gena Check\n" );
1128     //*******************************
1129     // GENA SET UP
1130     //*******************************
1131     if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument,
1132             &HInfo->ServiceTable, HInfo->DescURL ) ) {
1133         UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1134             "UpnpRegisterRootDevice2: GENA Service Table\n" );
1135         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
1136             "Here are the known services: \n" );
1137         printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API );
1138     } else {
1139         UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
1140             "\nUpnpRegisterRootDevice2: Empty service table\n" );
1141     }
1142
1143     UpnpSdkDeviceRegistered = 1;
1144     HandleUnlock();
1145     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1146         "Exiting RegisterRootDevice2 Successfully\n" );
1147
1148     return UPNP_E_SUCCESS;
1149 }
1150
1151 #endif // INCLUDE_DEVICE_APIS
1152
1153 #ifdef INCLUDE_CLIENT_APIS
1154
1155 /**************************************************************************
1156  * Function: UpnpRegisterClient
1157  *
1158  * Parameters:  
1159  *      IN Upnp_FunPtr Fun:  Pointer to a function for receiving 
1160  *               asynchronous events.
1161  *      IN const void * Cookie: Pointer to user data returned with the 
1162  *              callback function when invoked.
1163  *      OUT UpnpClient_Handle *Hnd: Pointer to a variable to store 
1164  *              the new control point handle.
1165  *
1166  * Description:
1167  *      This function registers a control point application with the
1168  *      UPnP Library.  A control point application cannot make any other API 
1169  *      calls until it registers using this function.
1170  *
1171  * Return Values: int
1172  *      
1173  ***************************************************************************/
1174 int
1175 UpnpRegisterClient( IN Upnp_FunPtr Fun,
1176                     IN const void *Cookie,
1177                     OUT UpnpClient_Handle * Hnd )
1178 {
1179     struct Handle_Info *HInfo;
1180
1181     if( UpnpSdkInit != 1 ) {
1182         return UPNP_E_FINISH;
1183     }
1184     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1185         "Inside UpnpRegisterClient \n" );
1186     if( Fun == NULL || Hnd == NULL ) {
1187         return UPNP_E_INVALID_PARAM;
1188     }
1189
1190     HandleLock();
1191
1192     if( UpnpSdkClientRegistered ) {
1193         HandleUnlock();
1194         return UPNP_E_ALREADY_REGISTERED;
1195     }
1196     if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
1197         HandleUnlock();
1198         return UPNP_E_OUTOF_MEMORY;
1199     }
1200     HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
1201     if( HInfo == NULL ) {
1202         HandleUnlock();
1203         return UPNP_E_OUTOF_MEMORY;
1204     }
1205
1206     HInfo->HType = HND_CLIENT;
1207     HInfo->Callback = Fun;
1208     HInfo->Cookie = ( void * )Cookie;
1209     HInfo->ClientSubList = NULL;
1210     ListInit( &HInfo->SsdpSearchList, NULL, NULL );
1211 #ifdef INCLUDE_DEVICE_APIS
1212     HInfo->MaxAge = 0;
1213     HInfo->MaxSubscriptions = UPNP_INFINITE;
1214     HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
1215 #endif
1216
1217     HandleTable[*Hnd] = HInfo;
1218     UpnpSdkClientRegistered = 1;
1219
1220     HandleUnlock();
1221
1222     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1223         "Exiting UpnpRegisterClient \n" );
1224
1225     return UPNP_E_SUCCESS;
1226
1227 }  /****************** End of UpnpRegisterClient   *********************/
1228 #endif // INCLUDE_CLIENT_APIS
1229
1230
1231 /****************************************************************************
1232  * Function: UpnpUnRegisterClient
1233  *
1234  * Parameters:  
1235  *      IN UpnpClient_Handle Hnd: The handle of the control point instance 
1236  *              to unregister
1237  * Description:
1238  *      This function unregisters a client registered with 
1239  *      UpnpRegisterclient or UpnpRegisterclient2. After this call, the 
1240  *      UpnpDevice_Handle Hnd is no longer valid. The UPnP Library generates 
1241  *      no more callbacks after this function returns.
1242  *
1243  * Return Values:
1244  *      UPNP_E_SUCCESS on success, nonzero on failure.
1245  *****************************************************************************/
1246 #ifdef INCLUDE_CLIENT_APIS
1247 int
1248 UpnpUnRegisterClient( IN UpnpClient_Handle Hnd )
1249 {
1250     struct Handle_Info *HInfo;
1251     ListNode *node = NULL;
1252     SsdpSearchArg *searchArg = NULL;
1253
1254     if( UpnpSdkInit != 1 ) {
1255         return UPNP_E_FINISH;
1256     }
1257
1258     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1259         "Inside UpnpUnRegisterClient \n" );
1260     HandleLock();
1261     if( !UpnpSdkClientRegistered ) {
1262         HandleUnlock();
1263         return UPNP_E_INVALID_HANDLE;
1264     }
1265     HandleUnlock();
1266
1267 #if EXCLUDE_GENA == 0
1268     if( genaUnregisterClient( Hnd ) != UPNP_E_SUCCESS )
1269         return UPNP_E_INVALID_HANDLE;
1270 #endif
1271     HandleLock();
1272     if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
1273         HandleUnlock();
1274         return UPNP_E_INVALID_HANDLE;
1275     }
1276     //clean up search list
1277     node = ListHead( &HInfo->SsdpSearchList );
1278     while( node != NULL ) {
1279         searchArg = ( SsdpSearchArg * ) node->item;
1280         if( searchArg ) {
1281             free( searchArg->searchTarget );
1282             free( searchArg );
1283         }
1284         ListDelNode( &HInfo->SsdpSearchList, node, 0 );
1285         node = ListHead( &HInfo->SsdpSearchList );
1286     }
1287
1288     ListDestroy( &HInfo->SsdpSearchList, 0 );
1289     FreeHandle( Hnd );
1290     UpnpSdkClientRegistered = 0;
1291     HandleUnlock();
1292     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1293         "Exiting UpnpUnRegisterClient \n" );
1294     return UPNP_E_SUCCESS;
1295
1296 }  /****************** End of UpnpUnRegisterClient *********************/
1297 #endif // INCLUDE_CLIENT_APIS
1298
1299 //-----------------------------------------------------------------------------
1300 //
1301 //                                   SSDP interface
1302 //
1303 //-----------------------------------------------------------------------------
1304
1305 #ifdef INCLUDE_DEVICE_APIS
1306 #if EXCLUDE_SSDP == 0
1307
1308 /**************************************************************************
1309  * Function: UpnpSendAdvertisement 
1310  *
1311  * Parameters:  
1312  *      IN UpnpDevice_Handle Hnd: handle of the device instance
1313  *      IN int Exp : Timer for resending the advertisement
1314  *
1315  * Description:
1316  *      This function sends the device advertisement. It also schedules a
1317  *      job for the next advertisement after "Exp" time.
1318  *
1319  * Return Values: int
1320  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1321  ***************************************************************************/
1322 int
1323 UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd,
1324                        IN int Exp )
1325 {
1326     struct Handle_Info *SInfo = NULL;
1327     int retVal = 0,
1328      *ptrMx;
1329     upnp_timeout *adEvent;
1330     ThreadPoolJob job;
1331
1332     if( UpnpSdkInit != 1 ) {
1333         return UPNP_E_FINISH;
1334     }
1335
1336     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1337         "Inside UpnpSendAdvertisement \n" );
1338
1339     HandleLock();
1340     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
1341         HandleUnlock();
1342         return UPNP_E_INVALID_HANDLE;
1343     }
1344     if( Exp < 1 )
1345         Exp = DEFAULT_MAXAGE;
1346     SInfo->MaxAge = Exp;
1347     HandleUnlock();
1348     retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr_in * )NULL,
1349                                 ( char * )NULL, ( char * )NULL,
1350                                 ( char * )NULL, Exp );
1351
1352     if( retVal != UPNP_E_SUCCESS )
1353         return retVal;
1354     ptrMx = ( int * )malloc( sizeof( int ) );
1355     if( ptrMx == NULL )
1356         return UPNP_E_OUTOF_MEMORY;
1357     adEvent = ( upnp_timeout * ) malloc( sizeof( upnp_timeout ) );
1358
1359     if( adEvent == NULL ) {
1360         free( ptrMx );
1361         return UPNP_E_OUTOF_MEMORY;
1362     }
1363     *ptrMx = Exp;
1364     adEvent->handle = Hnd;
1365     adEvent->Event = ptrMx;
1366
1367     HandleLock();
1368     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
1369         HandleUnlock();
1370         free( adEvent );
1371         free( ptrMx );
1372         return UPNP_E_INVALID_HANDLE;
1373     }
1374 #ifdef SSDP_PACKET_DISTRIBUTE
1375     TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent );
1376     TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
1377     TPJobSetPriority( &job, MED_PRIORITY );
1378     if( ( retVal = TimerThreadSchedule( &gTimerThread,
1379                                         ( ( Exp / 2 ) -
1380                                           ( AUTO_ADVERTISEMENT_TIME ) ),
1381                                         REL_SEC, &job, SHORT_TERM,
1382                                         &( adEvent->eventId ) ) )
1383         != UPNP_E_SUCCESS ) {
1384         HandleUnlock();
1385         free( adEvent );
1386         free( ptrMx );
1387         return retVal;
1388     }
1389 #else
1390     TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent );
1391     TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
1392     TPJobSetPriority( &job, MED_PRIORITY );
1393     if( ( retVal = TimerThreadSchedule( &gTimerThread,
1394                                         Exp - AUTO_ADVERTISEMENT_TIME,
1395                                         REL_SEC, &job, SHORT_TERM,
1396                                         &( adEvent->eventId ) ) )
1397         != UPNP_E_SUCCESS ) {
1398         HandleUnlock();
1399         free( adEvent );
1400         free( ptrMx );
1401         return retVal;
1402     }
1403 #endif
1404
1405     HandleUnlock();
1406     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1407         "Exiting UpnpSendAdvertisement \n" );
1408
1409     return retVal;
1410
1411 }  /****************** End of UpnpSendAdvertisement *********************/
1412 #endif // INCLUDE_DEVICE_APIS
1413 #endif
1414 #if EXCLUDE_SSDP == 0
1415 #ifdef INCLUDE_CLIENT_APIS
1416
1417 /**************************************************************************
1418  * Function: UpnpSearchAsync 
1419  *
1420  * Parameters:  
1421  *      IN UpnpClient_Handle Hnd: handle of the control point instance
1422  *      IN int Mx : Maximum time to wait for the search reply
1423  *      IN const char *Target_const: 
1424  *      IN const void *Cookie_const:
1425  *
1426  * Description:
1427  *      This function searches for the devices for the provided maximum time.
1428  *      It is a asynchronous function. It schedules a search job and returns. 
1429  *      client is notified about the search results after search timer.
1430  *
1431  * Return Values: int
1432  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1433  ***************************************************************************/
1434 int
1435 UpnpSearchAsync( IN UpnpClient_Handle Hnd,
1436                  IN int Mx,
1437                  IN const char *Target_const,
1438                  IN const void *Cookie_const )
1439 {
1440     struct Handle_Info *SInfo = NULL;
1441     char *Target = ( char * )Target_const;
1442
1443     if( UpnpSdkInit != 1 ) {
1444         return UPNP_E_FINISH;
1445     }
1446
1447     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1448         "Inside UpnpSearchAsync \n" );
1449
1450     HandleReadLock();
1451     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1452         HandleUnlock();
1453         return UPNP_E_INVALID_HANDLE;
1454     }
1455     if( Mx < 1 )
1456         Mx = DEFAULT_MX;
1457
1458     if( Target == NULL ) {
1459         HandleUnlock();
1460         return UPNP_E_INVALID_PARAM;
1461     }
1462
1463     HandleUnlock();
1464     SearchByTarget( Mx, Target, ( void * )Cookie_const );
1465
1466     //HandleUnlock();
1467
1468     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1469         "Exiting UpnpSearchAsync \n" );
1470
1471     return UPNP_E_SUCCESS;
1472
1473 }  /****************** End of UpnpSearchAsync *********************/
1474 #endif // INCLUDE_CLIENT_APIS
1475 #endif
1476 //-----------------------------------------------------------------------------
1477 //
1478 //                                   GENA interface 
1479 //
1480 //-----------------------------------------------------------------------------
1481
1482 #if EXCLUDE_GENA == 0
1483 #ifdef INCLUDE_DEVICE_APIS
1484
1485 /**************************************************************************
1486  * Function: UpnpSetMaxSubscriptions 
1487  *
1488  * Parameters:  
1489  *      IN UpnpDevice_Handle Hnd: The handle of the device for which
1490  *              the maximum subscriptions is being set.
1491  *      IN int MaxSubscriptions: The maximum number of subscriptions to be
1492  *              allowed per service.
1493  *
1494  * Description:
1495  *      This function sets the maximum subscriptions of the control points
1496  * Return Values: int
1497  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1498  ***************************************************************************/
1499 int
1500 UpnpSetMaxSubscriptions( IN UpnpDevice_Handle Hnd,
1501                          IN int MaxSubscriptions )
1502 {
1503     struct Handle_Info *SInfo = NULL;
1504
1505     if( UpnpSdkInit != 1 ) {
1506         return UPNP_E_FINISH;
1507     }
1508
1509     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1510         "Inside UpnpSetMaxSubscriptions \n" );
1511
1512     HandleLock();
1513     if( ( ( MaxSubscriptions != UPNP_INFINITE )
1514           && ( MaxSubscriptions < 0 ) )
1515         || ( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) ) {
1516         HandleUnlock();
1517         return UPNP_E_INVALID_HANDLE;
1518     }
1519     SInfo->MaxSubscriptions = MaxSubscriptions;
1520     HandleUnlock();
1521
1522     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1523         "Exiting UpnpSetMaxSubscriptions \n" );
1524
1525     return UPNP_E_SUCCESS;
1526
1527 }  /***************** End of UpnpSetMaxSubscriptions ********************/
1528 #endif // INCLUDE_DEVICE_APIS
1529
1530 #ifdef INCLUDE_DEVICE_APIS
1531
1532 /**************************************************************************
1533  * Function: UpnpSetMaxSubscriptionTimeOut 
1534  *
1535  * Parameters:  
1536  *      IN UpnpDevice_Handle Hnd: The handle of the device for which the
1537  *              maximum subscription time-out is being set.
1538  *      IN int MaxSubscriptionTimeOut:The maximum subscription time-out 
1539  *              to be accepted
1540  *
1541  * Description:
1542  *      This function sets the maximum subscription timer. Control points
1543  *      will require to send the subscription request before timeout.
1544  *
1545  * Return Values: int
1546  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1547  ***************************************************************************/
1548 int
1549 UpnpSetMaxSubscriptionTimeOut( IN UpnpDevice_Handle Hnd,
1550                                IN int MaxSubscriptionTimeOut )
1551 {
1552     struct Handle_Info *SInfo = NULL;
1553
1554     if( UpnpSdkInit != 1 ) {
1555         return UPNP_E_FINISH;
1556     }
1557
1558     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1559         "Inside UpnpSetMaxSubscriptionTimeOut \n" );
1560
1561     HandleLock();
1562
1563     if( ( ( MaxSubscriptionTimeOut != UPNP_INFINITE )
1564           && ( MaxSubscriptionTimeOut < 0 ) )
1565         || ( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) ) {
1566         HandleUnlock();
1567         return UPNP_E_INVALID_HANDLE;
1568     }
1569
1570     SInfo->MaxSubscriptionTimeOut = MaxSubscriptionTimeOut;
1571     HandleUnlock();
1572
1573     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1574         "Exiting UpnpSetMaxSubscriptionTimeOut \n" );
1575
1576     return UPNP_E_SUCCESS;
1577
1578 }  /****************** End of UpnpSetMaxSubscriptionTimeOut ******************/
1579 #endif // INCLUDE_DEVICE_APIS
1580
1581 #ifdef INCLUDE_CLIENT_APIS
1582
1583 /**************************************************************************
1584  * Function: UpnpSubscribeAsync 
1585  *
1586  * Parameters:  
1587  *      IN UpnpClient_Handle Hnd: The handle of the control point for which 
1588  *              the subscription request is to be sent.
1589  *      IN const char * EvtUrl_const: URL that control point wants to 
1590  *              subscribe
1591  *      IN int TimeOut: The requested subscription time.  Upon 
1592  *              return, it contains the actual subscription time 
1593  *              returned from the service
1594  *      IN Upnp_FunPtr Fun : callback function to tell result of the 
1595  *              subscription request
1596  *      IN const void * Cookie_const: cookie passed by client to give back 
1597  *              in the callback function.
1598  *
1599  * Description:
1600  *      This function performs the same operation as UpnpSubscribeAsync
1601  *      but returns immediately and calls the registered callback function 
1602  *      when the operation is complete.
1603  *
1604  * Return Values: int
1605  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1606  ***************************************************************************/
1607 int
1608 UpnpSubscribeAsync( IN UpnpClient_Handle Hnd,
1609                     IN const char *EvtUrl_const,
1610                     IN int TimeOut,
1611                     IN Upnp_FunPtr Fun,
1612                     IN const void *Cookie_const )
1613 {
1614     struct Handle_Info *SInfo = NULL;
1615     struct UpnpNonblockParam *Param;
1616     char *EvtUrl = ( char * )EvtUrl_const;
1617     ThreadPoolJob job;
1618
1619     if( UpnpSdkInit != 1 ) {
1620         return UPNP_E_FINISH;
1621     }
1622
1623     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1624         "Inside UpnpSubscribeAsync \n" );
1625
1626     HandleReadLock();
1627     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1628         HandleUnlock();
1629         return UPNP_E_INVALID_HANDLE;
1630     }
1631     if( EvtUrl == NULL ) {
1632         HandleUnlock();
1633         return UPNP_E_INVALID_PARAM;
1634     }
1635     if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) {
1636         HandleUnlock();
1637         return UPNP_E_INVALID_PARAM;
1638     }
1639     if( Fun == NULL ) {
1640         HandleUnlock();
1641         return UPNP_E_INVALID_PARAM;
1642     }
1643     HandleUnlock();
1644
1645     Param = (struct UpnpNonblockParam *)
1646         malloc(sizeof (struct UpnpNonblockParam));
1647     if( Param == NULL ) {
1648         return UPNP_E_OUTOF_MEMORY;
1649     }
1650
1651     Param->FunName = SUBSCRIBE;
1652     Param->Handle = Hnd;
1653     strcpy( Param->Url, EvtUrl );
1654     Param->TimeOut = TimeOut;
1655     Param->Fun = Fun;
1656     Param->Cookie = ( void * )Cookie_const;
1657
1658     TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
1659     TPJobSetFreeFunction( &job, ( free_routine ) free );
1660     TPJobSetPriority( &job, MED_PRIORITY );
1661     ThreadPoolAdd( &gSendThreadPool, &job, NULL );
1662
1663     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1664         "Exiting UpnpSubscribeAsync \n" );
1665
1666     return UPNP_E_SUCCESS;
1667
1668 }  /****************** End of UpnpSubscribeAsync *********************/
1669 #endif // INCLUDE_CLIENT_APIS
1670
1671 #ifdef INCLUDE_CLIENT_APIS
1672
1673 /**************************************************************************
1674  * Function: UpnpSubscribe 
1675  *
1676  * Parameters:  
1677  *      IN UpnpClient_Handle Hnd: The handle of the control point.
1678  *      IN const char *PublisherUrl: The URL of the service to subscribe to.
1679  *      INOUT int *TimeOut: Pointer to a variable containing the requested 
1680  *              subscription time.  Upon return, it contains the
1681  *              actual subscription time returned from the service.
1682  *      OUT Upnp_SID SubsId: Pointer to a variable to receive the 
1683  *              subscription ID (SID). 
1684  *
1685  * Description:
1686  *      This function registers a control point to receive event
1687  *      notifications from another device.  This operation is synchronous
1688  *
1689  * Return Values: int
1690  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1691  ***************************************************************************/
1692 int
1693 UpnpSubscribe( IN UpnpClient_Handle Hnd,
1694                IN const char *EvtUrl_const,
1695                INOUT int *TimeOut,
1696                OUT Upnp_SID SubsId )
1697 {
1698     struct Handle_Info *SInfo = NULL;
1699     int RetVal;
1700     char *EvtUrl = ( char * )EvtUrl_const;
1701
1702     if( UpnpSdkInit != 1 ) {
1703         return UPNP_E_FINISH;
1704     }
1705
1706     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1707         "Inside UpnpSubscribe \n" );
1708
1709     HandleReadLock();
1710     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1711         HandleUnlock();
1712         return UPNP_E_INVALID_HANDLE;
1713     }
1714     if( EvtUrl == NULL ) {
1715         HandleUnlock();
1716         return UPNP_E_INVALID_PARAM;
1717     }
1718     if( TimeOut == NULL ) {
1719         HandleUnlock();
1720         return UPNP_E_INVALID_PARAM;
1721     }
1722     if( SubsId == NULL ) {
1723         HandleUnlock();
1724         return UPNP_E_INVALID_PARAM;
1725     }
1726     HandleUnlock();
1727     RetVal = genaSubscribe( Hnd, EvtUrl, TimeOut, SubsId );
1728
1729     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1730         "Exiting UpnpSubscribe \n" );
1731
1732     return RetVal;
1733
1734 }  /****************** End of UpnpSubscribe  *********************/
1735 #endif // INCLUDE_CLIENT_APIS
1736
1737 #ifdef INCLUDE_CLIENT_APIS
1738
1739 int UpnpUnSubscribe(UpnpClient_Handle Hnd, const Upnp_SID SubsId)
1740 {
1741     struct Handle_Info *SInfo = NULL;
1742     int RetVal;
1743
1744     if( UpnpSdkInit != 1 ) {
1745         return UPNP_E_FINISH;
1746     }
1747
1748     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1749         "Inside UpnpUnSubscribe \n" );
1750
1751     HandleReadLock();
1752     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1753         HandleUnlock();
1754         return UPNP_E_INVALID_HANDLE;
1755     }
1756     if( SubsId == NULL ) {
1757         HandleUnlock();
1758         return UPNP_E_INVALID_PARAM;
1759     }
1760     HandleUnlock();
1761     RetVal = genaUnSubscribe( Hnd, SubsId );
1762
1763     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1764         "Exiting UpnpUnSubscribe \n" );
1765
1766     return RetVal;
1767
1768 }  /****************** End of UpnpUnSubscribe  *********************/
1769 #endif // INCLUDE_CLIENT_APIS
1770
1771 #ifdef INCLUDE_CLIENT_APIS
1772
1773 /**************************************************************************
1774  * Function: UpnpUnSubscribeAsync 
1775  *
1776  *  Parameters: 
1777  *      IN UpnpClient_Handle Hnd: The handle of the subscribed control point. 
1778  *      IN Upnp_SID SubsId: The ID returned when the control point 
1779  *              subscribed to the service.
1780  *      IN Upnp_FunPtr Fun: Pointer to a callback function to be called
1781  *              when the operation is complete. 
1782  *      IN const void *Cookie:Pointer to user data to pass to the
1783  *              callback function when invoked.
1784  *
1785  *  Description:
1786  *      This function removes a subscription of a control point
1787  *  from a service previously subscribed to using UpnpSubscribe or
1788  *      UpnpSubscribeAsync,generating a callback when the operation is complete.
1789  *
1790  *  Return Values: int
1791  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1792  ***************************************************************************/
1793 int
1794 UpnpUnSubscribeAsync( IN UpnpClient_Handle Hnd,
1795                       IN Upnp_SID SubsId,
1796                       IN Upnp_FunPtr Fun,
1797                       IN const void *Cookie_const )
1798 {
1799     ThreadPoolJob job;
1800     struct Handle_Info *SInfo = NULL;
1801     struct UpnpNonblockParam *Param;
1802
1803     if( UpnpSdkInit != 1 ) {
1804         return UPNP_E_FINISH;
1805     }
1806
1807     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1808         "Inside UpnpUnSubscribeAsync \n" );
1809
1810     HandleReadLock();
1811     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1812         HandleUnlock();
1813         return UPNP_E_INVALID_HANDLE;
1814     }
1815     if( SubsId == NULL ) {
1816         HandleUnlock();
1817         return UPNP_E_INVALID_PARAM;
1818     }
1819     if( Fun == NULL ) {
1820         HandleUnlock();
1821         return UPNP_E_INVALID_PARAM;
1822     }
1823
1824     HandleUnlock();
1825     Param =
1826         ( struct UpnpNonblockParam * )
1827         malloc( sizeof( struct UpnpNonblockParam ) );
1828     if( Param == NULL )
1829         return UPNP_E_OUTOF_MEMORY;
1830
1831     Param->FunName = UNSUBSCRIBE;
1832     Param->Handle = Hnd;
1833     strcpy( Param->SubsId, SubsId );
1834     Param->Fun = Fun;
1835     Param->Cookie = ( void * )Cookie_const;
1836     TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
1837     TPJobSetFreeFunction( &job, ( free_routine ) free );
1838     TPJobSetPriority( &job, MED_PRIORITY );
1839     ThreadPoolAdd( &gSendThreadPool, &job, NULL );
1840
1841     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1842         "Exiting UpnpUnSubscribeAsync \n" );
1843
1844     return UPNP_E_SUCCESS;
1845
1846 }
1847 #endif // INCLUDE_CLIENT_APIS
1848
1849 #ifdef INCLUDE_CLIENT_APIS
1850
1851 int UpnpRenewSubscription(UpnpClient_Handle Hnd, int *TimeOut, const Upnp_SID SubsId)
1852 {
1853     struct Handle_Info *SInfo = NULL;
1854     int RetVal;
1855
1856     if( UpnpSdkInit != 1 ) {
1857         return UPNP_E_FINISH;
1858     }
1859
1860     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1861         "Inside UpnpRenewSubscription \n" );
1862
1863     HandleReadLock();
1864     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1865         HandleUnlock();
1866         return UPNP_E_INVALID_HANDLE;
1867     }
1868     if( TimeOut == NULL ) {
1869         HandleUnlock();
1870         return UPNP_E_INVALID_PARAM;
1871     }
1872     if( SubsId == NULL ) {
1873         HandleUnlock();
1874         return UPNP_E_INVALID_PARAM;
1875     }
1876     HandleUnlock();
1877     RetVal = genaRenewSubscription( Hnd, SubsId, TimeOut );
1878
1879     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1880         "Exiting UpnpRenewSubscription \n" );
1881
1882     return RetVal;
1883
1884 }  /****************** End of UpnpRenewSubscription  *********************/
1885 #endif // INCLUDE_CLIENT_APIS
1886
1887 #ifdef INCLUDE_CLIENT_APIS
1888
1889 /**************************************************************************
1890  * Function: UpnpRenewSubscriptionAsync 
1891  *
1892  * Parameters:  
1893  *      IN UpnpClient_Handle Hnd: The handle of the control point that 
1894  *              is renewing the subscription. 
1895  *      IN int TimeOut: The requested subscription time.  The 
1896  *              actual timeout value is returned when 
1897  *              the callback function is called. 
1898  *      IN Upnp_SID SubsId: The ID for the subscription to renew. 
1899  *      IN Upnp_FunPtr Fun: Pointer to a callback function to be 
1900  *              invoked when the renewal is complete. 
1901  *      IN const void *Cookie  : Pointer to user data passed 
1902  *              to the callback function when invoked.
1903  *
1904  * Description:
1905  *      This function renews a subscription that is about
1906  *      to expire, generating a callback when the operation is complete.
1907  *
1908  * Return Values: int
1909  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1910  ***************************************************************************/
1911 int
1912 UpnpRenewSubscriptionAsync( IN UpnpClient_Handle Hnd,
1913                             INOUT int TimeOut,
1914                             IN Upnp_SID SubsId,
1915                             IN Upnp_FunPtr Fun,
1916                             IN const void *Cookie_const )
1917 {
1918     ThreadPoolJob job;
1919     struct Handle_Info *SInfo = NULL;
1920     struct UpnpNonblockParam *Param;
1921
1922     if( UpnpSdkInit != 1 ) {
1923         return UPNP_E_FINISH;
1924     }
1925
1926     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1927         "Inside UpnpRenewSubscriptionAsync \n" );
1928     HandleReadLock();
1929     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
1930         HandleUnlock();
1931         return UPNP_E_INVALID_HANDLE;
1932     }
1933     if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) {
1934         HandleUnlock();
1935         return UPNP_E_INVALID_PARAM;
1936     }
1937     if( SubsId == NULL ) {
1938         HandleUnlock();
1939         return UPNP_E_INVALID_PARAM;
1940     }
1941     if( Fun == NULL ) {
1942         HandleUnlock();
1943         return UPNP_E_INVALID_PARAM;
1944     }
1945     HandleUnlock();
1946
1947     Param =
1948         ( struct UpnpNonblockParam * )
1949         malloc( sizeof( struct UpnpNonblockParam ) );
1950     if( Param == NULL ) {
1951         return UPNP_E_OUTOF_MEMORY;
1952     }
1953
1954     Param->FunName = RENEW;
1955     Param->Handle = Hnd;
1956     strcpy( Param->SubsId, SubsId );
1957     Param->Fun = Fun;
1958     Param->Cookie = ( void * )Cookie_const;
1959     Param->TimeOut = TimeOut;
1960
1961     TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
1962     TPJobSetFreeFunction( &job, ( free_routine ) free );
1963     TPJobSetPriority( &job, MED_PRIORITY );
1964     ThreadPoolAdd( &gSendThreadPool, &job, NULL );
1965
1966     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
1967         "Exiting UpnpRenewSubscriptionAsync \n" );
1968
1969     return UPNP_E_SUCCESS;
1970
1971 }  /****************** End of UpnpRenewSubscriptionAsync *******************/
1972 #endif // INCLUDE_CLIENT_APIS
1973
1974 #ifdef INCLUDE_DEVICE_APIS
1975
1976 /**************************************************************************
1977  * Function: UpnpNotify 
1978  *
1979  *  Parameters: 
1980  *      IN UpnpDevice_Handle: The handle to the device sending the event.
1981  *      IN const char *DevID: The device ID of the subdevice of the 
1982  *              service generating the event. 
1983  *      IN const char *ServID: The unique identifier of the service 
1984  *              generating the event. 
1985  *      IN const char **VarName: Pointer to an array of variables that 
1986  *              have changed.
1987  *      IN const char **NewVal: Pointer to an array of new values for 
1988  *              those variables. 
1989  *      IN int cVariables: The count of variables included in this 
1990  *              notification. 
1991  *
1992  * Description:
1993  *      This function sends out an event change notification to all
1994  *      control points subscribed to a particular service.  This function is
1995  *      synchronous and generates no callbacks.
1996  *
1997  * Return Values: int
1998  *      UPNP_E_SUCCESS if successful else sends appropriate error.
1999  ***************************************************************************/
2000 int
2001 UpnpNotify( IN UpnpDevice_Handle Hnd,
2002             IN const char *DevID_const,
2003             IN const char *ServName_const,
2004             IN const char **VarName_const,
2005             IN const char **NewVal_const,
2006             IN int cVariables )
2007 {
2008
2009     struct Handle_Info *SInfo = NULL;
2010     int retVal;
2011     char *DevID = ( char * )DevID_const;
2012     char *ServName = ( char * )ServName_const;
2013     char **VarName = ( char ** )VarName_const;
2014     char **NewVal = ( char ** )NewVal_const;
2015
2016     if( UpnpSdkInit != 1 ) {
2017         return UPNP_E_FINISH;
2018     }
2019
2020     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2021         "Inside UpnpNotify \n" );
2022
2023     HandleReadLock();
2024     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
2025         HandleUnlock();
2026         return UPNP_E_INVALID_HANDLE;
2027     }
2028     if( DevID == NULL ) {
2029         HandleUnlock();
2030         return UPNP_E_INVALID_PARAM;
2031     }
2032     if( ServName == NULL ) {
2033         HandleUnlock();
2034         return UPNP_E_INVALID_PARAM;
2035     }
2036     if( VarName == NULL || NewVal == NULL || cVariables < 0 ) {
2037         HandleUnlock();
2038         return UPNP_E_INVALID_PARAM;
2039     }
2040
2041     HandleUnlock();
2042     retVal =
2043         genaNotifyAll( Hnd, DevID, ServName, VarName, NewVal, cVariables );
2044
2045     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2046         "Exiting UpnpNotify \n" );
2047
2048     return retVal;
2049
2050 } /****************** End of UpnpNotify *********************/
2051
2052 /**************************************************************************
2053  * Function: UpnpNotifyExt 
2054  *
2055  * Parameters:  
2056  *      IN UpnpDevice_Handle: The handle to the device sending the 
2057  *              event.
2058  *      IN const char *DevID: The device ID of the subdevice of the 
2059  *              service generating the event.
2060  *      IN const char *ServID: The unique identifier of the service 
2061  *              generating the event. 
2062  *      IN IXML_Document *PropSet: The DOM document for the property set. 
2063  *              Property set documents must conform to the XML schema
2064  *              defined in section 4.3 of the Universal Plug and Play
2065  *              Device Architecture specification. 
2066  *
2067  * Description:
2068  *      This function is similar to UpnpNotify except that it takes
2069  *      a DOM document for the event rather than an array of strings. This 
2070  *      function is synchronous and generates no callbacks.
2071  *
2072  * Return Values: int
2073  *      UPNP_E_SUCCESS if successful else sends appropriate error.
2074  ***************************************************************************/
2075 int
2076 UpnpNotifyExt( IN UpnpDevice_Handle Hnd,
2077                IN const char *DevID_const,
2078                IN const char *ServName_const,
2079                IN IXML_Document * PropSet )
2080 {
2081
2082     struct Handle_Info *SInfo = NULL;
2083     int retVal;
2084     char *DevID = ( char * )DevID_const;
2085     char *ServName = ( char * )ServName_const;
2086
2087     if( UpnpSdkInit != 1 ) {
2088         return UPNP_E_FINISH;
2089     }
2090
2091     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2092         "Inside UpnpNotify \n" );
2093
2094     HandleReadLock();
2095     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
2096         HandleUnlock();
2097         return UPNP_E_INVALID_HANDLE;
2098     }
2099     if( DevID == NULL ) {
2100         HandleUnlock();
2101         return UPNP_E_INVALID_PARAM;
2102     }
2103     if( ServName == NULL ) {
2104         HandleUnlock();
2105         return UPNP_E_INVALID_PARAM;
2106     }
2107
2108     HandleUnlock();
2109     retVal = genaNotifyAllExt( Hnd, DevID, ServName, PropSet );
2110
2111     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2112         "Exiting UpnpNotify \n" );
2113
2114     return retVal;
2115
2116 }  /****************** End of UpnpNotify *********************/
2117
2118 #endif // INCLUDE_DEVICE_APIS
2119
2120 #ifdef INCLUDE_DEVICE_APIS
2121
2122 int UpnpAcceptSubscription(
2123         UpnpDevice_Handle Hnd,
2124         const char *DevID_const,
2125         const char *ServName_const,
2126         const char **VarName_const,
2127         const char **NewVal_const,
2128         int cVariables,
2129         const Upnp_SID SubsId)
2130 {
2131     struct Handle_Info *SInfo = NULL;
2132     int retVal;
2133     char *DevID = ( char * )DevID_const;
2134     char *ServName = ( char * )ServName_const;
2135     char **VarName = ( char ** )VarName_const;
2136     char **NewVal = ( char ** )NewVal_const;
2137
2138     if( UpnpSdkInit != 1 ) {
2139         return UPNP_E_FINISH;
2140     }
2141
2142     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2143         "Inside UpnpAcceptSubscription \n" );
2144
2145     HandleReadLock();
2146     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
2147         HandleUnlock();
2148         return UPNP_E_INVALID_HANDLE;
2149     }
2150     if( DevID == NULL ) {
2151         HandleUnlock();
2152         return UPNP_E_INVALID_PARAM;
2153     }
2154     if( ServName == NULL ) {
2155         HandleUnlock();
2156         return UPNP_E_INVALID_PARAM;
2157     }
2158     if( SubsId == NULL ) {
2159         HandleUnlock();
2160         return UPNP_E_INVALID_PARAM;
2161     }
2162     /* Now accepts an empty state list, so the code below is commented out */
2163 #if 0
2164     if( VarName == NULL || NewVal == NULL || cVariables < 0 ) {
2165         HandleUnlock();
2166         return UPNP_E_INVALID_PARAM;
2167     }
2168 #endif
2169
2170     HandleUnlock();
2171     retVal =
2172         genaInitNotify( Hnd, DevID, ServName, VarName, NewVal, cVariables,
2173                         SubsId );
2174
2175     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2176         "Exiting UpnpAcceptSubscription \n" );
2177     return retVal;
2178
2179 }  /***************** End of UpnpAcceptSubscription *********************/
2180
2181 /**************************************************************************
2182  * Function: UpnpAcceptSubscriptionExt 
2183  *
2184  * Parameters:  
2185  *      IN UpnpDevice_Handle Hnd: The handle of the device. 
2186  *      IN const char *DevID: The device ID of the subdevice of the 
2187  *              service generating the event. 
2188  *      IN const char *ServID: The unique service identifier of the service 
2189  *              generating the event. 
2190  *      IN IXML_Document *PropSet: The DOM document for the property set. 
2191  *              Property set documents must conform to the XML schema
2192  *              defined in section 4.3 of the Universal Plug and Play
2193  *              Device Architecture specification. 
2194  *      IN Upnp_SID SubsId: The subscription ID of the newly
2195  *              registered control point. 
2196  *
2197  * Description:
2198  *      This function is similar to UpnpAcceptSubscription except that it
2199  *      takes a DOM document for the variables to event rather than an array
2200  *      of strings. This function is sychronous and generates no callbacks.
2201  *
2202  * Return Values: int
2203  *      UPNP_E_SUCCESS if successful else sends appropriate error.
2204  ***************************************************************************/
2205 int
2206 UpnpAcceptSubscriptionExt( IN UpnpDevice_Handle Hnd,
2207                            IN const char *DevID_const,
2208                            IN const char *ServName_const,
2209                            IN IXML_Document * PropSet,
2210                            IN Upnp_SID SubsId )
2211 {
2212     struct Handle_Info *SInfo = NULL;
2213     int retVal;
2214     char *DevID = ( char * )DevID_const;
2215     char *ServName = ( char * )ServName_const;
2216
2217     if( UpnpSdkInit != 1 ) {
2218         return UPNP_E_FINISH;
2219     }
2220
2221     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2222         "Inside UpnpAcceptSubscription \n" );
2223
2224     HandleReadLock();
2225     if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
2226         HandleUnlock();
2227         return UPNP_E_INVALID_HANDLE;
2228     }
2229     if( DevID == NULL ) {
2230         HandleUnlock();
2231         return UPNP_E_INVALID_PARAM;
2232     }
2233     if( ServName == NULL ) {
2234         HandleUnlock();
2235         return UPNP_E_INVALID_PARAM;
2236     }
2237     if( SubsId == NULL ) {
2238         HandleUnlock();
2239         return UPNP_E_INVALID_PARAM;
2240     }
2241         /* Now accepts an empty state list, so the code below is commented out */
2242 #if 0
2243     if( PropSet == NULL ) {
2244         HandleUnlock();
2245         return UPNP_E_INVALID_PARAM;
2246     }
2247 #endif
2248
2249     HandleUnlock();
2250     retVal = genaInitNotifyExt( Hnd, DevID, ServName, PropSet, SubsId );
2251
2252     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2253         "Exiting UpnpAcceptSubscription \n" );
2254
2255     return retVal;
2256
2257 }  /****************** End of UpnpAcceptSubscription *********************/
2258
2259 #endif // INCLUDE_DEVICE_APIS
2260 #endif // EXCLUDE_GENA == 0
2261
2262 //---------------------------------------------------------------------------
2263 //
2264 //                                   SOAP interface 
2265 //
2266 //---------------------------------------------------------------------------
2267 #if EXCLUDE_SOAP == 0
2268 #ifdef INCLUDE_CLIENT_APIS
2269
2270 /**************************************************************************
2271  * Function: UpnpSendAction 
2272  *
2273  * Parameters:  
2274  *      IN UpnpClient_Handle Hnd: The handle of the control point 
2275  *              sending the action. 
2276  *      IN const char *ActionURL: The action URL of the service. 
2277  *      IN const char *ServiceType: The type of the service. 
2278  *      IN const char *DevUDN: This parameter is ignored. 
2279  *      IN IXML_Document *Action: The DOM document for the action. 
2280  *      OUT IXML_Document **RespNode: The DOM document for the response 
2281  *              to the action.  The UPnP Library allocates this document
2282  *              and the caller needs to free it.  
2283  *  
2284  * Description:
2285  *      This function sends a message to change a state variable in a service.
2286  *      This is a synchronous call that does not return until the action is
2287  *      complete.
2288  * 
2289  *      Note that a positive return value indicates a SOAP-protocol error code.
2290  *      In this case,  the error description can be retrieved from RespNode.
2291  *      A negative return value indicates a UPnP Library error.
2292  *
2293  * Return Values: int
2294  *      UPNP_E_SUCCESS if successful else sends appropriate error.
2295  ***************************************************************************/
2296 int
2297 UpnpSendAction( IN UpnpClient_Handle Hnd,
2298                 IN const char *ActionURL_const,
2299                 IN const char *ServiceType_const,
2300                 IN const char *DevUDN_const,
2301                 IN IXML_Document * Action,
2302                 OUT IXML_Document ** RespNodePtr )
2303 {
2304     struct Handle_Info *SInfo = NULL;
2305     int retVal = 0;
2306     char *ActionURL = ( char * )ActionURL_const;
2307     char *ServiceType = ( char * )ServiceType_const;
2308
2309     //char *DevUDN = (char *)DevUDN_const;  // udn not used?
2310
2311     if( UpnpSdkInit != 1 ) {
2312         return UPNP_E_FINISH;
2313     }
2314
2315     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2316         "Inside UpnpSendAction \n" );
2317     if(DevUDN_const !=NULL) {
2318         UpnpPrintf(UPNP_ALL,API,__FILE__,__LINE__,"non NULL DevUDN is ignored\n");
2319     }
2320     DevUDN_const = NULL;
2321
2322     HandleReadLock();
2323     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
2324         HandleUnlock();
2325         return UPNP_E_INVALID_HANDLE;
2326     }
2327     HandleUnlock();
2328
2329     if( ActionURL == NULL ) {
2330         return UPNP_E_INVALID_PARAM;
2331     }
2332
2333     if( ServiceType == NULL || Action == NULL || RespNodePtr == NULL
2334         || DevUDN_const != NULL ) {
2335
2336         return UPNP_E_INVALID_PARAM;
2337     }
2338
2339     retVal = SoapSendAction( ActionURL, ServiceType, Action, RespNodePtr );
2340
2341     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2342         "Exiting UpnpSendAction \n" );
2343
2344     return retVal;
2345
2346 }  /****************** End of UpnpSendAction *********************/
2347
2348 /**************************************************************************
2349  * Function: UpnpSendActionEx 
2350  *
2351  * Parameters:  
2352  *      IN UpnpClient_Handle Hnd: The handle of the control point sending
2353  *              the action. 
2354  *      IN const char *ActionURL_const: The action URL of the service. 
2355  *      IN const char *ServiceType_const: The type of the service. 
2356  *      IN const char *DevUDN_const: This parameter is ignored. 
2357  *      IN IXML_Document *Header: The DOM document for the SOAP header. 
2358  *              This may be NULL if the header is not required. 
2359  *      IN IXML_Document *Action:   The DOM document for the action. 
2360  *      OUT IXML_Document **RespNodePtr: The DOM document for the response to
2361  *              the action.  The UPnP library allocates this document and the
2362  *              caller needs to free it.
2363  *  
2364  * Description:
2365  *      this function sends a message to change a state variable in a 
2366  *      service. This is a synchronous call that does not return until the 
2367  *      action is complete.
2368  *
2369  *      Note that a positive return value indicates a SOAP-protocol error code.
2370  *      In this case,  the error description can be retrieved from {\bf RespNode}.
2371  *      A negative return value indicates a UPnP Library error.
2372  *
2373  * Return Values: int
2374  *      UPNP_E_SUCCESS if successful else sends appropriate error.
2375  ***************************************************************************/
2376 int
2377 UpnpSendActionEx( IN UpnpClient_Handle Hnd,
2378                   IN const char *ActionURL_const,
2379                   IN const char *ServiceType_const,
2380                   IN const char *DevUDN_const,
2381                   IN IXML_Document * Header,
2382                   IN IXML_Document * Action,
2383                   OUT IXML_Document ** RespNodePtr )
2384 {
2385
2386     struct Handle_Info *SInfo = NULL;
2387     int retVal = 0;
2388     char *ActionURL = ( char * )ActionURL_const;
2389     char *ServiceType = ( char * )ServiceType_const;
2390
2391     //char *DevUDN = (char *)DevUDN_const;  // udn not used?
2392
2393     if( UpnpSdkInit != 1 ) {
2394         return UPNP_E_FINISH;
2395     }
2396
2397     UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
2398         "Inside UpnpSendActionEx \n" );
2399
2400     if( Header == NULL ) {
2401         retVal = UpnpSendAction( Hnd, ActionURL_const, ServiceType_const,
2402                                  DevUDN_const, Action, RespNodePtr );
2403         return retVal;
2404     }
2405
2406     HandleReadLock();
2407     if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
2408         HandleUnlock();
2409         return UPNP_E_INVALID_HANDLE;
2410     }
2411     HandleUnlock();
2412
2413     if( ActionURL == NULL ) {
2414         return UPNP_E_INVALID_PARAM;
2415     }