diff --git a/ChangeLog b/ChangeLog index 9dbc828..f4c13a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,48 @@ Version 1.6.7 ******************************************************************************* +2010-03-27 Marcelo Jimenez + Backport of svn revision 527: + * Added API to ithread, created the following functions: + - int ithread_initialize_library(void); + - int ithread_cleanup_library(void); + - int ithread_initialize_thread(void); + - int ithread_cleanup_thread(void); + * SF Bug Tracker [ 2876374 ] Access Violation when compiling with Visual Studio 2008 + Submitted: Stulle ( stulleamgym ) - 2009-10-10 19:05 + + Hi, + + I am one of the devs of the MorphXT project and I use this lib in some + other of my projects, too. When I tried to upgrade the lib earlier for one + of my projects I had to realise that something did not work at first and + while most of the things were reasonably ease to be fixed. Now, the last + thing I encountered was not so easy to fix and I am uncertain if my fix is + any good so I'll just post it here and wait for some comments. + + The problem was that I got an Access Violation when calling "UpnpInit". It + would call "ithread_rwlock_init(&GlobalHndRWLock, NULL)" which eventually + led to calling "pthread_cond_init" and I got the error notice at + "EnterCriticalSection (&ptw32_cond_list_lock);". It appeared that + "ptw32_cond_list_lock" was NULL. Now, I found two ways to fix this. Firstly + moving the whole block after at least one of the "ThreadPoolInit" calls + will fix the issue. Secondly, you could add: + #ifdef WIN32 + #ifdef PTW32_STATIC_LIB + // to get the following working we need this... is it a good patch or + not... I do not know! + pthread_win32_process_attach_np(); + #endif + #endif + right before "ithread_rwlock_init(&GlobalHndRWLock, NULL)". + + Just so you know, I am using libupnp 1.6.6 and libpthreads 2.8.0 and both + are linked static into the binaries. I am currently using Visual Studio + 2008 for development with Windows being the target OS. Any comment at your + end? + + Regards, Stulle + 2010-03-27 Marcelo Jimenez * SF Patch Tracker [ 2836704 ] Patch for Solaris10 compilation and usage. Submitted By: zephyrus ( zephyrus00jp ) diff --git a/configure.ac b/configure.ac index bbc732f..a29c5c1 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ # # Process this file with autoconf to produce a configure script. # -# (C) Copyright 2005-2007 Rémi Turboult +# (C) Copyright 2005-2007 Rémi Turboult # AC_PREREQ(2.60) @@ -147,13 +147,21 @@ dnl ############################################################################ dnl # Release 1.6.7: dnl # "current:revision:age" dnl # +dnl # - Code has changed in upnp +dnl # revision: 5 -> 6 +dnl # - Code has changed in threadutil +dnl # revision: 3 -> 4 +dnl # - Interfaces have been changed, added and removed in upnp +dnl # current: 4 -> 5 +dnl # revision: 4 -> 0 +dnl # dnl #AC_SUBST([LT_VERSION_IXML], [2:4:0]) -dnl #AC_SUBST([LT_VERSION_THREADUTIL], [4:3:2]) +dnl #AC_SUBST([LT_VERSION_THREADUTIL], [5:0:2]) dnl #AC_SUBST([LT_VERSION_UPNP], [3:5:0]) dnl # dnl ############################################################################ AC_SUBST([LT_VERSION_IXML], [2:4:0]) -AC_SUBST([LT_VERSION_THREADUTIL], [4:3:2]) +AC_SUBST([LT_VERSION_THREADUTIL], [5:0:2]) AC_SUBST([LT_VERSION_UPNP], [3:5:0]) dnl ############################################################################ dnl # Repeating the algorithm to place it closer to the modificatin place: @@ -333,9 +341,26 @@ AC_DEFINE([_FILE_OFFSET_BITS], [64], [File Offset size]) # -# Checks for header files +# Are we targetting Win32? +# +AC_MSG_CHECKING([for Win32]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#ifdef WIN32 + #error Yup +#endif +],[])], [ac_cv_win32="no"], [ac_cv_win32="yes"]) +if test "$ac_cv_win32" = "yes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + + +# +# Checks for header files (which aren't needed on Win32) # AC_HEADER_STDC +if test "$ac_cv_win32" = "no"; then # libupnp code doesn't use autoconf variables yet, # so just abort if a header file is not found. AC_CHECK_HEADERS( @@ -356,13 +381,38 @@ AC_CHECK_HEADERS( ], [], [AC_MSG_ERROR([required header file missing])]) +fi # # Checks for typedefs, structures, and compiler characteristics # AC_C_CONST -TYPE_SOCKLEN_T + +# The test for socklen_t was getting it wrong when it exists but is in ws2tcpip.h, +# so we use a new test. +#TYPE_SOCKLEN_T + +AC_CHECK_HEADERS([sys/types.h sys/socket.h ws2tcpip.h]) +AC_MSG_CHECKING(for socklen_t) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#ifdef HAVE_SYS_TYPES_H + #include +#endif +#ifdef HAVE_SYS_SOCKET_H + #include +#endif +#ifdef HAVE_WS2TCPIP_H + #include +#endif +],[ socklen_t t = 0; return t; ]) +],[ac_cv_socklen_t="yes"],[ac_cv_socklen_t="no"]) +if test "$ac_cv_socklen_t" = "yes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no, using int]) + AC_DEFINE(socklen_t, int, [Type for storing the length of struct sockaddr]) +fi # diff --git a/threadutil/inc/ithread.h b/threadutil/inc/ithread.h index 7d2aa28..4488e70 100644 --- a/threadutil/inc/ithread.h +++ b/threadutil/inc/ithread.h @@ -30,19 +30,21 @@ ******************************************************************************/ -#ifndef ITHREADH -#define ITHREADH +#ifndef ITHREAD_H +#define ITHREAD_H /*! * \file */ -#if ! defined(WIN32) + +#if !defined(WIN32) #include #endif -#include "UpnpGlobal.h" /* For EXPORT_SPEC */ + +#include "UpnpGlobal.h" /* For UPNP_INLINE, EXPORT_SPEC */ #ifdef __cplusplus @@ -92,7 +94,8 @@ extern "C" { * typedef to pthread_t. * Internal Use Only. ***************************************************************************/ -typedef pthread_t ithread_t; +typedef pthread_t ithread_t; + /**************************************************************************** * Name: ithread_attr_t @@ -112,7 +115,7 @@ typedef pthread_attr_t ithread_attr_t; * Thread start routine * Internal Use Only. ***************************************************************************/ -typedef void * (*start_routine) (void *arg); +typedef void *(*start_routine)(void *arg); /**************************************************************************** @@ -179,7 +182,96 @@ typedef pthread_rwlockattr_t ithread_rwlockattr_t; * typedef to pthread_rwlock_t * Internal Use Only ***************************************************************************/ -typedef pthread_rwlock_t ithread_rwlock_t; +typedef pthread_rwlock_t ithread_rwlock_t; + + +/**************************************************************************** + * Function: ithread_initialize_library + * + * Description: + * Initializes the library. Does nothing in all implementations, except + * when statically linked for WIN32. + * Parameters: + * none. + * Returns: + * 0 on success, Nonzero on failure. + ***************************************************************************/ +static UPNP_INLINE int ithread_initialize_library(void) { + int ret = 0; + +#if defined(WIN32) && defined(PTW32_STATIC_LIB) + ret = !pthread_win32_process_attach_np(); +#endif + + return ret; +} + + +/**************************************************************************** + * Function: ithread_cleanup_library + * + * Description: + * Clean up library resources. Does nothing in all implementations, except + * when statically linked for WIN32. + * Parameters: + * none. + * Returns: + * 0 on success, Nonzero on failure. + ***************************************************************************/ +static UPNP_INLINE int ithread_cleanup_library(void) { + int ret = 0; + +#if defined(WIN32) && defined(PTW32_STATIC_LIB) + ret = !pthread_win32_process_detach_np(); +#endif + + return ret; +} + + +/**************************************************************************** + * Function: ithread_initialize_thread + * + * Description: + * Initializes the thread. Does nothing in all implementations, except + * when statically linked for WIN32. + * Parameters: + * none. + * Returns: + * 0 on success, Nonzero on failure. + ***************************************************************************/ +static UPNP_INLINE int ithread_initialize_thread(void) { + int ret = 0; + +#if defined(WIN32) && defined(PTW32_STATIC_LIB) + ret = !pthread_win32_thread_attach_np(); +#endif + + return ret; +} + + +/**************************************************************************** + * Function: ithread_cleanup_thread + * + * Description: + * Clean up thread resources. Does nothing in all implementations, except + * when statically linked for WIN32. + * Parameters: + * none. + * Returns: + * 0 on success, Nonzero on failure. + ***************************************************************************/ +static UPNP_INLINE int ithread_cleanup_thread(void) { + int ret = 0; + +#if defined(WIN32) && defined(PTW32_STATIC_LIB) + ret = !pthread_win32_thread_detach_np(); +#endif + + return ret; +} + /**************************************************************************** * Function: ithread_mutexattr_init @@ -420,8 +512,8 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Must be called before use. * * Parameters: - * ithread_rwlock_t * rwlock (must be valid non NULL pointer to pthread_rwlock_t) - * const ithread_rwlockattr_t * rwlock_attr + * ithread_rwlock_t *rwlock (must be valid non NULL pointer to pthread_rwlock_t) + * const ithread_rwlockattr_t *rwlock_attr * Returns: * 0 on success, Nonzero on failure. * Always returns 0. @@ -436,7 +528,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Description: * Locks rwlock for reading. * Parameters: - * ithread_rwlock_t * rwlock (must be valid non NULL pointer to pthread_rwlock_t) + * ithread_rwlock_t *rwlock (must be valid non NULL pointer to pthread_rwlock_t) * rwlock must be initialized. * * Returns: @@ -453,7 +545,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Description: * Locks rwlock for writting. * Parameters: - * ithread_rwlock_t * rwlock (must be valid non NULL pointer to pthread_rwlock_t) + * ithread_rwlock_t *rwlock (must be valid non NULL pointer to pthread_rwlock_t) * rwlock must be initialized. * * Returns: @@ -471,7 +563,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Unlocks rwlock. * * Parameters: - * ithread_rwlock_t * rwlock (must be valid non NULL pointer to pthread_rwlock_t) + * ithread_rwlock_t *rwlock (must be valid non NULL pointer to pthread_rwlock_t) * rwlock must be initialized. * * Returns: @@ -491,7 +583,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * rwlock is only destroyed when there are no longer any threads waiting on it. * rwlock cannot be destroyed if it is locked. * Parameters: - * ithread_rwlock_t * rwlock (must be valid non NULL pointer to pthread_rwlock_t) + * ithread_rwlock_t *rwlock (must be valid non NULL pointer to pthread_rwlock_t) * rwlock must be initialized. * Returns: * 0 on success. Nonzero on failure. @@ -508,8 +600,8 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Initializes condition variable. * Must be called before use. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to pthread_cond_t) - * const ithread_condattr_t * cond_attr (ignored) + * ithread_cond_t *cond (must be valid non NULL pointer to pthread_cond_t) + * const ithread_condattr_t *cond_attr (ignored) * Returns: * 0 on success, Nonzero on failure. * See man page for pthread_cond_init @@ -517,7 +609,6 @@ typedef pthread_rwlock_t ithread_rwlock_t; #define ithread_cond_init pthread_cond_init - /**************************************************************************** * Function: ithread_cond_signal * @@ -525,7 +616,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Wakes up exactly one thread waiting on condition. * Associated mutex MUST be locked by thread before entering this call. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to + * ithread_cond_t *cond (must be valid non NULL pointer to * ithread_cond_t) * cond must be initialized * Returns: @@ -542,7 +633,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Wakes up all threads waiting on condition. * Associated mutex MUST be locked by thread before entering this call. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to + * ithread_cond_t *cond (must be valid non NULL pointer to * ithread_cond_t) * cond must be initialized * Returns: @@ -560,7 +651,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Associated mutex MUST be locked by thread before entering this call. * Mutex is reacquired when call returns. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to + * ithread_cond_t *cond (must be valid non NULL pointer to * ithread_cond_t) * cond must be initialized * ithread_mutex_t *mutex (must be valid non NULL pointer to @@ -576,23 +667,19 @@ typedef pthread_rwlock_t ithread_rwlock_t; /**************************************************************************** * Function: pthread_cond_timedwait * - * Description: - * Atomically releases the associated mutex and waits on the condition. - * If the condition is not signaled in the specified time - * than the - * call times out and returns. - * Associated mutex MUST be locked by thread before entering - * this call. - * Mutex is reacquired when call returns. + * Description: + * Atomically releases the associated mutex and waits on the + * condition. + * If the condition is not signaled in the specified time than the + * call times out and returns. + * Associated mutex MUST be locked by thread before entering this call. + * Mutex is reacquired when call returns. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to - * ithread_cond_t) - * cond must be initialized - * ithread_mutex_t *mutex (must be valid non NULL pointer to - * ithread_mutex_t) - * Mutex must be locked. - * const struct timespec *abstime (absolute time, measured - * from Jan 1, 1970) + * ithread_cond_t *cond (must be valid non NULL pointer to ithread_cond_t) + * cond must be initialized + * ithread_mutex_t *mutex (must be valid non NULL pointer to ithread_mutex_t) + * Mutex must be locked. + * const struct timespec *abstime (absolute time, measured from Jan 1, 1970) * Returns: * 0 on success. ETIMEDOUT on timeout. Nonzero on failure. * See man page for pthread_cond_timedwait @@ -608,7 +695,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; * Releases any resources held by the condition variable. * Condition variable can no longer be used after this call. * Parameters: - * ithread_cond_t * cond (must be valid non NULL pointer to + * ithread_cond_t *cond (must be valid non NULL pointer to * ithread_cond_t) * cond must be initialized. * Returns: @@ -664,6 +751,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; ***************************************************************************/ #define ithread_exit pthread_exit + /**************************************************************************** * Function: ithread_get_current_thread_id * @@ -687,6 +775,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; ***************************************************************************/ #define ithread_self pthread_self + /**************************************************************************** * Function: ithread_detach * @@ -700,6 +789,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; ***************************************************************************/ #define ithread_detach pthread_detach + /**************************************************************************** * Function: ithread_join * @@ -719,7 +809,6 @@ typedef pthread_rwlock_t ithread_rwlock_t; #define ithread_join pthread_join - /**************************************************************************** * Function: isleep * @@ -739,6 +828,7 @@ typedef pthread_rwlock_t ithread_rwlock_t; #define isleep sleep #endif + /**************************************************************************** * Function: isleep * @@ -764,9 +854,11 @@ typedef pthread_rwlock_t ithread_rwlock_t; EXPORT_SPEC int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind); #endif + #ifdef __cplusplus } #endif -#endif /* ITHREADH */ + +#endif /* ITHREAD_H */ diff --git a/threadutil/src/ThreadPool.c b/threadutil/src/ThreadPool.c index 35ceb7d..d44a39b 100644 --- a/threadutil/src/ThreadPool.c +++ b/threadutil/src/ThreadPool.c @@ -35,7 +35,7 @@ */ -#if ! defined(WIN32) +#if !defined(WIN32) #include #endif @@ -68,9 +68,6 @@ static unsigned long DiffMillis(struct timeval *time1, struct timeval *time2) { double temp = 0; - assert(time1 != NULL); - assert(time2 != NULL); - temp = time1->tv_sec - time2->tv_sec; /* convert to milliseconds */ temp *= 1000; @@ -94,8 +91,6 @@ static unsigned long DiffMillis(struct timeval *time1, struct timeval *time2) *****************************************************************************/ static void StatsInit(ThreadPoolStats *stats) { - assert(stats != NULL); - stats->totalIdleTime = 0; stats->totalJobsHQ = 0; stats->totalJobsLQ = 0; @@ -202,11 +197,8 @@ static UPNP_INLINE time_t StatsTime(time_t *t) { return 0; } *****************************************************************************/ static int CmpThreadPoolJob(void *jobA, void *jobB) { - ThreadPoolJob *a = (ThreadPoolJob *) jobA; - ThreadPoolJob *b = (ThreadPoolJob *) jobB; - - assert(jobA != NULL); - assert(jobB != NULL); + ThreadPoolJob *a = (ThreadPoolJob *)jobA; + ThreadPoolJob *b = (ThreadPoolJob *)jobB; return a->jobId == b->jobId; } @@ -221,8 +213,6 @@ static int CmpThreadPoolJob(void *jobA, void *jobB) *****************************************************************************/ static void FreeThreadPoolJob(ThreadPool *tp, ThreadPoolJob *tpj) { - assert(tp != NULL); - FreeListFree(&tp->jobFreeList, tpj); } @@ -340,8 +330,6 @@ static void BumpPriority(ThreadPool *tp) unsigned long diffTime = 0; ThreadPoolJob *tempJob = NULL; - assert(tp != NULL); - gettimeofday(&now, NULL); while (!done) { if (tp->medJobQ.size) { @@ -389,12 +377,9 @@ static void SetRelTimeout( struct timespec *time, int relMillis ) int sec = relMillis / 1000; int milliSeconds = relMillis % 1000; - assert( time != NULL ); - - gettimeofday( &now, NULL ); - + gettimeofday(&now, NULL); time->tv_sec = now.tv_sec + sec; - time->tv_nsec = ( (now.tv_usec/1000) + milliSeconds ) * 1000000; + time->tv_nsec = (now.tv_usec / 1000 + milliSeconds) * 1000000; } /**************************************************************************** @@ -413,17 +398,20 @@ static void SetSeed() gettimeofday(&t, NULL); #if defined(WIN32) - srand( ( unsigned int )t.tv_usec + (unsigned int)ithread_get_current_thread_id().p ); + srand((unsigned int)t.tv_usec + (unsigned int)ithread_get_current_thread_id().p); #elif defined(BSD) || defined(__OSX__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - srand( ( unsigned int )t.tv_usec + (unsigned int)ithread_get_current_thread_id() ); + srand((unsigned int)t.tv_usec + (unsigned int)ithread_get_current_thread_id()); #elif defined(__linux__) || defined(__sun) || defined(__CYGWIN__) || defined(__GLIBC__) - srand( ( unsigned int )t.tv_usec + ithread_get_current_thread_id() ); + srand((unsigned int)t.tv_usec + ithread_get_current_thread_id()); #else { - volatile union { volatile pthread_t tid; volatile unsigned i; } idu; + volatile union { + volatile pthread_t tid; + volatile unsigned i; + } idu; idu.tid = ithread_get_current_thread_id(); - srand( ( unsigned int )t.millitm + idu.i ); + srand((unsigned int)t.millitm + idu.i); } #endif } @@ -442,7 +430,7 @@ static void SetSeed() * Parameters: * void * arg -> is cast to ThreadPool * *****************************************************************************/ -static void *WorkerThread( void *arg ) +static void *WorkerThread(void *arg) { time_t start = 0; @@ -452,28 +440,23 @@ static void *WorkerThread( void *arg ) struct timespec timeout; int retCode = 0; int persistent = -1; - ThreadPool *tp = ( ThreadPool *) arg; - // allow static linking -#ifdef WIN32 -#ifdef PTW32_STATIC_LIB - pthread_win32_thread_attach_np(); -#endif -#endif - assert( tp != NULL ); + ThreadPool *tp = (ThreadPool *) arg; - // Increment total thread count - ithread_mutex_lock( &tp->mutex ); + ithread_initialize_thread(); + + /* Increment total thread count */ + ithread_mutex_lock(&tp->mutex); tp->totalThreads++; - ithread_cond_broadcast( &tp->start_and_shutdown ); - ithread_mutex_unlock( &tp->mutex ); + ithread_cond_broadcast(&tp->start_and_shutdown); + ithread_mutex_unlock(&tp->mutex); SetSeed(); - StatsTime( &start ); - while( 1 ) { - ithread_mutex_lock( &tp->mutex ); - if( job ) { + StatsTime(&start); + while (1) { + ithread_mutex_lock(&tp->mutex); + if (job) { tp->busyThreads--; - FreeThreadPoolJob( tp, job ); + FreeThreadPoolJob(tp, job); job = NULL; } retCode = 0; @@ -482,126 +465,100 @@ static void *WorkerThread( void *arg ) tp->stats.totalWorkTime += ( StatsTime( NULL ) - start ); // work time StatsTime( &start ); // idle time - if( persistent == 1 ) { - // Persistent thread - // becomes a regular thread + if (persistent == 0) { + tp->stats.workerThreads--; + } else if (persistent == 1) { + /* Persistent thread becomes a regular thread */ tp->persistentThreads--; } - if( persistent == 0 ) { - tp->stats.workerThreads--; - } - - // Check for a job or shutdown - while( tp->lowJobQ.size == 0 && + /* Check for a job or shutdown */ + while (tp->lowJobQ.size == 0 && tp->medJobQ.size == 0 && tp->highJobQ.size == 0 && - !tp->persistentJob && - !tp->shutdown ) { - // If wait timed out - // and we currently have more than the - // min threads, or if we have more than the max threads - // (only possible if the attributes have been reset) - // let this thread die. - if( ( retCode == ETIMEDOUT && - tp->totalThreads > tp->attr.minThreads ) || - ( tp->attr.maxThreads != -1 && - tp->totalThreads > tp->attr.maxThreads ) ) { + !tp->persistentJob && !tp->shutdown) { + /* If wait timed out and we currently have more than the + * min threads, or if we have more than the max threads + * (only possible if the attributes have been reset) + * let this thread die. */ + if ((retCode == ETIMEDOUT && + tp->totalThreads > tp->attr.minThreads) || + (tp->attr.maxThreads != -1 && + tp->totalThreads > tp->attr.maxThreads)) { tp->stats.idleThreads--; - tp->totalThreads--; - ithread_cond_broadcast( &tp->start_and_shutdown ); - ithread_mutex_unlock( &tp->mutex ); -#ifdef WIN32 -#ifdef PTW32_STATIC_LIB - // allow static linking - pthread_win32_thread_detach_np (); -#endif -#endif - return NULL; + goto exit_function; } - SetRelTimeout( &timeout, tp->attr.maxIdleTime ); + SetRelTimeout(&timeout, tp->attr.maxIdleTime); - // wait for a job up to the specified max time + /* wait for a job up to the specified max time */ retCode = ithread_cond_timedwait( - &tp->condition, &tp->mutex, &timeout ); + &tp->condition, &tp->mutex, &timeout); } - tp->stats.idleThreads--; - tp->stats.totalIdleTime += ( StatsTime( NULL ) - start ); // idle time - StatsTime( &start ); // work time - - // bump priority of starved jobs - BumpPriority( tp ); - - // if shutdown then stop - if( tp->shutdown ) { - tp->totalThreads--; - ithread_cond_broadcast( &tp->start_and_shutdown ); - ithread_mutex_unlock( &tp->mutex ); -#ifdef WIN32 -#ifdef PTW32_STATIC_LIB - // allow static linking - pthread_win32_thread_detach_np (); -#endif -#endif - return NULL; + /* idle time */ + tp->stats.totalIdleTime += StatsTime(NULL) - start; + /* work time */ + StatsTime(&start); + /* bump priority of starved jobs */ + BumpPriority(tp); + /* if shutdown then stop */ + if (tp->shutdown) { + goto exit_function; } else { - // Pick up persistent job if available - if( tp->persistentJob ) { + /* Pick up persistent job if available */ + if (tp->persistentJob) { job = tp->persistentJob; tp->persistentJob = NULL; tp->persistentThreads++; persistent = 1; - ithread_cond_broadcast( &tp->start_and_shutdown ); + ithread_cond_broadcast(&tp->start_and_shutdown); } else { tp->stats.workerThreads++; persistent = 0; - // Pick the highest priority job - if( tp->highJobQ.size > 0 ) { - head = ListHead( &tp->highJobQ ); - job = ( ThreadPoolJob *) head->item; - CalcWaitTime( tp, HIGH_PRIORITY, job ); - ListDelNode( &tp->highJobQ, head, 0 ); - } else if( tp->medJobQ.size > 0 ) { - head = ListHead( &tp->medJobQ ); - job = ( ThreadPoolJob *) head->item; - CalcWaitTime( tp, MED_PRIORITY, job ); - ListDelNode( &tp->medJobQ, head, 0 ); - } else if( tp->lowJobQ.size > 0 ) { - head = ListHead( &tp->lowJobQ ); - job = ( ThreadPoolJob *) head->item; - CalcWaitTime( tp, LOW_PRIORITY, job ); - ListDelNode( &tp->lowJobQ, head, 0 ); + /* Pick the highest priority job */ + if (tp->highJobQ.size > 0) { + head = ListHead(&tp->highJobQ); + job = (ThreadPoolJob *) head->item; + CalcWaitTime(tp, HIGH_PRIORITY, job); + ListDelNode(&tp->highJobQ, head, 0); + } else if (tp->medJobQ.size > 0) { + head = ListHead(&tp->medJobQ); + job = (ThreadPoolJob *) head->item; + CalcWaitTime(tp, MED_PRIORITY, job); + ListDelNode(&tp->medJobQ, head, 0); + } else if (tp->lowJobQ.size > 0) { + head = ListHead(&tp->lowJobQ); + job = (ThreadPoolJob *) head->item; + CalcWaitTime(tp, LOW_PRIORITY, job); + ListDelNode(&tp->lowJobQ, head, 0); } else { - // Should never get here - assert( 0 ); + /* Should never get here */ tp->stats.workerThreads--; - tp->totalThreads--; - ithread_cond_broadcast( &tp->start_and_shutdown ); - ithread_mutex_unlock( &tp->mutex ); - - return NULL; + goto exit_function; } } } tp->busyThreads++; - ithread_mutex_unlock( &tp->mutex ); + ithread_mutex_unlock(&tp->mutex); - if( SetPriority( job->priority ) != 0 ) { - // In the future can log - // info + /* In the future can log info */ + if (SetPriority(job->priority) != 0) { } else { - // In the future can log - // info } - - // run the job - job->func( job->arg ); - - // return to Normal - SetPriority( DEFAULT_PRIORITY ); + /* run the job */ + job->func(job->arg); + /* return to Normal */ + SetPriority(DEFAULT_PRIORITY); } + +exit_function: + tp->totalThreads--; + ithread_cond_broadcast(&tp->start_and_shutdown); + ithread_mutex_unlock(&tp->mutex); + ithread_cleanup_thread(); + + return NULL; } /**************************************************************************** @@ -617,18 +574,15 @@ static void *WorkerThread( void *arg ) * Returns: * ThreadPoolJob *on success, NULL on failure. *****************************************************************************/ -static ThreadPoolJob *CreateThreadPoolJob( ThreadPoolJob *job, int id, ThreadPool *tp ) +static ThreadPoolJob *CreateThreadPoolJob(ThreadPoolJob *job, int id, ThreadPool *tp) { ThreadPoolJob *newJob = NULL; - assert( job != NULL ); - assert( tp != NULL ); - - newJob = (ThreadPoolJob *)FreeListAlloc( &tp->jobFreeList ); - if( newJob ) { + newJob = (ThreadPoolJob *)FreeListAlloc(&tp->jobFreeList); + if (newJob) { *newJob = *job; newJob->jobId = id; - gettimeofday( &newJob->requestTime, NULL ); + gettimeofday(&newJob->requestTime, NULL); } return newJob; @@ -650,28 +604,24 @@ static ThreadPoolJob *CreateThreadPoolJob( ThreadPoolJob *job, int id, ThreadPoo * EAGAIN if system can not create thread * *****************************************************************************/ -static int CreateWorker( ThreadPool *tp ) +static int CreateWorker(ThreadPool *tp) { ithread_t temp; int rc = 0; int currentThreads = tp->totalThreads + 1; - assert( tp != NULL ); - - if ( tp->attr.maxThreads != INFINITE_THREADS && - currentThreads > tp->attr.maxThreads ) { + if (tp->attr.maxThreads != INFINITE_THREADS && + currentThreads > tp->attr.maxThreads) { return EMAXTHREADS; } - - rc = ithread_create( &temp, NULL, WorkerThread, tp ); - if( rc == 0 ) { - rc = ithread_detach( temp ); - while( tp->totalThreads < currentThreads ) { - ithread_cond_wait( &tp->start_and_shutdown, &tp->mutex ); + rc = ithread_create(&temp, NULL, WorkerThread, tp); + if (rc == 0) { + rc = ithread_detach(temp); + while (tp->totalThreads < currentThreads) { + ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); } } - - if( tp->stats.maxThreads < tp->totalThreads ) { + if (tp->stats.maxThreads < tp->totalThreads) { tp->stats.maxThreads = tp->totalThreads; } @@ -695,13 +645,11 @@ static void AddWorker(ThreadPool *tp) int jobs = 0; int threads = 0; - assert( tp != NULL ); - jobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size; threads = tp->totalThreads - tp->persistentThreads; - while (threads == 0 || - (jobs / threads) >= tp->attr.jobsPerThread || - (tp->totalThreads == tp->busyThreads) ) { + while (threads == 0 || + (jobs / threads) >= tp->attr.jobsPerThread || + (tp->totalThreads == tp->busyThreads) ) { if (CreateWorker(tp) != 0) { return; } @@ -741,67 +689,43 @@ static void AddWorker(ThreadPool *tp) * INVALID_POLICY if schedPolicy can't be set * EMAXTHREADS if minimum threads is greater than maximum threads *****************************************************************************/ -int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr ) +int ThreadPoolInit(ThreadPool *tp, ThreadPoolAttr *attr) { int retCode = 0; int i = 0; - assert( tp != NULL ); - if( tp == NULL ) { + if (!tp) { return EINVAL; } -#ifdef WIN32 -#ifdef PTW32_STATIC_LIB - pthread_win32_process_attach_np(); -#endif -#endif - retCode += ithread_mutex_init( &tp->mutex, NULL ); - assert( retCode == 0 ); + retCode += ithread_mutex_init(&tp->mutex, NULL); + retCode += ithread_mutex_lock(&tp->mutex); - retCode += ithread_mutex_lock( &tp->mutex ); - assert( retCode == 0 ); - - retCode += ithread_cond_init( &tp->condition, NULL ); - assert( retCode == 0 ); - - retCode += ithread_cond_init( &tp->start_and_shutdown, NULL ); - assert( retCode == 0 ); - - if( retCode != 0 ) { + retCode += ithread_cond_init(&tp->condition, NULL); + retCode += ithread_cond_init(&tp->start_and_shutdown, NULL); + if (retCode) { return EAGAIN; } - - if( attr ) { - tp->attr = ( *attr ); + if (attr) { + tp->attr = *attr; } else { - TPAttrInit( &tp->attr ); + TPAttrInit(&tp->attr); } + if (SetPolicyType(tp->attr.schedPolicy) != 0) { + ithread_mutex_unlock(&tp->mutex); + ithread_mutex_destroy(&tp->mutex); + ithread_cond_destroy(&tp->condition); + ithread_cond_destroy(&tp->start_and_shutdown); - if( SetPolicyType( tp->attr.schedPolicy ) != 0 ) { - ithread_mutex_unlock( &tp->mutex ); - ithread_mutex_destroy( &tp->mutex ); - ithread_cond_destroy( &tp->condition ); - ithread_cond_destroy( &tp->start_and_shutdown ); return INVALID_POLICY; } - retCode += FreeListInit( - &tp->jobFreeList, sizeof( ThreadPoolJob ), JOBFREELISTSIZE ); - assert( retCode == 0 ); - - StatsInit( &tp->stats ); - - retCode += ListInit( &tp->highJobQ, CmpThreadPoolJob, NULL ); - assert( retCode == 0 ); - - retCode += ListInit( &tp->medJobQ, CmpThreadPoolJob, NULL ); - assert( retCode == 0 ); - - retCode += ListInit( &tp->lowJobQ, CmpThreadPoolJob, NULL ); - assert( retCode == 0 ); - - if( retCode != 0 ) { + &tp->jobFreeList, sizeof(ThreadPoolJob), JOBFREELISTSIZE); + StatsInit(&tp->stats); + retCode += ListInit(&tp->highJobQ, CmpThreadPoolJob, NULL); + retCode += ListInit(&tp->medJobQ, CmpThreadPoolJob, NULL); + retCode += ListInit(&tp->lowJobQ, CmpThreadPoolJob, NULL); + if (retCode) { retCode = EAGAIN; } else { tp->persistentJob = NULL; @@ -810,18 +734,19 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr ) tp->totalThreads = 0; tp->busyThreads = 0; tp->persistentThreads = 0; - for( i = 0; i < tp->attr.minThreads; ++i ) { - if( ( retCode = CreateWorker( tp ) ) != 0 ) { + for (i = 0; i < tp->attr.minThreads; ++i) { + retCode = CreateWorker(tp); + if (retCode) { break; } } } - ithread_mutex_unlock( &tp->mutex ); + ithread_mutex_unlock(&tp->mutex); - if( retCode != 0 ) { - // clean up if the min threads could not be created - ThreadPoolShutdown( tp ); + if (retCode) { + /* clean up if the min threads could not be created */ + ThreadPoolShutdown(tp); } return retCode; @@ -846,61 +771,53 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr ) * EOUTOFMEM not enough memory to add job. * EMAXTHREADS not enough threads to add persistent job. *****************************************************************************/ -int ThreadPoolAddPersistent( ThreadPool *tp, ThreadPoolJob *job, int *jobId ) +int ThreadPoolAddPersistent(ThreadPool *tp, ThreadPoolJob *job, int *jobId) { + int ret = 0; int tempId = -1; ThreadPoolJob *temp = NULL; - assert( tp != NULL ); - assert( job != NULL ); - if( ( tp == NULL ) || ( job == NULL ) ) { + if (!tp || !job) { return EINVAL; } - - if( jobId == NULL ) { + if (!jobId) { jobId = &tempId; } - *jobId = INVALID_JOB_ID; - ithread_mutex_lock( &tp->mutex ); + ithread_mutex_lock(&tp->mutex); - assert( job->priority == LOW_PRIORITY || - job->priority == MED_PRIORITY || - job->priority == HIGH_PRIORITY ); - - // Create A worker if less than max threads running - if( tp->totalThreads < tp->attr.maxThreads ) { - CreateWorker( tp ); + /* Create A worker if less than max threads running */ + if (tp->totalThreads < tp->attr.maxThreads) { + CreateWorker(tp); } else { - // if there is more than one worker thread - // available then schedule job, otherwise fail - if( tp->totalThreads - tp->persistentThreads - 1 == 0 ) { - ithread_mutex_unlock( &tp->mutex ); - return EMAXTHREADS; + /* if there is more than one worker thread + * available then schedule job, otherwise fail */ + if (tp->totalThreads - tp->persistentThreads - 1 == 0) { + ret = EMAXTHREADS; + goto exit_function; } } - - temp = CreateThreadPoolJob( job, tp->lastJobId, tp ); - if( temp == NULL ) { - ithread_mutex_unlock( &tp->mutex ); - return EOUTOFMEM; + temp = CreateThreadPoolJob(job, tp->lastJobId, tp); + if (!temp) { + ret = EOUTOFMEM; + goto exit_function; } - tp->persistentJob = temp; - // Notify a waiting thread - ithread_cond_signal( &tp->condition ); + /* Notify a waiting thread */ + ithread_cond_signal(&tp->condition); - // wait until long job has been picked up - while( tp->persistentJob != NULL ) { - ithread_cond_wait( &tp->start_and_shutdown, &tp->mutex ); + /* wait until long job has been picked up */ + while (tp->persistentJob) { + ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); } - *jobId = tp->lastJobId++; - ithread_mutex_unlock( &tp->mutex ); - return 0; +exit_function: + ithread_mutex_unlock(&tp->mutex); + + return ret; } /**************************************************************************** @@ -921,72 +838,60 @@ int ThreadPoolAddPersistent( ThreadPool *tp, ThreadPoolJob *job, int *jobId ) * 0 on success, nonzero on failure * EOUTOFMEM if not enough memory to add job. *****************************************************************************/ -int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId ) +int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId) { int rc = EOUTOFMEM; - int tempId = -1; int totalJobs; - ThreadPoolJob *temp = NULL; - assert( tp != NULL ); - assert( job != NULL ); - if( ( tp == NULL ) || ( job == NULL ) ) { + if (!tp || !job) { return EINVAL; } - ithread_mutex_lock( &tp->mutex ); - - assert( job->priority == LOW_PRIORITY || - job->priority == MED_PRIORITY || - job->priority == HIGH_PRIORITY ); + ithread_mutex_lock(&tp->mutex); totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size; if (totalJobs >= tp->attr.maxJobsTotal) { fprintf(stderr, "total jobs = %d, too many jobs", totalJobs); - ithread_mutex_unlock( &tp->mutex ); - return rc; + goto exit_function; } - - if( jobId == NULL ) { + if (!jobId) { jobId = &tempId; } *jobId = INVALID_JOB_ID; - - temp = CreateThreadPoolJob( job, tp->lastJobId, tp ); - if( temp == NULL ) { - ithread_mutex_unlock( &tp->mutex ); - return rc; + temp = CreateThreadPoolJob(job, tp->lastJobId, tp); + if (!temp) { + goto exit_function; } - - if( job->priority == HIGH_PRIORITY ) { - if( ListAddTail( &tp->highJobQ, temp ) ) { + if (job->priority == HIGH_PRIORITY) { + if (ListAddTail(&tp->highJobQ, temp)) { rc = 0; } - } else if( job->priority == MED_PRIORITY ) { - if( ListAddTail( &tp->medJobQ, temp ) ) { + } else if (job->priority == MED_PRIORITY) { + if (ListAddTail(&tp->medJobQ, temp)) { rc = 0; } } else { - if( ListAddTail( &tp->lowJobQ, temp ) ) { + if (ListAddTail(&tp->lowJobQ, temp)) { rc = 0; } } - // AddWorker if appropriate - AddWorker( tp ); + /* AddWorker if appropriate */ + AddWorker(tp); - // Notify a waiting thread - if( rc == 0 ) { - ithread_cond_signal( &tp->condition ); + /* Notify a waiting thread */ + if (rc == 0) { + ithread_cond_signal(&tp->condition); } else { - FreeThreadPoolJob( tp, temp ); + FreeThreadPoolJob(tp, temp); } *jobId = tp->lastJobId++; - ithread_mutex_unlock( &tp->mutex ); +exit_function: + ithread_mutex_unlock(&tp->mutex); return rc; } @@ -1007,69 +912,61 @@ int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId ) * Returns: * 0 on success. INVALID_JOB_ID on failure. *****************************************************************************/ -int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out ) +int ThreadPoolRemove(ThreadPool *tp, int jobId, ThreadPoolJob *out) { - ThreadPoolJob *temp = NULL; int ret = INVALID_JOB_ID; + ThreadPoolJob *temp = NULL; ListNode *tempNode = NULL; ThreadPoolJob dummy; - assert( tp != NULL ); - if( tp == NULL ) { + if (!tp) { return EINVAL; } - - if( out == NULL ) { + if (!out) { out = &dummy; } - dummy.jobId = jobId; - ithread_mutex_lock( &tp->mutex ); + ithread_mutex_lock(&tp->mutex); - tempNode = ListFind( &tp->highJobQ, NULL, &dummy ); - if( tempNode ) { + tempNode = ListFind(&tp->highJobQ, NULL, &dummy); + if (tempNode) { temp = (ThreadPoolJob *)tempNode->item; *out = *temp; - ListDelNode( &tp->highJobQ, tempNode, 0 ); - FreeThreadPoolJob( tp, temp ); - ithread_mutex_unlock( &tp->mutex ); - - return 0; + ListDelNode(&tp->highJobQ, tempNode, 0); + FreeThreadPoolJob(tp, temp); + ret = 0; + goto exit_function; } - tempNode = ListFind( &tp->medJobQ, NULL, &dummy ); - if( tempNode ) { + tempNode = ListFind(&tp->medJobQ, NULL, &dummy); + if (tempNode) { temp = (ThreadPoolJob *)tempNode->item; *out = *temp; - ListDelNode( &tp->medJobQ, tempNode, 0 ); - FreeThreadPoolJob( tp, temp ); - ithread_mutex_unlock( &tp->mutex ); - - return 0; + ListDelNode(&tp->medJobQ, tempNode, 0); + FreeThreadPoolJob(tp, temp); + ret = 0; + goto exit_function; } - - tempNode = ListFind( &tp->lowJobQ, NULL, &dummy ); - if( tempNode ) { + tempNode = ListFind(&tp->lowJobQ, NULL, &dummy); + if (tempNode) { temp = (ThreadPoolJob *)tempNode->item; *out = *temp; - ListDelNode( &tp->lowJobQ, tempNode, 0 ); - FreeThreadPoolJob( tp, temp ); - ithread_mutex_unlock( &tp->mutex ); - - return 0; + ListDelNode(&tp->lowJobQ, tempNode, 0); + FreeThreadPoolJob(tp, temp); + ret = 0; + goto exit_function; } - - if( tp->persistentJob && tp->persistentJob->jobId == jobId ) { + if (tp->persistentJob && tp->persistentJob->jobId == jobId) { *out = *tp->persistentJob; - FreeThreadPoolJob( tp, tp->persistentJob ); + FreeThreadPoolJob(tp, tp->persistentJob); tp->persistentJob = NULL; - ithread_mutex_unlock( &tp->mutex ); - - return 0; + ret = 0; + goto exit_function; } - ithread_mutex_unlock( &tp->mutex ); +exit_function: + ithread_mutex_unlock(&tp->mutex); return ret; } @@ -1087,22 +984,17 @@ int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out ) * 0 on success, nonzero on failure * Always returns 0. *****************************************************************************/ -int ThreadPoolGetAttr( ThreadPool *tp, ThreadPoolAttr *out ) +int ThreadPoolGetAttr(ThreadPool *tp, ThreadPoolAttr *out) { - assert( tp != NULL ); - assert( out != NULL ); - if( tp == NULL || out == NULL ) { + if (!tp || !out) { return EINVAL; } - - if( !tp->shutdown ) { - ithread_mutex_lock( &tp->mutex ); + if (!tp->shutdown) { + ithread_mutex_lock(&tp->mutex); } - *out = tp->attr; - - if( !tp->shutdown ) { - ithread_mutex_unlock( &tp->mutex ); + if (!tp->shutdown) { + ithread_mutex_unlock(&tp->mutex); } return 0; @@ -1121,49 +1013,46 @@ int ThreadPoolGetAttr( ThreadPool *tp, ThreadPoolAttr *out ) * 0 on success, nonzero on failure * Returns INVALID_POLICY if policy can not be set. *****************************************************************************/ -int ThreadPoolSetAttr( ThreadPool *tp, ThreadPoolAttr *attr ) +int ThreadPoolSetAttr(ThreadPool *tp, ThreadPoolAttr *attr) { int retCode = 0; ThreadPoolAttr temp; int i = 0; - assert( tp != NULL ); - if( tp == NULL ) { + if (!tp) { return EINVAL; } - ithread_mutex_lock( &tp->mutex ); - if( attr != NULL ) { - temp = ( *attr ); + ithread_mutex_lock(&tp->mutex); + + if (attr) { + temp = *attr; } else { - TPAttrInit( &temp ); + TPAttrInit(&temp); } - - if( SetPolicyType( temp.schedPolicy ) != 0 ) { - ithread_mutex_unlock( &tp->mutex ); + if (SetPolicyType(temp.schedPolicy) != 0) { + ithread_mutex_unlock(&tp->mutex); return INVALID_POLICY; } - - tp->attr = ( temp ); - - // add threads - if( tp->totalThreads < tp->attr.minThreads ) - { - for( i = tp->totalThreads; i < tp->attr.minThreads; i++ ) { - if( ( retCode = CreateWorker( tp ) ) != 0 ) { + tp->attr = temp; + /* add threads */ + if (tp->totalThreads < tp->attr.minThreads) { + for (i = tp->totalThreads; i < tp->attr.minThreads; i++) { + retCode = CreateWorker(tp); + if (retCode != 0) { break; } } } + /* signal changes */ + ithread_cond_signal(&tp->condition); - // signal changes - ithread_cond_signal( &tp->condition ); - ithread_mutex_unlock( &tp->mutex ); + ithread_mutex_unlock(&tp->mutex); - if( retCode != 0 ) { - // clean up if the min threads could not be created - ThreadPoolShutdown( tp ); + if (retCode != 0) { + /* clean up if the min threads could not be created */ + ThreadPoolShutdown(tp); } return retCode; @@ -1183,85 +1072,83 @@ int ThreadPoolSetAttr( ThreadPool *tp, ThreadPoolAttr *attr ) * 0 on success, nonzero on failure * Always returns 0. *****************************************************************************/ -int ThreadPoolShutdown( ThreadPool *tp ) +int ThreadPoolShutdown(ThreadPool *tp) { ListNode *head = NULL; ThreadPoolJob *temp = NULL; - assert( tp != NULL ); - if( tp == NULL ) { + if (!tp) { return EINVAL; } - ithread_mutex_lock( &tp->mutex ); + ithread_mutex_lock(&tp->mutex); - // clean up high priority jobs - while( tp->highJobQ.size ) { - head = ListHead( &tp->highJobQ ); - temp = ( ThreadPoolJob *) head->item; - if( temp->free_func ) { - temp->free_func( temp->arg ); + /* clean up high priority jobs */ + while (tp->highJobQ.size) { + head = ListHead(&tp->highJobQ); + temp = (ThreadPoolJob *)head->item; + if (temp->free_func) { + temp->free_func(temp->arg); } - FreeThreadPoolJob( tp, temp ); - ListDelNode( &tp->highJobQ, head, 0 ); + FreeThreadPoolJob(tp, temp); + ListDelNode(&tp->highJobQ, head, 0); } - ListDestroy( &tp->highJobQ, 0 ); + ListDestroy(&tp->highJobQ, 0); - // clean up med priority jobs - while( tp->medJobQ.size ) { - head = ListHead( &tp->medJobQ ); - temp = ( ThreadPoolJob *) head->item; - if( temp->free_func ) { - temp->free_func( temp->arg ); + /* clean up med priority jobs */ + while (tp->medJobQ.size) { + head = ListHead(&tp->medJobQ); + temp = (ThreadPoolJob *)head->item; + if (temp->free_func) { + temp->free_func(temp->arg); } - FreeThreadPoolJob( tp, temp ); - ListDelNode( &tp->medJobQ, head, 0 ); + FreeThreadPoolJob(tp, temp); + ListDelNode(&tp->medJobQ, head, 0); } - ListDestroy( &tp->medJobQ, 0 ); + ListDestroy(&tp->medJobQ, 0); - // clean up low priority jobs - while( tp->lowJobQ.size ) { - head = ListHead( &tp->lowJobQ ); - temp = ( ThreadPoolJob *) head->item; - if( temp->free_func ) { - temp->free_func( temp->arg ); + /* clean up low priority jobs */ + while (tp->lowJobQ.size) { + head = ListHead(&tp->lowJobQ); + temp = (ThreadPoolJob *)head->item; + if (temp->free_func) { + temp->free_func(temp->arg); } - FreeThreadPoolJob( tp, temp ); - ListDelNode( &tp->lowJobQ, head, 0 ); + FreeThreadPoolJob(tp, temp); + ListDelNode(&tp->lowJobQ, head, 0); } - ListDestroy( &tp->lowJobQ, 0 ); + ListDestroy(&tp->lowJobQ, 0); - // clean up long term job - if( tp->persistentJob ) { + /* clean up long term job */ + if (tp->persistentJob) { temp = tp->persistentJob; - if( temp->free_func ) { - temp->free_func( temp->arg ); + if (temp->free_func) { + temp->free_func(temp->arg); } - FreeThreadPoolJob( tp, temp ); + FreeThreadPoolJob(tp, temp); tp->persistentJob = NULL; } - - // signal shutdown + /* signal shutdown */ tp->shutdown = 1; - ithread_cond_broadcast( &tp->condition ); - - // wait for all threads to finish - while( tp->totalThreads > 0 ) { - ithread_cond_wait( &tp->start_and_shutdown, &tp->mutex ); + ithread_cond_broadcast(&tp->condition); + /* wait for all threads to finish */ + while (tp->totalThreads > 0) { + ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); } - - // destroy condition - while( ithread_cond_destroy( &tp->condition ) != 0 ) { + /* destroy condition */ + while (ithread_cond_destroy(&tp->condition) != 0) { + /**/ } - while( ithread_cond_destroy( &tp->start_and_shutdown ) != 0 ) { + while (ithread_cond_destroy(&tp->start_and_shutdown) != 0) { + /**/ } + FreeListDestroy(&tp->jobFreeList); - FreeListDestroy( &tp->jobFreeList ); + ithread_mutex_unlock(&tp->mutex); - ithread_mutex_unlock( &tp->mutex ); - - // destroy mutex - while( ithread_mutex_destroy( &tp->mutex ) != 0 ) { + /* destroy mutex */ + while (ithread_mutex_destroy(&tp->mutex) != 0) { + /**/ } return 0; @@ -1278,13 +1165,11 @@ int ThreadPoolShutdown( ThreadPool *tp ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrInit( ThreadPoolAttr *attr ) +int TPAttrInit(ThreadPoolAttr *attr) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->jobsPerThread = DEFAULT_JOBS_PER_THREAD; attr->maxIdleTime = DEFAULT_IDLE_TIME; attr->maxThreads = DEFAULT_MAX_THREADS; @@ -1310,14 +1195,11 @@ int TPAttrInit( ThreadPoolAttr *attr ) * Returns: * Always returns 0. *****************************************************************************/ -int TPJobInit( ThreadPoolJob *job, start_routine func, void *arg ) +int TPJobInit(ThreadPoolJob *job, start_routine func, void *arg) { - assert( job != NULL ); - assert( func != NULL ); - if( job == NULL || func == NULL ) { + if (!job || !func) { return EINVAL; } - job->func = func; job->arg = arg; job->priority = DEFAULT_PRIORITY; @@ -1338,16 +1220,14 @@ int TPJobInit( ThreadPoolJob *job, start_routine func, void *arg ) * Returns 0 on success nonzero on failure. * Returns EINVAL if invalid priority. *****************************************************************************/ -int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority ) +int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority) { - assert( job != NULL ); - if( job == NULL ) { + if (!job) { return EINVAL; } - - if( priority == LOW_PRIORITY || + if (priority == LOW_PRIORITY || priority == MED_PRIORITY || - priority == HIGH_PRIORITY ) { + priority == HIGH_PRIORITY) { job->priority = priority; return 0; } else { @@ -1366,13 +1246,11 @@ int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority ) * Returns: * Always returns 0. *****************************************************************************/ -int TPJobSetFreeFunction( ThreadPoolJob *job, free_routine func ) +int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func) { - assert( job != NULL ); - if( job == NULL ) { + if(!job) { return EINVAL; } - job->free_func = func; return 0; @@ -1389,13 +1267,11 @@ int TPJobSetFreeFunction( ThreadPoolJob *job, free_routine func ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetMaxThreads( ThreadPoolAttr *attr, int maxThreads ) +int TPAttrSetMaxThreads(ThreadPoolAttr *attr, int maxThreads) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->maxThreads = maxThreads; return 0; @@ -1412,13 +1288,11 @@ int TPAttrSetMaxThreads( ThreadPoolAttr *attr, int maxThreads ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetMinThreads( ThreadPoolAttr *attr, int minThreads ) +int TPAttrSetMinThreads(ThreadPoolAttr *attr, int minThreads) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->minThreads = minThreads; return 0; @@ -1434,13 +1308,11 @@ int TPAttrSetMinThreads( ThreadPoolAttr *attr, int minThreads ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetIdleTime( ThreadPoolAttr *attr, int idleTime ) +int TPAttrSetIdleTime(ThreadPoolAttr *attr, int idleTime) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->maxIdleTime = idleTime; return 0; @@ -1456,13 +1328,11 @@ int TPAttrSetIdleTime( ThreadPoolAttr *attr, int idleTime ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetJobsPerThread( ThreadPoolAttr *attr, int jobsPerThread ) +int TPAttrSetJobsPerThread(ThreadPoolAttr *attr, int jobsPerThread) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->jobsPerThread = jobsPerThread; return 0; @@ -1478,13 +1348,11 @@ int TPAttrSetJobsPerThread( ThreadPoolAttr *attr, int jobsPerThread ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetStarvationTime( ThreadPoolAttr *attr, int starvationTime ) +int TPAttrSetStarvationTime(ThreadPoolAttr *attr, int starvationTime) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->starvationTime = starvationTime; return 0; @@ -1501,13 +1369,11 @@ int TPAttrSetStarvationTime( ThreadPoolAttr *attr, int starvationTime ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetSchedPolicy( ThreadPoolAttr *attr, PolicyType schedPolicy ) +int TPAttrSetSchedPolicy(ThreadPoolAttr *attr, PolicyType schedPolicy) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->schedPolicy = schedPolicy; return 0; @@ -1524,13 +1390,11 @@ int TPAttrSetSchedPolicy( ThreadPoolAttr *attr, PolicyType schedPolicy ) * Returns: * Always returns 0. *****************************************************************************/ -int TPAttrSetMaxJobsTotal( ThreadPoolAttr *attr, int maxJobsTotal ) +int TPAttrSetMaxJobsTotal(ThreadPoolAttr *attr, int maxJobsTotal) { - assert( attr != NULL ); - if( attr == NULL ) { + if (!attr) { return EINVAL; } - attr->maxJobsTotal = maxJobsTotal; return 0; @@ -1540,11 +1404,9 @@ int TPAttrSetMaxJobsTotal( ThreadPoolAttr *attr, int maxJobsTotal ) #ifdef STATS void ThreadPoolPrintStats(ThreadPoolStats *stats) { - assert( stats != NULL ); - if (stats == NULL) { + if (!stats) { return; } - /* some OSses time_t length may depending on platform, promote it to long for safety */ printf("ThreadPoolStats at Time: %ld\n", (long)StatsTime(NULL)); printf("High Jobs pending: %d\n", stats->currentJobsHQ); @@ -1578,15 +1440,13 @@ void ThreadPoolPrintStats(ThreadPoolStats *stats) * Always returns 0. *****************************************************************************/ #ifdef STATS -int ThreadPoolGetStats( ThreadPool *tp, ThreadPoolStats *stats ) +int ThreadPoolGetStats(ThreadPool *tp, ThreadPoolStats *stats) { - assert(tp != NULL); - assert(stats != NULL); if (tp == NULL || stats == NULL) { return EINVAL; } - //if not shutdown then acquire mutex + /* if not shutdown then acquire mutex */ if (!tp->shutdown) { ithread_mutex_lock(&tp->mutex); } @@ -1597,28 +1457,24 @@ int ThreadPoolGetStats( ThreadPool *tp, ThreadPoolStats *stats ) } else { stats->avgWaitHQ = 0; } - - if( stats->totalJobsMQ > 0 ) { + if (stats->totalJobsMQ > 0) { stats->avgWaitMQ = stats->totalTimeMQ / stats->totalJobsMQ; } else { stats->avgWaitMQ = 0; } - - if( stats->totalJobsLQ > 0 ) { + if (stats->totalJobsLQ > 0) { stats->avgWaitLQ = stats->totalTimeLQ / stats->totalJobsLQ; } else { stats->avgWaitLQ = 0; } - stats->totalThreads = tp->totalThreads; stats->persistentThreads = tp->persistentThreads; stats->currentJobsHQ = ListSize( &tp->highJobQ ); stats->currentJobsLQ = ListSize( &tp->lowJobQ ); stats->currentJobsMQ = ListSize( &tp->medJobQ ); - - //if not shutdown then release mutex - if( !tp->shutdown ) { - ithread_mutex_unlock( &tp->mutex ); + /* if not shutdown then release mutex */ + if (!tp->shutdown) { + ithread_mutex_unlock(&tp->mutex); } return 0; @@ -1628,44 +1484,42 @@ int ThreadPoolGetStats( ThreadPool *tp, ThreadPoolStats *stats ) #ifdef WIN32 + #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif - + int gettimeofday(struct timeval *tv, struct timezone *tz) { - FILETIME ft; - unsigned __int64 tmpres = 0; - static int tzflag; + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; - if (NULL != tv) - { - GetSystemTimeAsFileTime(&ft); + if (tv) { + GetSystemTimeAsFileTime(&ft); - tmpres |= ft.dwHighDateTime; - tmpres <<= 32; - tmpres |= ft.dwLowDateTime; + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; - /*converting file time to unix epoch*/ - tmpres /= 10; /*convert into microseconds*/ - tmpres -= DELTA_EPOCH_IN_MICROSECS; - tv->tv_sec = (long)(tmpres / 1000000UL); - tv->tv_usec = (long)(tmpres % 1000000UL); - } + /*converting file time to unix epoch*/ + tmpres /= 10; /*convert into microseconds*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + if (tz) { + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } - if (NULL != tz) - { - if (!tzflag) - { - _tzset(); - tzflag++; - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; + return 0; } #endif /* WIN32 */ + diff --git a/upnp/Makefile.am b/upnp/Makefile.am index be15a62..39d7c6f 100644 --- a/upnp/Makefile.am +++ b/upnp/Makefile.am @@ -73,6 +73,7 @@ libupnp_la_SOURCES = \ src/inc/util.h \ src/inc/utilall.h \ src/inc/uuid.h \ + src/inc/VirtualDir.h \ src/inc/webserver.h # ssdp diff --git a/upnp/inc/upnp.h b/upnp/inc/upnp.h index 84a3184..5afb4fa 100644 --- a/upnp/inc/upnp.h +++ b/upnp/inc/upnp.h @@ -644,7 +644,7 @@ struct Upnp_Action_Request IXML_Document *ActionResult; /** IP address of the control point requesting this action. */ - struct in_addr CtrlPtIPAddr; + struct sockaddr_storage CtrlPtIPAddr; /** The DOM document containing the information from the the SOAP header. */ @@ -691,7 +691,7 @@ struct Upnp_State_Var_Request char StateVarName[NAME_SIZE]; /** IP address of sender requesting the state variable. */ - struct in_addr CtrlPtIPAddr; + struct sockaddr_storage CtrlPtIPAddr; /** The current value of the variable. This needs to be allocated by * the caller. When finished with it, the SDK frees this {\bf DOMString}. */ @@ -817,132 +817,29 @@ struct Upnp_Subscription_Request struct File_Info { - /** The length of the file. A length less than 0 indicates the size - * is unknown, and data will be sent until 0 bytes are returned from - * a read call. */ - off_t file_length; + /** The length of the file. A length less than 0 indicates the size + * is unknown, and data will be sent until 0 bytes are returned from + * a read call. */ + off_t file_length; - /** The time at which the contents of the file was modified; - * The time system is always local (not GMT). */ - time_t last_modified; + /** The time at which the contents of the file was modified; + * The time system is always local (not GMT). */ + time_t last_modified; - /** If the file is a directory, {\bf is_directory} contains - * a non-zero value. For a regular file, it should be 0. */ - int is_directory; + /** If the file is a directory, {\bf is_directory} contains + * a non-zero value. For a regular file, it should be 0. */ + int is_directory; - /** If the file or directory is readable, this contains - * a non-zero value. If unreadable, it should be set to 0. */ - int is_readable; - - /** The content type of the file. This string needs to be allocated - * by the caller using {\bf ixmlCloneDOMString}. When finished - * with it, the SDK frees the {\bf DOMString}. */ - - DOMString content_type; + /** If the file or directory is readable, this contains + * a non-zero value. If unreadable, it should be set to 0. */ + int is_readable; + /** The content type of the file. This string needs to be allocated + * by the caller using {\bf ixmlCloneDOMString}. When finished + * with it, the SDK frees the {\bf DOMString}. */ + DOMString content_type; }; -/* The type of handle returned by the web server for open requests. */ - -typedef void *UpnpWebFileHandle; - -/** The {\bf UpnpVirtualDirCallbacks} structure contains the pointers to - * file-related callback functions a device application can register to - * virtualize URLs. - */ -struct UpnpVirtualDirCallbacks -{ - /** Called by the web server to query information on a file. The callback - * should return 0 on success or -1 on an error. */ - int (*get_info) ( - IN const char *filename, /** The name of the file to query. */ - OUT struct File_Info *info /** Pointer to a structure to store the - information on the file. */ - ); - - /** Called by the web server to open a file. The callback should return - * a valid handle if the file can be opened. Otherwise, it should return - * {\tt NULL} to signify an error. */ - UpnpWebFileHandle (*open)( - IN const char *filename, /** The name of the file to open. */ - IN enum UpnpOpenFileMode Mode /** The mode in which to open the file. - Valid values are {\tt UPNP_READ} or - {\tt UPNP_WRITE}. */ - ); - - /** Called by the web server to perform a sequential read from an open - * file. The callback should copy {\bf buflen} bytes from the file into - * the buffer. - * @return [int] An integer representing one of the following: - * \begin{itemize} - * \item {\tt 0}: The file contains no more data (EOF). - * \item {\tt >0}: A successful read of the number of bytes in the - * return code. - * \item {\tt <0}: An error occurred reading the file. - * \end{itemzie} - */ - int (*read) ( - IN UpnpWebFileHandle fileHnd, /** The handle of the file to read. */ - OUT char *buf, /** The buffer in which to place the - data. */ - IN size_t buflen /** The size of the buffer (i.e. the - number of bytes to read). */ - ); - - /** Called by the web server to perform a sequential write to an open - * file. The callback should write {\bf buflen} bytes into the file from - * the buffer. It should return the actual number of bytes written, - * which might be less than {\bf buflen} in the case of a write error. - */ - int (*write) ( - IN UpnpWebFileHandle fileHnd, /** The handle of the file to write. */ - IN char *buf, /** The buffer with the bytes to write. */ - IN size_t buflen /** The number of bytes to write. */ - ); - - /** Called by the web server to move the file pointer, or offset, into - * an open file. The {\bf origin} parameter determines where to start - * moving the file pointer. A value of {\tt SEEK_CUR} moves the - * file pointer relative to where it is. The {\bf offset} parameter can - * be either positive (move forward) or negative (move backward). - * {\tt SEEK_END} moves relative to the end of the file. A positive - * {\bf offset} extends the file. A negative {\bf offset} moves backward - * in the file. Finally, {\tt SEEK_SET} moves to an absolute position in - * the file. In this case, {\bf offset} must be positive. The callback - * should return 0 on a successful seek or a non-zero value on an error. - */ - int (*seek) ( - IN UpnpWebFileHandle fileHnd, /** The handle of the file to move the - file pointer. */ - IN off_t offset, /** The number of bytes to move in the - file. Positive values move foward and - negative values move backward. Note - that this must be positive if the - {\bf origin} is {\tt SEEK_SET}. */ - IN int origin /** The position to move relative to. It - can be {\tt SEEK_CUR} to move relative - to the current position, - {\tt SEEK_END} to move relative to - the end of the file, or {\tt - SEEK_SET} to specify an absolute - offset. */ - ); - - /** Called by the web server to close a file opened via the {\bf open} - * callback. It should return 0 on success, or a non-zero value on an - * error. - */ - int (*close) ( - IN UpnpWebFileHandle fileHnd /** The handle of the file to close. */ - ); - -}; - -typedef struct virtual_Dir_List -{ - struct virtual_Dir_List *next; - char dirName[NAME_SIZE]; -} virtualDirList; /** All callback functions share the same prototype, documented below. * Note that any memory passed to the callback function @@ -992,22 +889,22 @@ extern "C" { /*! - * \brief Initializes the Linux SDK for UPnP Devices. + * \brief Initializes the Linux SDK for UPnP Devices (IPv4 only). * * \deprecated Kept for backwards compatibility. Use UpnpInit2 for new - * implementations. + * implementations or where IPv6 is required. * * This function must be called before any other API function can be called. * It should be called only once. Subsequent calls to this API return a * \c UPNP_E_INIT error code. * - * Optionally, the application can specify a host IP address (in the + * Optionally, the application can specify a host IPv4 address (in the * case of a multi-homed configuration) and a port number to use for * all UPnP operations. Since a port number can be used only by one * process, multiple processes using the SDK must specify * different port numbers. * - * If unspecified, the SDK will use the first adapter's IP address + * If unspecified, the SDK will use the first IPv4-capable adapter's IP address * and an arbitrary port. * * This call is synchronous. @@ -1025,14 +922,55 @@ extern "C" { * \li \c UPNP_E_INTERNAL_ERROR: An internal error ocurred. */ EXPORT_SPEC int UpnpInit( - /*! The host local IP address to use, in string format, for example - * "192.168.0.1", or \c NULL to use the first adapter's IP address. */ + /*! The host local IPv4 address to use, in string format, for example + * "192.168.0.1", or \c NULL to use the first IPv4 adapter's IP address. */ const char *HostIP, /*! Local Port to listen for incoming connections * \c NULL will pick an arbitrary free port. */ unsigned short DestPort); +/*! + * \brief Initializes the Linux SDK for UPnP Devices (IPv4 or IPv6). + * + * This function must be called before any other API function can be called. + * It should be called only once. Subsequent calls to this API return a + * \c UPNP_E_INIT error code. + * + * Optionally, the application can specify an interface name (in the + * case of a multi-homed configuration) and a port number to use for + * all UPnP operations. Since a port number can be used only by one + * process, multiple processes using the SDK must specify + * different port numbers. + * + * If unspecified, the SDK will use the first suitable interface and an + * arbitrary port. + * + * This call is synchronous. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist + * to initialize the SDK. + * \li \c UPNP_E_INIT: The SDK is already initialized. + * \li \c UPNP_E_INIT_FAILED: The SDK initialization + * failed for an unknown reason. + * \li \c UPNP_E_SOCKET_BIND: An error occurred binding a socket. + * \li \c UPNP_E_LISTEN: An error occurred listening to a socket. + * \li \c UPNP_E_OUTOF_SOCKET: An error ocurred creating a socket. + * \li \c UPNP_E_INTERNAL_ERROR: An internal error ocurred. + * \li \c UPNP_E_INVALID_INTERFACE: IfName is invalid or does not + * have a valid IPv4 or IPv6 addresss configured. + */ +EXPORT_SPEC int UpnpInit2( + /*! The interface name to use by the UPnP SDK operations. + * Examples: "eth0", "xl0", "Local Area Connection", \c NULL to + * use the first suitable interface. */ + const char *IfName, + /*! Local Port to listen for incoming connections. + * \c NULL will pick an arbitrary free port. */ + unsigned short DestPort); + /*! * \brief Terminates the Linux SDK for UPnP Devices. @@ -1070,6 +1008,19 @@ EXPORT_SPEC int UpnpFinish(void); EXPORT_SPEC unsigned short UpnpGetServerPort(void); +/*! + * \brief Returns the internal server IPv6 UPnP listening port. + * + * If '0' is used as the port number in \b UpnpInit, then this function can be + * used to retrieve the actual port allocated to the SDK. + * + * \return + * \li On success: The port on which an internal server is listening for IPv6 UPnP + * related requests. + * \li On error: 0 is returned if \b UpnpInit has not succeeded. + */ +EXPORT_SPEC unsigned short UpnpGetServerPort6(void); + /*! * \brief Returns the local IPv4 listening ip address. * @@ -1084,6 +1035,20 @@ EXPORT_SPEC unsigned short UpnpGetServerPort(void); EXPORT_SPEC char *UpnpGetServerIpAddress(void); +/*! + * \brief Returns the local IPv6 listening ip address. + * + * If \c NULL is used as the IPv6 address in \b UpnpInit, then this function can + * be used to retrieve the actual interface address on which device is running. + * + * \return + * \li On success: The IPv6 address on which an internal server is + * listening for UPnP related requests. + * \li On error: \c NULL is returned if \b UpnpInit has not succeeded. + */ +EXPORT_SPEC char *UpnpGetServerIp6Address(void); + + /*! * \brief Registers a device application with the UPnP Library. * @@ -1220,6 +1185,56 @@ EXPORT_SPEC int UpnpRegisterRootDevice2( UpnpDevice_Handle* Hnd); +/*! + * \brief Registers a device application for a specific address family with + * the UPnP library. + * + * A device application cannot make any other API calls until it registers + * using this function. Device applications can also register as control + * points (see \b UpnpRegisterClient to get a control point handle to perform + * control point functionality). + * + * This is synchronous and does not generate any callbacks. Callbacks can occur + * as soon as this function returns. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_FINISH: The SDK is already terminated or + * is not initialized. + * \li \c UPNP_E_INVALID_DESC: The description document was not + * a valid device description. + * \li \c UPNP_E_INVALID_URL: The URL for the description document + * is not valid. + * \li \c UPNP_E_INVALID_PARAM: Either \b Callback or \b Hnd + * is not a valid pointer or \b DescURL is \c NULL. + * \li \c UPNP_E_NETWORK_ERROR: A network error occurred. + * \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing + * to a socket. + * \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading + * from a socket. + * \li \c UPNP_E_SOCKET_BIND: An error occurred binding a socket. + * \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting the + * socket. + * \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently + * allocated. + * \li \c UPNP_E_OUTOF_MEMORY: There are insufficient resources to + * register this root device. + */ +EXPORT_SPEC int UpnpRegisterRootDevice3( + /*! [in] Pointer to a string containing the description URL for this root + * device instance. */ + const char *DescUrl, + /*! [in] Pointer to the callback function for receiving asynchronous events. */ + Upnp_FunPtr Callback, + /*! [in] Pointer to user data returned with the callback function when invoked. */ + const void *Cookie, + /*! [out] Pointer to a variable to store the new device handle. */ + UpnpDevice_Handle *Hnd, + /*! [in] Address family of this device. Can be AF_INET for an IPv4 device, or + * AF_INET6 for an IPv6 device. Defaults to AF_INET. */ + const int AddressFamily); + + /*! * \brief Unregisters a root device registered with \b UpnpRegisterRootDevice or * \b UpnpRegisterRootDevice2. @@ -2592,6 +2607,147 @@ EXPORT_SPEC int UpnpSetWebServerRootDir( const char *rootDir); +/*! + * \brief The type of handle returned by the web server for open requests. + */ +typedef void *UpnpWebFileHandle; + + +/*! + * \brief Get-info callback function prototype. + */ +typedef int (*VDCallback_GetInfo)( + /*! [in] The name of the file to query. */ + const char *filename, + /*! [out] Pointer to a structure to store the information on the file. */ + struct File_Info *info); + +/*! + * \brief Sets the get_info callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_GetInfoCallback(VDCallback_GetInfo callback); + + +/*! + * \brief Open callback function prototype. + */ +typedef UpnpWebFileHandle (*VDCallback_Open)( + /*! [in] The name of the file to open. */ + const char *filename, + /*! [in] The mode in which to open the file. + * Valid values are \c UPNP_READ or \c UPNP_WRITE. */ + enum UpnpOpenFileMode Mode); + + +/*! + * \brief Sets the open callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_OpenCallback(VDCallback_Open callback); + + +/*! + * \brief Read callback function prototype. + */ +typedef int (*VDCallback_Read)( + /*! [in] The handle of the file to read. */ + UpnpWebFileHandle fileHnd, + /*! [out] The buffer in which to place the data. */ + char *buf, + /*! [in] The size of the buffer (i.e. the number of bytes to read). */ + size_t buflen); + + +/*! + * \brief Sets the read callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_ReadCallback(VDCallback_Read callback); + + +/*! + * \brief Write callback function prototype. + */ +typedef int (*VDCallback_Write)( + /*! [in] The handle of the file to write. */ + UpnpWebFileHandle fileHnd, + /*! [in] The buffer with the bytes to write. */ + char *buf, + /*! [in] The number of bytes to write. */ + size_t buflen); + + +/*! + * \brief Sets the write callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_WriteCallback(VDCallback_Write callback); + + +/*! + * \brief Seek callback function prototype. + */ +typedef int (*VDCallback_Seek) ( + /*! [in] The handle of the file to move the file pointer. */ + UpnpWebFileHandle fileHnd, + /*! [in] The number of bytes to move in the file. Positive values + * move foward and negative values move backward. Note that + * this must be positive if the \b origin is \c SEEK_SET. */ + off_t offset, + /*! [in] The position to move relative to. It can be \c SEEK_CUR + * to move relative to the current position, \c SEEK_END to + * move relative to the end of the file, or \c SEEK_SET to + * specify an absolute offset. */ + int origin); + + +/*! + * \brief Sets the seek callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_SeekCallback(VDCallback_Seek callback); + + +/*! + * \brief Close callback function prototype. + */ +typedef int (*VDCallback_Close)( + /*! [in] The handle of the file to close. */ + UpnpWebFileHandle fileHnd); + + +/*! + * \brief Sets the close callback function to be used to access a virtual + * directory. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INVALID_ARGUMENT: \b callback is not a valid pointer. + */ +EXPORT_SPEC int UpnpVirtualDir_set_CloseCallback(VDCallback_Close callback); + + /*! * \brief Enables or disables the webserver. * diff --git a/upnp/inc/upnpdebug.h b/upnp/inc/upnpdebug.h index a32bd13..b716e82 100644 --- a/upnp/inc/upnpdebug.h +++ b/upnp/inc/upnpdebug.h @@ -7,12 +7,12 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * * Redistributions of source code must retain the above copyright notice, + * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, + * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * * Neither name of Intel Corporation nor the names of its contributors + * - Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -33,25 +33,34 @@ #ifndef UPNP_DEBUG_H #define UPNP_DEBUG_H -#include "upnp.h" + +/*! + * \file + */ + + +#include "ThreadPool.h" #include "upnpconfig.h" +#include "UpnpGlobal.h" /* for UPNP_INLINE */ + #include + #ifdef __cplusplus extern "C" { #endif -/** @name Other debugging features - The UPnP SDK contains other features to aid in debugging. +/** \name Other debugging features + * + * The UPnP SDK contains other features to aid in debugging. */ +/*@{*/ -/*! @{ */ - -/** @name Upnp_LogLevel +/** \name Upnp_LogLevel * The user has the option to select 4 different types of debugging levels, - * see {\tt UpnpSetLogLevel}. + * see \c UpnpSetLogLevel. * The critical level will show only those messages * which can halt the normal processing of the library, like memory * allocation errors. The remaining three levels are just for debugging @@ -60,14 +69,11 @@ extern "C" { * Info Level displays the other important operational information * regarding the working of the library. If the user selects All, * then the library displays all the debugging information that it has. - * \begin{itemize} - * \item {\tt UPNP_CRITICAL [0]} - * \item {\tt UPNP_PACKET [1]} - * \item {\tt UPNP_INFO [2]} - * \item {\tt UPNP_ALL [3]} - * \end{itemize} + * \li \c UPNP_CRITICAL [0] + * \li \c UPNP_PACKET [1] + * \li \c UPNP_INFO [2] + * \li \c UPNP_ALL [3] */ - typedef enum Upnp_Module { SSDP, SOAP, @@ -79,67 +85,54 @@ typedef enum Upnp_Module { HTTP } Dbg_Module; -/*! @{ */ + +/*@{*/ typedef enum Upnp_LogLevel_e { UPNP_CRITICAL, UPNP_PACKET, UPNP_INFO, UPNP_ALL } Upnp_LogLevel; -/*! @} */ +/*@}*/ /** - * Default log level : see {\tt Upnp_LogLevel} + * Default log level : see \c Upnp_LogLevel */ #define UPNP_DEFAULT_LOG_LEVEL UPNP_ALL -/*************************************************************************** - * Function : UpnpInitLog +/*! + * \brief Initialize the log files. * - * Parameters: void - * - * Description: - * This functions initializes the log files - * - * Returns: int - * -1 : If fails - * UPNP_E_SUCCESS : if success - ***************************************************************************/ + * \return -1 if fails or UPNP_E_SUCCESS if succeeds. + */ #ifdef DEBUG int UpnpInitLog(void); #else -static UPNP_INLINE int UpnpInitLog(void) { return UPNP_E_SUCCESS; } +static UPNP_INLINE int UpnpInitLog(void) +{ + return UPNP_E_SUCCESS; +} #endif -/*************************************************************************** - * Function : UpnpSetLogLevel - * - * Parameters: Upnp_LogLevel log_level - * - * Description: - * This functions set the log level (see {\tt Upnp_LogLevel} - * Returns: void - ***************************************************************************/ +/*! + * \brief Set the log level (see \c Upnp_LogLevel). + */ #ifdef DEBUG -void UpnpSetLogLevel(Upnp_LogLevel log_level); +void UpnpSetLogLevel( + /*! [in] Log level. */ + Upnp_LogLevel log_level); #else static UPNP_INLINE void UpnpSetLogLevel(Upnp_LogLevel log_level) {} #endif -/*************************************************************************** - * Function : UpnpCloseLog - * - * Parameters: void - * - * Description: - * This functions closes the log files - * Returns: void - ***************************************************************************/ +/*! + * \brief Closes the log files. + */ #ifdef DEBUG void UpnpCloseLog(void); #else @@ -147,23 +140,14 @@ static UPNP_INLINE void UpnpCloseLog(void) {} #endif -/*************************************************************************** - * Function : UpnpSetLogFileNames - * - * Parameters: - * IN const char* ErrFileName: name of the error file - * IN const char *InfoFileName: name of the information file - * IN int size: Size of the buffer - * IN int starLength: This parameter provides the width of the banner - * - * Description: - * This functions takes the buffer and writes the buffer in the file as - * per the requested banner - * Returns: void - ***************************************************************************/ +/*! + * \brief Set the name for error and information files, respectively. + */ #ifdef DEBUG void UpnpSetLogFileNames( + /*! [in] Name of the error file. */ const char *ErrFileName, + /*! [in] Name of the information file. */ const char *InfoFileName); #else static UPNP_INLINE void UpnpSetLogFileNames( @@ -172,24 +156,20 @@ static UPNP_INLINE void UpnpSetLogFileNames( #endif -/*************************************************************************** - * Function : UpnpGetDebugFile - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * - * Description: - * This function checks if the module is turned on for debug - * and returns the file descriptor corresponding to the debug level - * Returns: FILE * - * NULL : if the module is turn off for debug - * else returns the right file descriptor - ***************************************************************************/ +/*! + * \brief Check if the module is turned on for debug and returns the file + * descriptor corresponding to the debug level + * + * \return NULL if the module is turn off for debug otheriwse returns the + * right file descriptor. + */ #ifdef DEBUG -FILE *UpnpGetDebugFile(Upnp_LogLevel level, Dbg_Module module); +FILE *UpnpGetDebugFile( + /*! [in] The level of the debug logging. It will decide whether debug + * statement will go to standard output, or any of the log files. */ + Upnp_LogLevel level, + /*! [in] debug will go in the name of this module. */ + Dbg_Module module); #else static UPNP_INLINE FILE *UpnpGetDebugFile(Upnp_LogLevel level, Dbg_Module module) { @@ -198,60 +178,47 @@ static UPNP_INLINE FILE *UpnpGetDebugFile(Upnp_LogLevel level, Dbg_Module module #endif -/*************************************************************************** - * Function : DebugAtThisLevel - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * - * Description: - * This functions returns true if debug output should be done in this - * module. +/*! + * \brief Returns true if debug output should be done in this module. * - * Returns: int - ***************************************************************************/ + * \return Nonzero value if true, zero if false. + */ #ifdef DEBUG int DebugAtThisLevel( - IN Upnp_LogLevel DLevel, - IN Dbg_Module Module); + /*! [in] The level of the debug logging. It will decide whether debug + * statement will go to standard output, or any of the log files. */ + Upnp_LogLevel DLevel, + /*! [in] Debug will go in the name of this module. */ + Dbg_Module Module); #else static UPNP_INLINE int DebugAtThisLevel( - IN Upnp_LogLevel DLevel, - IN Dbg_Module Module) { return 0; } + Upnp_LogLevel DLevel, + Dbg_Module Module) +{ + return 0; +} #endif -/*************************************************************************** - * Function : UpnpPrintf - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * IN char *DbgFileName: Name of the file from where debug statement is - * coming - * IN int DbgLineNo : Line number of the file from where debug statement - * is coming - * IN char * FmtStr, ...: Variable number of arguments that will go - * in the debug statement - * - * Description: - * This functions prints the debug statement either on the startdard - * output or log file along with the information from where this - * debug statement is coming - * Returns: void - ***************************************************************************/ +/*! + * \brief Prints the debug statement either on the standard output or log file + * along with the information from where this debug statement is coming. + */ #ifdef DEBUG void UpnpPrintf( + /*! [in] The level of the debug logging. It will decide whether debug + * statement will go to standard output, or any of the log files. */ Upnp_LogLevel DLevel, + /*! [in] debug will go in the name of this module. */ Dbg_Module Module, + /*! [in] Name of the file from where debug statement is coming. */ const char* DbgFileName, + /*! [in] Line number of the file from where debug statement is coming. */ int DbgLineNo, + /*! [in] Printf like format specification. */ const char* FmtStr, + /*! [in] Printf like Variable number of arguments that will go in the debug + * statement. */ ...) #if (__GNUC__ >= 3) /* This enables printf like format checking by the compiler */ @@ -265,29 +232,44 @@ static UPNP_INLINE void UpnpPrintf( const char* DbgFileName, int DbgLineNo, const char* FmtStr, - ...) {} + ...) +{ +} #endif /* DEBUG */ -/*************************************************************************** - * Function : UpnpDisplayBanner - * - * Parameters: - * IN FILE *fd: file descriptor where the banner will be written - * IN char **lines: The buffer that will be written - * IN int size: Size of the buffer - * IN int starLength: This parameter provides the width of the banner - * - * Description: - * This functions takes the buffer and writes the buffer in the file as - * per the requested banner - * Returns: void - ***************************************************************************/ +/*! + * \brief Writes the file name and file number from where debug statement is + * coming to the log file. + */ +#ifdef DEBUG +void UpnpDisplayFileAndLine( + /*! [in] File descriptor where line number and file name will be written. */ + FILE *fd, + /*! [in] Name of the file. */ + const char *DbgFileName, + /*! [in] Line number of the file. */ + int DbgLineNo); +#else +static UPNP_INLINE void UpnpDisplayFileAndLine( + FILE *fd, + const char *DbgFileName, + int DbgLineNo) {} +#endif + + +/*! + * \brief Writes the buffer in the file as per the requested banner + */ #ifdef DEBUG void UpnpDisplayBanner( + /*! [in] file descriptor where the banner will be written. */ FILE *fd, + /*! [in] The buffer that will be written. */ const char **lines, + /*! [in] Size of the buffer. */ size_t size, + /*! [in] This parameter provides the width of the banner. */ int starlength); #else static UPNP_INLINE void UpnpDisplayBanner( @@ -298,33 +280,49 @@ static UPNP_INLINE void UpnpDisplayBanner( #endif -/*************************************************************************** - * Function : UpnpDisplayFileAndLine - * - * Parameters: - * IN FILE *fd: File descriptor where line number and file name will be - * written - * IN char *DbgFileName: Name of the file - * IN int DbgLineNo : Line number of the file - * - * Description: - * This function writes the file name and file number from where - * debug statement is coming to the log file - * Returns: void - ***************************************************************************/ +/*! + * \brief Prints thread pool statistics. + */ #ifdef DEBUG -void UpnpDisplayFileAndLine( - FILE *fd, +void PrintThreadPoolStats( + /*! [in] The thread pool. */ + ThreadPool *tp, + /*! [in] The file name that called this function, use the macro __FILE__. */ const char *DbgFileName, - int DbgLineNo); + /*! [in] The line number that the function was called, use the macro __LINE__. */ + int DbgLineNo, + /*! [in] The message. */ + const char *msg); #else -static UPNP_INLINE void UpnpDisplayFileAndLine( - FILE *fd, +static UPNP_INLINE void PrintThreadPoolStats( + ThreadPool *tp, const char *DbgFileName, - int DbgLineNo) {} + int DbgLineNo, + const char *msg) +{ +} #endif -/*! @} */ + +/*! + * \brief Print the node names and values of a XML tree. + */ +#ifdef DEBUG +void printNodes( + /*! [in] The root of the tree to print. */ + IXML_Node *tmpRoot, + /*! [in] The depth to print. */ + int depth); +#else +static UPNP_INLINE void printNodes( + IXML_Node *tmpRoot, + int depth) +{ +} +#endif + + +/*@}*/ #ifdef __cplusplus } diff --git a/upnp/src/api/upnpapi.c b/upnp/src/api/upnpapi.c index 6377229..4e755ad 100644 --- a/upnp/src/api/upnpapi.c +++ b/upnp/src/api/upnpapi.c @@ -33,6 +33,11 @@ #include "config.h" +/*! + * \file + */ + + #include @@ -42,7 +47,20 @@ #include -#ifndef WIN32 +#ifdef WIN32 + /* Do not include these files */ +#else + #include + #if defined(__sun) + #include + #include + #elif defined(BSD) && BSD >= 199306 + #include + /* Do not move or remove the include below for "sys/socket"! + * Will break FreeBSD builds. */ + #include + #endif + #include #include #include @@ -51,18 +69,8 @@ #include #include #include - - #include - - - #if defined(__sun) - #include - #include - #elif defined(BSD) && BSD >= 199306 - #include - #endif -#endif /* WIN32 */ +#endif #include "upnpapi.h" @@ -71,631 +79,989 @@ #include "ssdplib.h" #include "soaplib.h" #include "ThreadPool.h" +#include "sysdep.h" +#include "uuid.h" -// Needed for GENA +/* Needed for GENA */ #include "gena.h" #include "miniserver.h" #include "service_table.h" #ifdef INTERNAL_WEB_SERVER - #include "webserver.h" #include "urlconfig.h" -#endif // INTERNAL_WEB_SERVER + #include "VirtualDir.h" + #include "webserver.h" +#endif /* INTERNAL_WEB_SERVER */ -// +/*! This structure is for virtual directory callbacks */ +struct VirtualDirCallbacks virtualDirCallback; + +/*! Pointer to the virtual directory list. */ virtualDirList *pVirtualDirList; -// Mutex to synchronize the subscription handling at the client side -CLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex; ) +#ifdef INCLUDE_CLIENT_APIS +/*! Mutex to synchronize the subscription handling at the client side. */ +ithread_mutex_t GlobalClientSubscribeMutex; +#endif /* INCLUDE_CLIENT_APIS */ -// rwlock to synchronize handles (root device or control point handle) - ithread_rwlock_t GlobalHndRWLock; +/*! rwlock to synchronize handles (root device or control point handle). */ +ithread_rwlock_t GlobalHndRWLock; -// Mutex to synchronize the uuid creation process - ithread_mutex_t gUUIDMutex; +/*! Mutex to synchronize the uuid creation process. */ +ithread_mutex_t gUUIDMutex; - TimerThread gTimerThread; +/*! Initialization mutex. */ +ithread_mutex_t gSDKInitMutex = PTHREAD_MUTEX_INITIALIZER; - ThreadPool gSendThreadPool; - ThreadPool gRecvThreadPool; - ThreadPool gMiniServerThreadPool; +/*! Global timer thread. */ +TimerThread gTimerThread; -//Flag to indicate the state of web server - WebServerState bWebServerState = WEB_SERVER_DISABLED; +/*! Send thread pool. */ +ThreadPool gSendThreadPool; -// static buffer to store the local host ip address or host name - char LOCAL_HOST[LINE_SIZE]; +/*! Receive thread pool. */ +ThreadPool gRecvThreadPool; -// local port for the mini-server - unsigned short LOCAL_PORT; +/*! Mini server thread pool. */ +ThreadPool gMiniServerThreadPool; -// UPnP device and control point handle table - void *HandleTable[NUM_HANDLE]; +/*! Flag to indicate the state of web server */ +WebServerState bWebServerState = WEB_SERVER_DISABLED; -//This structure is for virtual directory callbacks - struct UpnpVirtualDirCallbacks virtualDirCallback; +/*! Static buffer to contain interface name. (extern'ed in upnp.h) */ +char gIF_NAME[LINE_SIZE] = { '\0' }; -// a local dir which serves as webserver root - extern membuffer gDocumentRootDir; +/*! Static buffer to contain interface IPv4 address. (extern'ed in upnp.h) */ +char gIF_IPV4[22]/* INET_ADDRSTRLEN*/ = { '\0' }; -// Maximum content-length that the SDK will process on an incoming packet. -// Content-Length exceeding this size will be not processed and error 413 -// (HTTP Error Code) will be returned to the remote end point. -size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; // in bytes +/*! Static buffer to contain interface IPv6 address. (extern'ed in upnp.h) */ +char gIF_IPV6[65]/* INET6_ADDRSTRLEN*/ = { '\0' }; -// Global variable to denote the state of Upnp SDK -// = 0 if uninitialized, = 1 if initialized. - int UpnpSdkInit = 0; +/*! Contains interface index. (extern'ed in upnp.h) */ +int gIF_INDEX = -1; -// Global variable to denote the state of Upnp SDK device registration. -// = 0 if unregistered, = 1 if registered. - int UpnpSdkDeviceRegistered = 0; +/*! local IPv4 port for the mini-server */ +unsigned short LOCAL_PORT_V4; -// Global variable to denote the state of Upnp SDK client registration. -// = 0 if unregistered, = 1 if registered. - int UpnpSdkClientRegistered = 0; +/*! local IPv6 port for the mini-server */ +unsigned short LOCAL_PORT_V6; -/**************************************************************************** - * Function: UpnpInit +/*! UPnP device and control point handle table */ +void *HandleTable[NUM_HANDLE]; + +/*! a local dir which serves as webserver root */ +extern membuffer gDocumentRootDir; + +/*! Maximum content-length (in bytes) that the SDK will process on an incoming + * packet. Content-Length exceeding this size will be not processed and + * error 413 (HTTP Error Code) will be returned to the remote end point. */ +size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; + +/*! Global variable to denote the state of Upnp SDK == 0 if uninitialized, + * == 1 if initialized. */ +int UpnpSdkInit = 0; + +/*! Global variable to denote the state of Upnp SDK client registration. + * == 0 if unregistered, == 1 if registered. */ +int UpnpSdkClientRegistered = 0; + +/*! Global variable to denote the state of Upnp SDK IPv4 device registration. + * == 0 if unregistered, == 1 if registered. */ +int UpnpSdkDeviceRegisteredV4 = 0; + +/*! Global variable to denote the state of Upnp SDK IPv6 device registration. + * == 0 if unregistered, == 1 if registered. */ +int UpnpSdkDeviceregisteredV6 = 0; + +/*! Global variable used in discovery notifications. */ +Upnp_SID gUpnpSdkNLSuuid; + + +/*! + * \brief (Windows Only) Initializes the Windows Winsock library. * - * Parameters: - * IN const char * HostIP: Local IP Address - * IN short DestPort: Local Port to listen for incoming connections - * Description: - * Initializes - * - Mutex objects, - * - Handle Table - * - Thread Pool and Thread Pool Attributes - * - MiniServer(starts listening for incoming requests) - * and WebServer (Sends request to the - * Upper Layer after HTTP Parsing) - * - Checks for IP Address passed as an argument. IF NULL, - * gets local host name - * - Sets GENA and SOAP Callbacks. - * - Starts the timer thread. - * - * Returns: - * UPNP_E_SUCCESS on success, nonzero on failure. - * UPNP_E_INIT_FAILED if Initialization fails. - * UPNP_E_INIT if UPnP is already initialized - *****************************************************************************/ -int UpnpInit( IN const char *HostIP, - IN unsigned short DestPort ) + * \return UPNP_E_SUCCESS on success, UPNP_E_INIT_FAILED on failure. + */ +static int WinsockInit(void) { - int retVal = 0; - ThreadPoolAttr attr; + int retVal = UPNP_E_SUCCESS; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int err; -#endif - if( UpnpSdkInit == 1 ) { - // already initialized - return UPNP_E_INIT; - } - -#ifdef WIN32 - wVersionRequested = MAKEWORD( 2, 2 ); - - err = WSAStartup( wVersionRequested, &wsaData ); - if ( err != 0 ) { + wVersionRequested = MAKEWORD(2, 2); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ + retVal = UPNP_E_INIT_FAILED; + goto exit_function; + } + /* Confirm that the WinSock DLL supports 2.2. + * Note that if the DLL supports versions greater + * than 2.2 in addition to 2.2, it will still return + * 2.2 in wVersion since that is the version we + * requested. */ + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 2) { + /* Tell the user that we could not find a usable + * WinSock DLL. */ + WSACleanup(); + retVal = UPNP_E_INIT_FAILED; + goto exit_function; + } + /* The WinSock DLL is acceptable. Proceed. */ +exit_function: +#else +#endif + return retVal; +} + + +/*! + * \brief Initializes the global mutexes used by the UPnP SDK. + * + * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not + * be initialized. + */ +static int UpnpInitMutexes(void) +{ +#ifdef __CYGWIN__ + /* On Cygwin, pthread_mutex_init() fails without this memset. */ + /* TODO: Fix Cygwin so we don't need this memset(). */ + memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock)); +#endif + if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) { return UPNP_E_INIT_FAILED; } - /* Confirm that the WinSock DLL supports 2.2.*/ - /* Note that if the DLL supports versions greater */ - /* than 2.2 in addition to 2.2, it will still return */ - /* 2.2 in wVersion since that is the version we */ - /* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 2 ) { - /* Tell the user that we could not find a usable */ - /* WinSock DLL. */ - WSACleanup( ); - return UPNP_E_INIT_FAILED; + if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) { + return UPNP_E_INIT_FAILED; + } + /* initialize subscribe mutex. */ +#ifdef INCLUDE_CLIENT_APIS + if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) { + return UPNP_E_INIT_FAILED; + } +#endif + return UPNP_E_SUCCESS; +} + + +/*! + * \brief Initializes the global threadm pools used by the UPnP SDK. + * + * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not + * be initialized. + */ +static int UpnpInitThreadPools(void) +{ + int ret = UPNP_E_SUCCESS; + ThreadPoolAttr attr; + + TPAttrInit(&attr); + TPAttrSetMaxThreads(&attr, MAX_THREADS); + TPAttrSetMinThreads(&attr, MIN_THREADS); + TPAttrSetJobsPerThread(&attr, JOBS_PER_THREAD); + TPAttrSetIdleTime(&attr, THREAD_IDLE_TIME); + TPAttrSetMaxJobsTotal(&attr, MAX_JOBS_TOTAL); + + if (ThreadPoolInit(&gSendThreadPool, &attr) != UPNP_E_SUCCESS) { + ret = UPNP_E_INIT_FAILED; + goto exit_function; } - /* The WinSock DLL is acceptable. Proceed. */ -#endif + if (ThreadPoolInit(&gRecvThreadPool, &attr) != UPNP_E_SUCCESS) { + ret = UPNP_E_INIT_FAILED; + goto exit_function; + } - membuffer_init( &gDocumentRootDir ); + if (ThreadPoolInit(&gMiniServerThreadPool, &attr) != UPNP_E_SUCCESS) { + ret = UPNP_E_INIT_FAILED; + goto exit_function; + } - srand( time( NULL ) ); // needed by SSDP or other parts +exit_function: + if (ret != UPNP_E_SUCCESS) { + UpnpSdkInit = 0; + UpnpFinish(); + } - if( UpnpInitLog() != UPNP_E_SUCCESS ) { - return UPNP_E_INIT_FAILED; - } + return ret; +} - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInit\n" ); - // initialize mutex -#ifdef __CYGWIN__ - /* On Cygwin, pthread_mutex_init() fails without this memset. */ - /* TODO: Fix Cygwin so we don't need this memset(). */ - memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock)); -#endif - if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } - if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } - // initialize subscribe mutex -#ifdef INCLUDE_CLIENT_APIS - if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } -#endif +/*! + * \brief Performs the initial steps in initializing the UPnP SDK. + * + * \li Winsock library is initialized for the process (Windows specific). + * \li The logging (for debug messages) is initialized. + * \li Mutexes, Handle table and thread pools are allocated and initialized. + * \li Callback functions for SOAP and GENA are set, if they're enabled. + * \li The SDK timer thread is initialized. + * + * \return UPNP_E_SUCCESS on success. + */ +static int UpnpInitPreamble(void) +{ + int retVal = UPNP_E_SUCCESS; + int i; + uuid_upnp nls_uuid; - HandleLock(); - if( HostIP != NULL ) { - strcpy( LOCAL_HOST, HostIP ); - } else { - if( getlocalhostname( LOCAL_HOST ) != UPNP_E_SUCCESS ) { - HandleUnlock(); - return UPNP_E_INIT_FAILED; - } - } + retVal = WinsockInit(); + if (retVal != UPNP_E_SUCCESS) { + return retVal; + } - if( UpnpSdkInit != 0 ) { - HandleUnlock(); - return UPNP_E_INIT; - } + /* needed by SSDP or other parts. */ + srand((unsigned int)time(NULL)); - InitHandleList(); - HandleUnlock(); + /* Initialize debug output. */ + retVal = UpnpInitLog(); + if (retVal != UPNP_E_SUCCESS) { + /* UpnpInitLog does not return a valid UPNP_E_*. */ + return UPNP_E_INIT_FAILED; + } - TPAttrInit( &attr ); - TPAttrSetMaxThreads( &attr, MAX_THREADS ); - TPAttrSetMinThreads( &attr, MIN_THREADS ); - TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD ); - TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME ); - TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL ); + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInitPreamble\n" ); - if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } + /* Initialize SDK global mutexes. */ + retVal = UpnpInitMutexes(); + if (retVal != UPNP_E_SUCCESS) { + return retVal; + } - if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } + /* Create the NLS uuid. */ + uuid_create(&nls_uuid); + uuid_unpack(&nls_uuid, gUpnpSdkNLSuuid); - if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } + /* Initializes the handle list. */ + HandleLock(); + for (i = 0; i < NUM_HANDLE; ++i) { + HandleTable[i] = NULL; + } + HandleUnlock(); + + /* Initialize SDK global thread pools. */ + retVal = UpnpInitThreadPools(); + if (retVal != UPNP_E_SUCCESS) { + return retVal; + } - UpnpSdkInit = 1; #if EXCLUDE_SOAP == 0 - SetSoapCallback( soap_device_callback ); + SetSoapCallback(soap_device_callback); #endif + #if EXCLUDE_GENA == 0 - SetGenaCallback( genaCallback ); + SetGenaCallback(genaCallback); #endif - if( ( retVal = TimerThreadInit( &gTimerThread, - &gSendThreadPool ) ) != - UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return retVal; - } + /* Initialize the SDK timer thread. */ + retVal = TimerThreadInit( &gTimerThread, &gSendThreadPool ); + if (retVal != UPNP_E_SUCCESS) { + UpnpFinish(); + + return retVal; + } + + return UPNP_E_SUCCESS; +} + + +/*! + * \brief Finishes initializing the UPnP SDK. + * \li The MiniServer is started, if enabled. + * \li The WebServer is started, if enabled. + * + * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not + * be initialized. + */ +static int UpnpInitStartServers( + /*! [in] Local Port to listen for incoming connections. */ + unsigned short DestPort) +{ + int retVal = 0; + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Entering UpnpInitStartServers\n" ); + #if EXCLUDE_MINISERVER == 0 - if( ( retVal = StartMiniServer( DestPort ) ) <= 0 ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "Miniserver failed to start" ); - UpnpFinish(); - UpnpSdkInit = 0; - if( retVal != -1 ) - return retVal; - else // if miniserver is already running for unknown reasons! - return UPNP_E_INIT_FAILED; - } + LOCAL_PORT_V4 = DestPort; + LOCAL_PORT_V6 = DestPort; + retVal = StartMiniServer(&LOCAL_PORT_V4, &LOCAL_PORT_V6); + if (retVal != UPNP_E_SUCCESS) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "Miniserver failed to start"); + UpnpFinish(); + return retVal; + } #endif - DestPort = retVal; - LOCAL_PORT = DestPort; #if EXCLUDE_WEB_SERVER == 0 - if( ( retVal = - UpnpEnableWebserver( WEB_SERVER_ENABLED ) ) != UPNP_E_SUCCESS ) { - UpnpFinish(); - UpnpSdkInit = 0; - return retVal; - } + membuffer_init(&gDocumentRootDir); + retVal = UpnpEnableWebserver(WEB_SERVER_ENABLED); + if (retVal != UPNP_E_SUCCESS) { + UpnpFinish(); + return retVal; + } #endif - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Host Ip: %s Host Port: %d\n", LOCAL_HOST, - LOCAL_PORT ); + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "Exiting UpnpInitStartServers\n"); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInit\n" ); - - return UPNP_E_SUCCESS; - -} /***************** end of UpnpInit ******************/ - -#ifdef DEBUG -static void -PrintThreadPoolStats( - ThreadPool *tp, - const char *DbgFileName, - int DbgLineNo, - const char *msg) -{ - ThreadPoolStats stats; - ThreadPoolGetStats(tp, &stats); - UpnpPrintf(UPNP_INFO, API, DbgFileName, DbgLineNo, - "%s\n" - "High Jobs pending: %d\n" - "Med Jobs Pending: %d\n" - "Low Jobs Pending: %d\n" - "Average wait in High Q in milliseconds: %lf\n" - "Average wait in Med Q in milliseconds: %lf\n" - "Average wait in Low Q in milliseconds: %lf\n" - "Max Threads Used: %d\n" - "Worker Threads: %d\n" - "Persistent Threads: %d\n" - "Idle Threads: %d\n" - "Total Threads: %d\n" - "Total Work Time: %lf\n" - "Total Idle Time: %lf\n", - msg, - stats.currentJobsHQ, - stats.currentJobsMQ, - stats.currentJobsLQ, - stats.avgWaitHQ, - stats.avgWaitMQ, - stats.avgWaitLQ, - stats.maxThreads, - stats.workerThreads, - stats.persistentThreads, - stats.idleThreads, - stats.totalThreads, - stats.totalWorkTime, - stats.totalIdleTime); + return UPNP_E_SUCCESS; } -#else /* DEBUG */ -static UPNP_INLINE void -PrintThreadPoolStats( - ThreadPool *tp, - const char *DbgFileName, - int DbgLineNo, - const char *msg) + + +int UpnpInit(const char *HostIP, unsigned short DestPort) { + int retVal = UPNP_E_SUCCESS; + + /* Initializes the ithread library */ + ithread_initialize_library(); + + ithread_mutex_lock(&gSDKInitMutex); + + /* Check if we're already initialized. */ + if (UpnpSdkInit == 1) { + retVal = UPNP_E_INIT; + goto exit_function; + } + + /* Perform initialization preamble. */ + retVal = UpnpInitPreamble(); + if (retVal != UPNP_E_SUCCESS) { + goto exit_function; + } + + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "UpnpInit with HostIP=%s, DestPort=%d.\n", + HostIP ? HostIP : "", DestPort); + + /* Verify HostIP, if provided, or find it ourselves. */ + if (HostIP != NULL) { + strncpy(gIF_IPV4, HostIP, sizeof(gIF_IPV4)); + } else { + if( getlocalhostname( gIF_IPV4, sizeof(gIF_IPV4) ) != UPNP_E_SUCCESS ) { + retVal = UPNP_E_INIT_FAILED; + goto exit_function; + } + } + + /* Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized. */ + UpnpSdkInit = 1; + + /* Finish initializing the SDK. */ + retVal = UpnpInitStartServers(DestPort); + if (retVal != UPNP_E_SUCCESS) { + UpnpSdkInit = 0; + goto exit_function; + } + + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "Host Ip: %s Host Port: %d\n", gIF_IPV4, + LOCAL_PORT_V4); + +exit_function: + ithread_mutex_unlock(&gSDKInitMutex); + + return retVal; } -#endif /* DEBUG */ -/**************************************************************************** - * Function: UpnpFinish - * - * Parameters: NONE - * - * Description: - * Checks for pending jobs and threads - * Unregisters either the client or device - * Shuts down the Timer Thread - * Stops the Mini Server - * Uninitializes the Thread Pool - * For Win32 cleans up Winsock Interface - * Cleans up mutex objects - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - *****************************************************************************/ -int -UpnpFinish(void) +int UpnpInit2(const char *IfName, unsigned short DestPort) +{ + int retVal; + + /* Initializes the ithread library */ + ithread_initialize_library(); + + ithread_mutex_lock(&gSDKInitMutex); + + /* Check if we're already initialized. */ + if (UpnpSdkInit == 1) { + retVal = UPNP_E_INIT; + goto exit_function; + } + + /* Perform initialization preamble. */ + retVal = UpnpInitPreamble(); + if (retVal != UPNP_E_SUCCESS) { + goto exit_function; + } + + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "UpnpInit2 with IfName=%s, DestPort=%d.\n", + IfName ? IfName : "", DestPort); + + /* Retrieve interface information (Addresses, index, etc). */ + retVal = UpnpGetIfInfo( IfName ); + if (retVal != UPNP_E_SUCCESS) { + goto exit_function; + } + + /* Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized. */ + UpnpSdkInit = 1; + + /* Finish initializing the SDK. */ + retVal = UpnpInitStartServers(DestPort); + if (retVal != UPNP_E_SUCCESS) { + UpnpSdkInit = 0; + goto exit_function; + } + +exit_function: + ithread_mutex_unlock(&gSDKInitMutex); + + return UPNP_E_SUCCESS; +} + + +int UpnpFinish(void) { #ifdef INCLUDE_DEVICE_APIS - UpnpDevice_Handle device_handle; + UpnpDevice_Handle device_handle; #endif #ifdef INCLUDE_CLIENT_APIS - UpnpClient_Handle client_handle; + UpnpClient_Handle client_handle; #endif - struct Handle_Info *temp; + struct Handle_Info *temp; -#ifdef WIN32 -// WSACleanup(); -#endif + if (UpnpSdkInit != 1) { + return UPNP_E_FINISH; + } - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Inside UpnpFinish : UpnpSdkInit is :%d:\n", UpnpSdkInit ); - if( UpnpSdkInit == 1 ) { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "UpnpFinish : UpnpSdkInit is ONE\n" ); - } - PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); - PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); - PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "Inside UpnpFinish: UpnpSdkInit is %d\n", UpnpSdkInit); + if (UpnpSdkInit == 1) { + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "UpnpFinish: UpnpSdkInit is ONE\n"); + } + PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); + PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); + PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); #ifdef INCLUDE_DEVICE_APIS - if( GetDeviceHandleInfo( &device_handle, &temp ) == HND_DEVICE ) - UpnpUnRegisterRootDevice( device_handle ); + if (GetDeviceHandleInfo(AF_INET, &device_handle, &temp) == HND_DEVICE ) { + UpnpUnRegisterRootDevice(device_handle); + } + if (GetDeviceHandleInfo(AF_INET6, &device_handle, &temp) == HND_DEVICE ) { + UpnpUnRegisterRootDevice(device_handle); + } #endif #ifdef INCLUDE_CLIENT_APIS - if( GetClientHandleInfo( &client_handle, &temp ) == HND_CLIENT ) - UpnpUnRegisterClient( client_handle ); + if (GetClientHandleInfo(&client_handle, &temp) == HND_CLIENT) { + UpnpUnRegisterClient(client_handle); + } #endif - TimerThreadShutdown( &gTimerThread ); - StopMiniServer(); + TimerThreadShutdown(&gTimerThread); + StopMiniServer(); #if EXCLUDE_WEB_SERVER == 0 - web_server_destroy(); + web_server_destroy(); #endif - ThreadPoolShutdown(&gMiniServerThreadPool); - ThreadPoolShutdown(&gRecvThreadPool); - ThreadPoolShutdown(&gSendThreadPool); - - PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); - PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); - PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); + ThreadPoolShutdown(&gMiniServerThreadPool); + PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); + ThreadPoolShutdown(&gRecvThreadPool); + PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); + ThreadPoolShutdown(&gSendThreadPool); + PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); #ifdef INCLUDE_CLIENT_APIS - ithread_mutex_destroy(&GlobalClientSubscribeMutex); + ithread_mutex_destroy(&GlobalClientSubscribeMutex); #endif - ithread_rwlock_destroy(&GlobalHndRWLock); - ithread_mutex_destroy(&gUUIDMutex); + ithread_rwlock_destroy(&GlobalHndRWLock); + ithread_mutex_destroy(&gUUIDMutex); - // remove all virtual dirs - UpnpRemoveAllVirtualDirs(); + /* remove all virtual dirs */ + UpnpRemoveAllVirtualDirs(); - // allow static linking -#ifdef WIN32 -#ifdef PTW32_STATIC_LIB - pthread_win32_thread_detach_np(); -#endif -#endif + /* Clean-up ithread library resources */ + ithread_cleanup_library(); - UpnpSdkInit = 0; - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Exiting UpnpFinish : UpnpSdkInit is :%d:\n", UpnpSdkInit); - UpnpCloseLog(); - - return UPNP_E_SUCCESS; + UpnpSdkInit = 0; + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Exiting UpnpFinish: UpnpSdkInit is :%d:\n", UpnpSdkInit); + UpnpCloseLog(); + return UPNP_E_SUCCESS; } -/*************************** End of UpnpFinish *****************************/ -/****************************************************************************** - * Function: UpnpGetServerPort - * - * Parameters: NONE - * - * Description: - * Gives back the miniserver port. - * - * Return Values: - * local port on success, zero on failure. - *****************************************************************************/ -unsigned short -UpnpGetServerPort(void) + +unsigned short UpnpGetServerPort(void) { + if (UpnpSdkInit != 1) { + return 0; + } - if( UpnpSdkInit != 1 ) - return 0; - - return LOCAL_PORT; + return LOCAL_PORT_V4; } -/*************************************************************************** - * Function: UpnpGetServerIpAddress - * - * Parameters: NONE - * - * Description: - * Gives back the local ipaddress. - * - * Return Values: char * - * return the IP address string on success else NULL of failure - ***************************************************************************/ -char * -UpnpGetServerIpAddress(void) + +unsigned short UpnpGetServerPort6(void) { + if (UpnpSdkInit != 1) { + return 0; + } - if( UpnpSdkInit != 1 ) - return NULL; - - return LOCAL_HOST; + return LOCAL_PORT_V6; } -#ifdef INCLUDE_DEVICE_APIS -/**************************************************************************** - * Function: UpnpRegisterRootDevice - * - * Parameters: - * IN const char *DescUrl:Pointer to a string containing the - * description URL for this root device instance. - * IN Upnp_FunPtr Callback: Pointer to the callback function for - * receiving asynchronous events. - * IN const void *Cookie: Pointer to user data returned with the - * callback function when invoked. - * OUT UpnpDevice_Handle *Hnd: Pointer to a variable to store the - * new device handle. - * - * Description: - * This function registers a device application with - * the UPnP Library. A device application cannot make any other API - * calls until it registers using this function. - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - *****************************************************************************/ -int -UpnpRegisterRootDevice( IN const char *DescUrl, - IN Upnp_FunPtr Fun, - IN const void *Cookie, - OUT UpnpDevice_Handle * Hnd ) + +char *UpnpGetServerIpAddress(void) { + if (UpnpSdkInit != 1) { + return NULL; + } - struct Handle_Info *HInfo; - int retVal = 0; - - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Inside UpnpRegisterRootDevice\n" ); - - HandleLock(); - if( UpnpSdkDeviceRegistered ) { - HandleUnlock(); - return UPNP_E_ALREADY_REGISTERED; - } - - if( Hnd == NULL || Fun == NULL || - DescUrl == NULL || strlen( DescUrl ) == 0 ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - - if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) { - HandleUnlock(); - return UPNP_E_OUTOF_MEMORY; - } - - HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) ); - if( HInfo == NULL ) { - HandleUnlock(); - return UPNP_E_OUTOF_MEMORY; - } - HandleTable[*Hnd] = HInfo; - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Root device URL is %s\n", DescUrl ); - - HInfo->aliasInstalled = 0; - HInfo->HType = HND_DEVICE; - strcpy( HInfo->DescURL, DescUrl ); - HInfo->Callback = Fun; - HInfo->Cookie = ( void * )Cookie; - HInfo->MaxAge = DEFAULT_MAXAGE; - HInfo->DeviceList = NULL; - HInfo->ServiceList = NULL; - HInfo->DescDocument = NULL; - CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); ) - CLIENTONLY( HInfo->ClientSubList = NULL; ) - HInfo->MaxSubscriptions = UPNP_INFINITE; - HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; - - if( ( retVal = - UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) ) - != UPNP_E_SUCCESS ) { - CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) ); - FreeHandle( *Hnd ); - HandleUnlock(); - return retVal; - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: Valid Description\n" ); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: DescURL : %s\n", - HInfo->DescURL ); - - HInfo->DeviceList = - ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" ); - if( !HInfo->DeviceList ) { - CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) ); - ixmlDocument_free( HInfo->DescDocument ); - FreeHandle( *Hnd ); - HandleUnlock(); - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: No devices found for RootDevice\n" ); - return UPNP_E_INVALID_DESC; - } - - HInfo->ServiceList = ixmlDocument_getElementsByTagName( - HInfo->DescDocument, "serviceList" ); - if( !HInfo->ServiceList ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: No services found for RootDevice\n" ); - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: Gena Check\n" ); - //******************************* - // GENA SET UP - //******************************* - if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument, - &HInfo->ServiceTable, HInfo->DescURL ) ) { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice: GENA Service Table \n" ); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Here are the known services: \n" ); - printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API ); - } else { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "\nUpnpRegisterRootDevice2: Empty service table\n" ); - } - - UpnpSdkDeviceRegistered = 1; - HandleUnlock(); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Exiting RegisterRootDevice Successfully\n" ); - - return UPNP_E_SUCCESS; + return gIF_IPV4; +} + + +char *UpnpGetServerIp6Address(void) +{ + if( UpnpSdkInit != 1 ) { + return NULL; + } + + return gIF_IPV6; } -#endif // INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS -/**************************************************************************** - * Function: UpnpUnRegisterRootDevice - * - * Parameters: - * IN UpnpDevice_Handle Hnd: The handle of the device instance - * to unregister - * Description: - * This function unregisters a root device registered with - * UpnpRegisterRootDevice} or UpnpRegisterRootDevice2. After this call, the - * UpnpDevice_Handle Hnd is no longer valid. For all advertisements that - * have not yet expired, the UPnP library sends a device unavailable message - * automatically. - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - *****************************************************************************/ -int -UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) +int UpnpRegisterRootDevice( + const char *DescUrl, + Upnp_FunPtr Fun, + const void *Cookie, + UpnpDevice_Handle *Hnd) +{ + struct Handle_Info *HInfo = NULL; + int retVal = 0; + int hasServiceTable = 0; + + HandleLock(); + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpRegisterRootDevice\n"); + + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } + + if (Hnd == NULL || + Fun == NULL || + DescUrl == NULL || + strlen(DescUrl) == 0) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + if (UpnpSdkDeviceRegisteredV4 == 1) { + retVal = UPNP_E_ALREADY_REGISTERED; + goto exit_function; + } + + *Hnd = GetFreeHandle(); + if (*Hnd == UPNP_E_OUTOF_HANDLE) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + + HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); + if (HInfo == NULL) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + HandleTable[*Hnd] = HInfo; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Root device URL is %s\n", DescUrl ); + + HInfo->aliasInstalled = 0; + HInfo->HType = HND_DEVICE; + strcpy(HInfo->DescURL, DescUrl); + HInfo->Callback = Fun; + HInfo->Cookie = (void *)Cookie; + HInfo->MaxAge = DEFAULT_MAXAGE; + HInfo->DeviceList = NULL; + HInfo->ServiceList = NULL; + HInfo->DescDocument = NULL; + CLIENTONLY( ListInit(&HInfo->SsdpSearchList, NULL, NULL); ) + CLIENTONLY( HInfo->ClientSubList = NULL; ) + HInfo->MaxSubscriptions = UPNP_INFINITE; + HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AF_INET; + + retVal = UpnpDownloadXmlDoc(HInfo->DescURL, &(HInfo->DescDocument)); + if (retVal != UPNP_E_SUCCESS) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: error downloading Document: %d\n", + retVal); + CLIENTONLY( ListDestroy(&HInfo->SsdpSearchList, 0); ) + FreeHandle(*Hnd); + goto exit_function; + } + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: Valid Description\n" + "UpnpRegisterRootDevice: DescURL : %s\n", + HInfo->DescURL); + + HInfo->DeviceList = + ixmlDocument_getElementsByTagName(HInfo->DescDocument, "device"); + if (!HInfo->DeviceList) { + CLIENTONLY( ListDestroy(&HInfo->SsdpSearchList, 0); ) + ixmlDocument_free(HInfo->DescDocument); + FreeHandle(*Hnd); + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: No devices found for RootDevice\n"); + retVal = UPNP_E_INVALID_DESC; + goto exit_function; + } + + HInfo->ServiceList = ixmlDocument_getElementsByTagName( + HInfo->DescDocument, "serviceList"); + if (!HInfo->ServiceList) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: No services found for RootDevice\n"); + } + + /* + * GENA SET UP + */ + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: Gena Check\n"); + hasServiceTable = getServiceTable( + (IXML_Node *)HInfo->DescDocument, + &HInfo->ServiceTable, + HInfo->DescURL); + if (hasServiceTable) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: GENA Service Table\n" + "Here are the known services:\n"); + printServiceTable( &HInfo->ServiceTable, UPNP_ALL, API ); + } else { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "\nUpnpRegisterRootDevice: Empty service table\n"); + } + + UpnpSdkDeviceRegisteredV4 = 1; + + retVal = UPNP_E_SUCCESS; + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting RegisterRootDevice, return value == %d\n", retVal); + HandleUnlock(); + + return retVal; +} +#endif /* INCLUDE_DEVICE_APIS */ + + +/*! + * \brief Fills the sockadr_in with miniserver information. + */ +static int GetDescDocumentAndURL( + /* [in] pointer to server address structure. */ + Upnp_DescType descriptionType, + /* [in] . */ + char *description, + /* [in] . */ + unsigned int bufferLen, + /* [in] . */ + int config_baseURL, + /* [in] . */ + int AddressFamily, + /* [out] . */ + IXML_Document **xmlDoc, + /* [out] . */ + char *descURL); + + +#ifdef INCLUDE_DEVICE_APIS +int UpnpRegisterRootDevice2( + Upnp_DescType descriptionType, + const char *description_const, + size_t bufferLen, // ignored unless descType == UPNPREG_BUF_DESC + int config_baseURL, + Upnp_FunPtr Fun, + const void *Cookie, + UpnpDevice_Handle *Hnd) +{ + struct Handle_Info *HInfo = NULL; + int retVal = 0; + int hasServiceTable = 0; + char *description = (char *)description_const; + + HandleLock(); + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpRegisterRootDevice2\n"); + + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } + + if (Hnd == NULL || Fun == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + if (UpnpSdkDeviceRegisteredV4 == 1) { + retVal = UPNP_E_ALREADY_REGISTERED; + goto exit_function; + } + + *Hnd = GetFreeHandle(); + if (*Hnd == UPNP_E_OUTOF_HANDLE) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + + HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); + if (HInfo == NULL) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + HandleTable[*Hnd] = HInfo; + + // prevent accidental removal of a non-existent alias + HInfo->aliasInstalled = 0; + + retVal = GetDescDocumentAndURL( + descriptionType, description, bufferLen, + config_baseURL, AF_INET, + &HInfo->DescDocument, HInfo->DescURL); + if (retVal != UPNP_E_SUCCESS) { + FreeHandle(*Hnd); + goto exit_function; + } + + HInfo->aliasInstalled = config_baseURL != 0; + HInfo->HType = HND_DEVICE; + HInfo->Callback = Fun; + HInfo->Cookie = (void *)Cookie; + HInfo->MaxAge = DEFAULT_MAXAGE; + HInfo->DeviceList = NULL; + HInfo->ServiceList = NULL; + CLIENTONLY( ListInit(&HInfo->SsdpSearchList, NULL, NULL); ) + CLIENTONLY( HInfo->ClientSubList = NULL; ) + HInfo->MaxSubscriptions = UPNP_INFINITE; + HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AF_INET; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice2: Valid Description\n" + "UpnpRegisterRootDevice2: DescURL : %s\n", + HInfo->DescURL); + + HInfo->DeviceList = + ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" ); + if (!HInfo->DeviceList) { + CLIENTONLY( ListDestroy(&HInfo->SsdpSearchList, 0); ) + ixmlDocument_free(HInfo->DescDocument); + FreeHandle(*Hnd); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice2: No devices found for RootDevice\n" ); + retVal = UPNP_E_INVALID_DESC; + goto exit_function; + } + + HInfo->ServiceList = ixmlDocument_getElementsByTagName( + HInfo->DescDocument, "serviceList" ); + if (!HInfo->ServiceList) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice2: No services found for RootDevice\n"); + } + + /* + * GENA SET UP + */ + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice2: Gena Check\n" ); + hasServiceTable = getServiceTable( + (IXML_Node *)HInfo->DescDocument, + &HInfo->ServiceTable, + HInfo->DescURL); + if (hasServiceTable) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice2: GENA Service Table\n" + "Here are the known services: \n"); + printServiceTable(&HInfo->ServiceTable, UPNP_ALL, API); + } else { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "\nUpnpRegisterRootDevice2: Empty service table\n"); + } + + UpnpSdkDeviceRegisteredV4 = 1; + + retVal = UPNP_E_SUCCESS; + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting RegisterRootDevice2, return value == %d\n", retVal); + HandleUnlock(); + + return retVal; +} +#endif /* INCLUDE_DEVICE_APIS */ + + +#ifdef INCLUDE_DEVICE_APIS +int UpnpRegisterRootDevice3( + const char *DescUrl, + Upnp_FunPtr Fun, + const void *Cookie, + UpnpDevice_Handle *Hnd, + const int AddressFamily) +{ + struct Handle_Info *HInfo; + int retVal = 0; + int hasServiceTable = 0; + + HandleLock(); + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpRegisterRootDevice3\n"); + + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } + + if (Hnd == NULL || + Fun == NULL || + DescUrl == NULL || + strlen(DescUrl) == 0 || + (AddressFamily != AF_INET && AddressFamily != AF_INET6)) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + if ((AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 1) || + (AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 1)) { + retVal = UPNP_E_ALREADY_REGISTERED; + goto exit_function; + } + + *Hnd = GetFreeHandle(); + if (*Hnd == UPNP_E_OUTOF_HANDLE) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + + HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); + if (HInfo == NULL) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + HandleTable[*Hnd] = HInfo; + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Root device URL is %s\n", DescUrl); + + HInfo->aliasInstalled = 0; + HInfo->HType = HND_DEVICE; + strcpy(HInfo->DescURL, DescUrl); + HInfo->Callback = Fun; + HInfo->Cookie = (void *)Cookie; + HInfo->MaxAge = DEFAULT_MAXAGE; + HInfo->DeviceList = NULL; + HInfo->ServiceList = NULL; + HInfo->DescDocument = NULL; + CLIENTONLY( ListInit(&HInfo->SsdpSearchList, NULL, NULL); ) + CLIENTONLY( HInfo->ClientSubList = NULL; ) + HInfo->MaxSubscriptions = UPNP_INFINITE; + HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AddressFamily; + + retVal = UpnpDownloadXmlDoc(HInfo->DescURL, &(HInfo->DescDocument)); + if (retVal != UPNP_E_SUCCESS) { + CLIENTONLY( ListDestroy(&HInfo->SsdpSearchList, 0); ) + FreeHandle(*Hnd); + goto exit_function; + } + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice3: Valid Description\n" + "UpnpRegisterRootDevice3: DescURL : %s\n", + HInfo->DescURL); + + HInfo->DeviceList = ixmlDocument_getElementsByTagName( + HInfo->DescDocument, "device"); + if (!HInfo->DeviceList) { + CLIENTONLY( ListDestroy(&HInfo->SsdpSearchList, 0); ) + ixmlDocument_free(HInfo->DescDocument); + FreeHandle(*Hnd); + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice3: No devices found for RootDevice\n"); + retVal = UPNP_E_INVALID_DESC; + goto exit_function; + } + + HInfo->ServiceList = ixmlDocument_getElementsByTagName( + HInfo->DescDocument, "serviceList" ); + if (!HInfo->ServiceList) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice3: No services found for RootDevice\n"); + } + + /* + * GENA SET UP + */ + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice3: Gena Check\n" ); + hasServiceTable = getServiceTable( + (IXML_Node *)HInfo->DescDocument, + &HInfo->ServiceTable, + HInfo->DescURL); + if (hasServiceTable) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice3: GENA Service Table \n" + "Here are the known services: \n" ); + printServiceTable(&HInfo->ServiceTable, UPNP_ALL, API); + } else { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "\nUpnpRegisterRootDevice3: Empty service table\n"); + } + + if (AddressFamily == AF_INET) { + UpnpSdkDeviceRegisteredV4 = 1; + } else { + UpnpSdkDeviceregisteredV6 = 1; + } + + retVal = UPNP_E_SUCCESS; + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting RegisterRootDevice3, return value == %d\n", retVal); + HandleUnlock(); + + return retVal; +} +#endif /* INCLUDE_DEVICE_APIS */ + + +#ifdef INCLUDE_DEVICE_APIS +int UpnpUnRegisterRootDevice(UpnpDevice_Handle Hnd) { int retVal = 0; struct Handle_Info *HInfo = NULL; - // struct Handle_Info *info=NULL; - - if( UpnpSdkInit != 1 ) { + if (UpnpSdkInit != 1) { return UPNP_E_FINISH; } - HandleLock(); - if( !UpnpSdkDeviceRegistered ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - HandleUnlock(); - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Inside UpnpUnRegisterRootDevice \n" ); + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "Inside UpnpUnRegisterRootDevice\n"); #if EXCLUDE_GENA == 0 if( genaUnregisterDevice( Hnd ) != UPNP_E_SUCCESS ) return UPNP_E_INVALID_HANDLE; @@ -709,9 +1075,8 @@ UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) HandleUnlock(); #if EXCLUDE_SSDP == 0 - retVal = AdvertiseAndReply( -1, Hnd, 0, ( struct sockaddr_in * )NULL, - ( char * )NULL, ( char * )NULL, - ( char * )NULL, HInfo->MaxAge ); + retVal = AdvertiseAndReply(-1, Hnd, 0, (struct sockaddr *)NULL, + (char *)NULL, (char *)NULL, (char *)NULL, HInfo->MaxAge); #endif HandleLock(); @@ -732,449 +1097,28 @@ UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) } #endif // INTERNAL_WEB_SERVER - FreeHandle( Hnd ); - UpnpSdkDeviceRegistered = 0; + if( HInfo->DeviceAf == AF_INET ) { + UpnpSdkDeviceRegisteredV4 = 0; + } else if( HInfo->DeviceAf == AF_INET6 ) { + UpnpSdkDeviceregisteredV6 = 0; + } + + FreeHandle(Hnd); HandleUnlock(); UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Exiting UpnpUnRegisterRootDevice \n" ); + "Exiting UpnpUnRegisterRootDevice\n" ); return retVal; - -} /****************** End of UpnpUnRegisterRootDevice *********************/ - -#endif //INCLUDE_DEVICE_APIS - -// ************************************************************* -#ifdef INCLUDE_DEVICE_APIS -#ifdef INTERNAL_WEB_SERVER - -/************************************************************************** - * Function: GetNameForAlias - * - * Parameters: - * IN char *name: name of the file - * OUT char** alias: pointer to alias string - * - * Description: - * This function determines alias for given name which is a file name - * or URL. - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - ***************************************************************************/ -static int -GetNameForAlias( IN char *name, - OUT char **alias ) -{ - char *ext; - char *al; - - ext = strrchr( name, '.' ); - if( ext == NULL || strcasecmp( ext, ".xml" ) != 0 ) { - return UPNP_E_EXT_NOT_XML; - } - - al = strrchr( name, '/' ); - if( al == NULL ) { - *alias = name; - } else { - *alias = al; - } - - return UPNP_E_SUCCESS; } +#endif /* INCLUDE_DEVICE_APIS */ -/************************************************************************** - * Function: get_server_addr - * - * Parameters: - * OUT struct sockaddr_in* serverAddr: pointer to server address - * structure - * - * Description: - * This function fills the sockadr_in with miniserver information. - * - * Return Values: VOID - * - ***************************************************************************/ -static void -get_server_addr( OUT struct sockaddr_in *serverAddr ) -{ - memset( serverAddr, 0, sizeof( struct sockaddr_in ) ); - - serverAddr->sin_family = AF_INET; - serverAddr->sin_port = htons( LOCAL_PORT ); - //inet_aton( LOCAL_HOST, &serverAddr->sin_addr ); - serverAddr->sin_addr.s_addr = inet_addr( LOCAL_HOST ); -} - -/************************************************************************** - * Function: GetDescDocumentAndURL ( In the case of device) - * - * Parameters: - * IN Upnp_DescType descriptionType: pointer to server address - * structure - * IN char* description: - * IN unsigned int bufferLen: - * IN int config_baseURL: - * OUT IXML_Document **xmlDoc: - * OUT char descURL[LINE_SIZE]: - * - * Description: - * This function fills the sockadr_in with miniserver information. - * - * Return Values: VOID - * - ***************************************************************************/ -static int -GetDescDocumentAndURL( IN Upnp_DescType descriptionType, - IN char *description, - IN unsigned int bufferLen, - IN int config_baseURL, - OUT IXML_Document ** xmlDoc, - OUT char descURL[LINE_SIZE] ) -{ - int retVal = 0; - char *membuf = NULL; - char aliasStr[LINE_SIZE]; - char *temp_str = NULL; - FILE *fp = NULL; - off_t fileLen; - size_t num_read; - time_t last_modified; - struct stat file_info; - struct sockaddr_in serverAddr; - int rc = UPNP_E_SUCCESS; - - if( description == NULL ) { - return UPNP_E_INVALID_PARAM; - } - // non-URL description must have configuration specified - if( descriptionType != UPNPREG_URL_DESC && ( !config_baseURL ) ) { - return UPNP_E_INVALID_PARAM; - } - // get XML doc and last modified time - if( descriptionType == UPNPREG_URL_DESC ) { - if( ( retVal = - UpnpDownloadXmlDoc( description, - xmlDoc ) ) != UPNP_E_SUCCESS ) { - return retVal; - } - last_modified = time( NULL ); - } else if( descriptionType == UPNPREG_FILENAME_DESC ) { - retVal = stat( description, &file_info ); - if( retVal == -1 ) { - return UPNP_E_FILE_NOT_FOUND; - } - fileLen = file_info.st_size; - last_modified = file_info.st_mtime; - - if( ( fp = fopen( description, "rb" ) ) == NULL ) { - return UPNP_E_FILE_NOT_FOUND; - } - - if( ( membuf = ( char * )malloc( fileLen + 1 ) ) == NULL ) { - fclose( fp ); - return UPNP_E_OUTOF_MEMORY; - } - - num_read = fread( membuf, 1, fileLen, fp ); - if( num_read != fileLen ) { - fclose( fp ); - free( membuf ); - return UPNP_E_FILE_READ_ERROR; - } - - membuf[fileLen] = 0; - fclose( fp ); - rc = ixmlParseBufferEx( membuf, xmlDoc ); - free( membuf ); - } else if( descriptionType == UPNPREG_BUF_DESC ) { - last_modified = time( NULL ); - rc = ixmlParseBufferEx( description, xmlDoc ); - } else { - return UPNP_E_INVALID_PARAM; - } - - if( rc != IXML_SUCCESS && descriptionType != UPNPREG_URL_DESC ) { - if( rc == IXML_INSUFFICIENT_MEMORY ) { - return UPNP_E_OUTOF_MEMORY; - } else { - return UPNP_E_INVALID_DESC; - } - } - // determine alias - if( config_baseURL ) { - if( descriptionType == UPNPREG_BUF_DESC ) { - strcpy( aliasStr, "description.xml" ); - } else // URL or filename - { - retVal = GetNameForAlias( description, &temp_str ); - if( retVal != UPNP_E_SUCCESS ) { - ixmlDocument_free( *xmlDoc ); - return retVal; - } - if( strlen( temp_str ) > ( LINE_SIZE - 1 ) ) { - ixmlDocument_free( *xmlDoc ); - free( temp_str ); - return UPNP_E_URL_TOO_BIG; - } - strcpy( aliasStr, temp_str ); - } - - get_server_addr( &serverAddr ); - - // config - retVal = configure_urlbase( *xmlDoc, &serverAddr, - aliasStr, last_modified, descURL ); - if( retVal != UPNP_E_SUCCESS ) { - ixmlDocument_free( *xmlDoc ); - return retVal; - } - } else // manual - { - if( strlen( description ) > ( LINE_SIZE - 1 ) ) { - ixmlDocument_free( *xmlDoc ); - return UPNP_E_URL_TOO_BIG; - } - strcpy( descURL, description ); - } - - assert( *xmlDoc != NULL ); - - return UPNP_E_SUCCESS; -} - -#else // no web server - -/************************************************************************** - * Function: GetDescDocumentAndURL ( In the case of control point) - * - * Parameters: - * IN Upnp_DescType descriptionType: pointer to server address - * structure - * IN char* description: - * IN unsigned int bufferLen: - * IN int config_baseURL: - * OUT IXML_Document **xmlDoc: - * OUT char *descURL: - * - * Description: - * This function fills the sockadr_in with miniserver information. - * - * Return Values: VOID - * - ***************************************************************************/ -static int -GetDescDocumentAndURL( IN Upnp_DescType descriptionType, - IN char *description, - IN unsigned int bufferLen, - IN int config_baseURL, - OUT IXML_Document ** xmlDoc, - OUT char *descURL ) -{ - int retVal; - - if( ( descriptionType != UPNPREG_URL_DESC ) || config_baseURL ) { - return UPNP_E_NO_WEB_SERVER; - } - - if( description == NULL ) { - return UPNP_E_INVALID_PARAM; - } - - if( strlen( description ) > ( LINE_SIZE - 1 ) ) { - return UPNP_E_URL_TOO_BIG; - } - strcpy( descURL, description ); - - if( ( retVal = - UpnpDownloadXmlDoc( description, xmlDoc ) ) != UPNP_E_SUCCESS ) { - return retVal; - } - - return UPNP_E_SUCCESS; -} - -#endif // INTERNAL_WEB_SERVER -// ******************************************************** - -/**************************************************************************** - * Function: UpnpRegisterRootDevice2 - * - * Parameters: - * IN Upnp_DescType descriptionType: The type of description document. - * IN const char* description: Treated as a URL, file name or - * memory buffer depending on description type. - * IN size_t bufferLen: Length of memory buffer if passing a description - * in a buffer, otherwize ignored. - * IN int config_baseURL: If nonzero, URLBase of description document is - * configured and the description is served using the internal - * web server. - * IN Upnp_FunPtr Fun: Pointer to the callback function for - * receiving asynchronous events. - * IN const void* Cookie: Pointer to user data returned with the - * callback function when invoked. - * OUT UpnpDevice_Handle* Hnd: Pointer to a variable to store - * the new device handle. - * - * Description: - * This function is similar to UpnpRegisterRootDevice except that - * it also allows the description document to be specified as a file or - * a memory buffer. The description can also be configured to have the - * correct IP and port address. - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - *****************************************************************************/ -int -UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, - IN const char *description_const, - IN size_t bufferLen, // ignored unless descType == UPNPREG_BUF_DESC - - IN int config_baseURL, - IN Upnp_FunPtr Fun, - IN const void *Cookie, - OUT UpnpDevice_Handle * Hnd ) -{ - struct Handle_Info *HInfo; - int retVal = 0; - char *description = ( char * )description_const; - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Inside UpnpRegisterRootDevice2\n" ); - - if( Hnd == NULL || Fun == NULL ) { - return UPNP_E_INVALID_PARAM; - } - - HandleLock(); - if( UpnpSdkDeviceRegistered ) { - HandleUnlock(); - return UPNP_E_ALREADY_REGISTERED; - } - - if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) { - HandleUnlock(); - return UPNP_E_OUTOF_MEMORY; - } - - HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) ); - if( HInfo == NULL ) { - HandleUnlock(); - return UPNP_E_OUTOF_MEMORY; - } - HandleTable[*Hnd] = HInfo; - - // prevent accidental removal of a non-existent alias - HInfo->aliasInstalled = 0; - - retVal = GetDescDocumentAndURL( - descriptionType, description, bufferLen, - config_baseURL, &HInfo->DescDocument, HInfo->DescURL ); - - if( retVal != UPNP_E_SUCCESS ) { - FreeHandle( *Hnd ); - HandleUnlock(); - return retVal; - } - - HInfo->aliasInstalled = ( config_baseURL != 0 ); - HInfo->HType = HND_DEVICE; - - HInfo->Callback = Fun; - HInfo->Cookie = ( void * )Cookie; - HInfo->MaxAge = DEFAULT_MAXAGE; - HInfo->DeviceList = NULL; - HInfo->ServiceList = NULL; - - CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); ) - CLIENTONLY( HInfo->ClientSubList = NULL; ) - HInfo->MaxSubscriptions = UPNP_INFINITE; - HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: Valid Description\n" ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: DescURL : %s\n", - HInfo->DescURL ); - - HInfo->DeviceList = - ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" ); - - if( !HInfo->DeviceList ) { - CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ); ) - ixmlDocument_free( HInfo->DescDocument ); - FreeHandle( *Hnd ); - HandleUnlock(); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: No devices found for RootDevice\n" ); - return UPNP_E_INVALID_DESC; - } - - HInfo->ServiceList = ixmlDocument_getElementsByTagName( - HInfo->DescDocument, "serviceList" ); - if( !HInfo->ServiceList ) { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: No services found for RootDevice\n" ); - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: Gena Check\n" ); - //******************************* - // GENA SET UP - //******************************* - if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument, - &HInfo->ServiceTable, HInfo->DescURL ) ) { - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "UpnpRegisterRootDevice2: GENA Service Table\n" ); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Here are the known services: \n" ); - printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API ); - } else { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "\nUpnpRegisterRootDevice2: Empty service table\n" ); - } - - UpnpSdkDeviceRegistered = 1; - HandleUnlock(); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting RegisterRootDevice2 Successfully\n" ); - - return UPNP_E_SUCCESS; -} - -#endif // INCLUDE_DEVICE_APIS #ifdef INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: UpnpRegisterClient - * - * Parameters: - * IN Upnp_FunPtr Fun: Pointer to a function for receiving - * asynchronous events. - * IN const void * Cookie: Pointer to user data returned with the - * callback function when invoked. - * OUT UpnpClient_Handle *Hnd: Pointer to a variable to store - * the new control point handle. - * - * Description: - * This function registers a control point application with the - * UPnP Library. A control point application cannot make any other API - * calls until it registers using this function. - * - * Return Values: int - * - ***************************************************************************/ -int -UpnpRegisterClient( IN Upnp_FunPtr Fun, - IN const void *Cookie, - OUT UpnpClient_Handle * Hnd ) +int UpnpRegisterClient( + Upnp_FunPtr Fun, + const void *Cookie, + UpnpClient_Handle *Hnd) { struct Handle_Info *HInfo; @@ -1223,29 +1167,12 @@ UpnpRegisterClient( IN Upnp_FunPtr Fun, "Exiting UpnpRegisterClient \n" ); return UPNP_E_SUCCESS; - -} /****************** End of UpnpRegisterClient *********************/ -#endif // INCLUDE_CLIENT_APIS +} +#endif /* INCLUDE_CLIENT_APIS */ -/**************************************************************************** - * Function: UpnpUnRegisterClient - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point instance - * to unregister - * Description: - * This function unregisters a client registered with - * UpnpRegisterclient or UpnpRegisterclient2. After this call, the - * UpnpDevice_Handle Hnd is no longer valid. The UPnP Library generates - * no more callbacks after this function returns. - * - * Return Values: - * UPNP_E_SUCCESS on success, nonzero on failure. - *****************************************************************************/ #ifdef INCLUDE_CLIENT_APIS -int -UpnpUnRegisterClient( IN UpnpClient_Handle Hnd ) +int UpnpUnRegisterClient(UpnpClient_Handle Hnd) { struct Handle_Info *HInfo; ListNode *node = NULL; @@ -1273,7 +1200,7 @@ UpnpUnRegisterClient( IN UpnpClient_Handle Hnd ) HandleUnlock(); return UPNP_E_INVALID_HANDLE; } - //clean up search list + /* clean up search list */ node = ListHead( &HInfo->SsdpSearchList ); while( node != NULL ) { searchArg = ( SsdpSearchArg * ) node->item; @@ -1286,42 +1213,248 @@ UpnpUnRegisterClient( IN UpnpClient_Handle Hnd ) } ListDestroy( &HInfo->SsdpSearchList, 0 ); - FreeHandle( Hnd ); + FreeHandle(Hnd); UpnpSdkClientRegistered = 0; HandleUnlock(); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnRegisterClient \n" ); return UPNP_E_SUCCESS; -} /****************** End of UpnpUnRegisterClient *********************/ -#endif // INCLUDE_CLIENT_APIS +} +#endif /* INCLUDE_CLIENT_APIS */ + + +#ifdef INCLUDE_DEVICE_APIS +#ifdef INTERNAL_WEB_SERVER +/*! + * \brief Determines alias for given name which is a file name or URL. + * + * \return UPNP_E_SUCCESS on success, nonzero on failure. + */ +static int GetNameForAlias( + /*! [in] Name of the file. */ + char *name, + /*! [out] Pointer to alias string. */ + char **alias) +{ + char *ext; + char *al; + + ext = strrchr( name, '.' ); + if( ext == NULL || strcasecmp( ext, ".xml" ) != 0 ) { + return UPNP_E_EXT_NOT_XML; + } + + al = strrchr( name, '/' ); + if( al == NULL ) { + *alias = name; + } else { + *alias = al; + } + + return UPNP_E_SUCCESS; +} + +/*! + * \brief Fill the sockadr with IPv4 miniserver information. + */ +static void get_server_addr( + /*! [out] pointer to server address structure. */ + struct sockaddr *serverAddr) +{ + struct sockaddr_in* sa4 = (struct sockaddr_in*)serverAddr; + + memset( serverAddr, 0, sizeof(struct sockaddr_storage) ); + + sa4->sin_family = AF_INET; + inet_pton( AF_INET, gIF_IPV4, &sa4->sin_addr ); + sa4->sin_port = htons( LOCAL_PORT_V4 ); +} + +/*! + * \brief Fill the sockadr with IPv6 miniserver information. + */ +static void get_server_addr6( + /*! [out] pointer to server address structure. */ + struct sockaddr *serverAddr) +{ + struct sockaddr_in6* sa6 = (struct sockaddr_in6*)serverAddr; + + memset( serverAddr, 0, sizeof(struct sockaddr_storage) ); + + sa6->sin6_family = AF_INET6; + inet_pton(AF_INET6, gIF_IPV6, &sa6->sin6_addr ); + sa6->sin6_port = htons( LOCAL_PORT_V6 ); +} + + +static int GetDescDocumentAndURL( + Upnp_DescType descriptionType, + char *description, + unsigned int bufferLen, + int config_baseURL, + int AddressFamily, + IXML_Document **xmlDoc, + char *descURL) +{ + int retVal = 0; + char *membuf = NULL; + char aliasStr[LINE_SIZE]; + char *temp_str = NULL; + FILE *fp = NULL; + off_t fileLen; + size_t num_read; + time_t last_modified; + struct stat file_info; + struct sockaddr_storage serverAddr; + int rc = UPNP_E_SUCCESS; + + if (description == NULL) { + return UPNP_E_INVALID_PARAM; + } + /* non-URL description must have configuration specified */ + if (descriptionType != UPNPREG_URL_DESC && !config_baseURL) { + return UPNP_E_INVALID_PARAM; + } + /* Get XML doc and last modified time */ + if (descriptionType == UPNPREG_URL_DESC) { + retVal = UpnpDownloadXmlDoc(description, xmlDoc); + if (retVal != UPNP_E_SUCCESS) { + return retVal; + } + last_modified = time(NULL); + } else if (descriptionType == UPNPREG_FILENAME_DESC) { + retVal = stat( description, &file_info ); + if (retVal == -1) { + return UPNP_E_FILE_NOT_FOUND; + } + fileLen = file_info.st_size; + last_modified = file_info.st_mtime; + fp = fopen(description, "rb"); + if (fp == NULL) { + return UPNP_E_FILE_NOT_FOUND; + } + membuf = (char *)malloc(fileLen + 1); + if (membuf == NULL) { + fclose(fp); + return UPNP_E_OUTOF_MEMORY; + } + num_read = fread(membuf, 1, fileLen, fp); + if (num_read != fileLen) { + fclose(fp); + free(membuf); + return UPNP_E_FILE_READ_ERROR; + } + membuf[fileLen] = 0; + fclose(fp); + rc = ixmlParseBufferEx(membuf, xmlDoc); + free(membuf); + } else if (descriptionType == UPNPREG_BUF_DESC) { + last_modified = time(NULL); + rc = ixmlParseBufferEx(description, xmlDoc); + } else { + return UPNP_E_INVALID_PARAM; + } + + if (rc != IXML_SUCCESS && descriptionType != UPNPREG_URL_DESC) { + if (rc == IXML_INSUFFICIENT_MEMORY) { + return UPNP_E_OUTOF_MEMORY; + } else { + return UPNP_E_INVALID_DESC; + } + } + /* Determine alias */ + if (config_baseURL) { + if (descriptionType == UPNPREG_BUF_DESC) { + strcpy( aliasStr, "description.xml" ); + } else { + /* URL or filename */ + retVal = GetNameForAlias(description, &temp_str); + if (retVal != UPNP_E_SUCCESS) { + ixmlDocument_free(*xmlDoc); + return retVal; + } + if (strlen(temp_str) > (LINE_SIZE - 1)) { + ixmlDocument_free(*xmlDoc); + free(temp_str); + return UPNP_E_URL_TOO_BIG; + } + strcpy(aliasStr, temp_str); + } + if(AddressFamily == AF_INET) { + get_server_addr((struct sockaddr *)&serverAddr); + } else { + get_server_addr6((struct sockaddr *)&serverAddr); + } + + /* config */ + retVal = configure_urlbase(*xmlDoc, (struct sockaddr *)&serverAddr, + aliasStr, last_modified, descURL); + if (retVal != UPNP_E_SUCCESS) { + ixmlDocument_free(*xmlDoc); + return retVal; + } + } else { + /* Manual */ + if (strlen(description) > (LINE_SIZE - 1)) { + ixmlDocument_free(*xmlDoc); + return UPNP_E_URL_TOO_BIG; + } + strcpy(descURL, description); + } + + assert(*xmlDoc != NULL); + + return UPNP_E_SUCCESS; +} + + +#else /* INTERNAL_WEB_SERVER */ /* no web server */ +static int GetDescDocumentAndURL( + Upnp_DescType descriptionType, + char *description, + unsigned int bufferLen, + int config_baseURL, + int AddressFamily, + IXML_Document **xmlDoc, + char *descURL) +{ + int retVal = 0; + + if (descriptionType != UPNPREG_URL_DESC || config_baseURL) { + return UPNP_E_NO_WEB_SERVER; + } + + if (description == NULL) { + return UPNP_E_INVALID_PARAM; + } + + if (strlen(description) > (LINE_SIZE - 1)) { + return UPNP_E_URL_TOO_BIG; + } + strcpy(descURL, description); + + retVal = UpnpDownloadXmlDoc(description, xmlDoc); + if (retVal != UPNP_E_SUCCESS) { + return retVal; + } + + return UPNP_E_SUCCESS; +} +#endif /* INTERNAL_WEB_SERVER */ +#endif /* INCLUDE_DEVICE_APIS */ + + +/******************************************************************************* + * + * SSDP interface + * + ******************************************************************************/ -//----------------------------------------------------------------------------- -// -// SSDP interface -// -//----------------------------------------------------------------------------- #ifdef INCLUDE_DEVICE_APIS #if EXCLUDE_SSDP == 0 - -/************************************************************************** - * Function: UpnpSendAdvertisement - * - * Parameters: - * IN UpnpDevice_Handle Hnd: handle of the device instance - * IN int Exp : Timer for resending the advertisement - * - * Description: - * This function sends the device advertisement. It also schedules a - * job for the next advertisement after "Exp" time. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd, - IN int Exp ) +int UpnpSendAdvertisement(UpnpDevice_Handle Hnd, int Exp) { struct Handle_Info *SInfo = NULL; int retVal = 0, @@ -1345,7 +1478,7 @@ UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd, Exp = DEFAULT_MAXAGE; SInfo->MaxAge = Exp; HandleUnlock(); - retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr_in * )NULL, + retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr * )NULL, ( char * )NULL, ( char * )NULL, ( char * )NULL, Exp ); @@ -1408,34 +1541,20 @@ UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd, return retVal; -} /****************** End of UpnpSendAdvertisement *********************/ -#endif // INCLUDE_DEVICE_APIS -#endif +} +#endif /* EXCLUDE_SSDP == 0 */ +#endif /* INCLUDE_DEVICE_APIS */ + + #if EXCLUDE_SSDP == 0 #ifdef INCLUDE_CLIENT_APIS -/************************************************************************** - * Function: UpnpSearchAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: handle of the control point instance - * IN int Mx : Maximum time to wait for the search reply - * IN const char *Target_const: - * IN const void *Cookie_const: - * - * Description: - * This function searches for the devices for the provided maximum time. - * It is a asynchronous function. It schedules a search job and returns. - * client is notified about the search results after search timer. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSearchAsync( IN UpnpClient_Handle Hnd, - IN int Mx, - IN const char *Target_const, - IN const void *Cookie_const ) + +int UpnpSearchAsync( + UpnpClient_Handle Hnd, + int Mx, + const char *Target_const, + const void *Cookie_const ) { struct Handle_Info *SInfo = NULL; char *Target = ( char * )Target_const; @@ -1445,7 +1564,7 @@ UpnpSearchAsync( IN UpnpClient_Handle Hnd, } UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSearchAsync \n" ); + "Inside UpnpSearchAsync\n" ); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { @@ -1463,42 +1582,26 @@ UpnpSearchAsync( IN UpnpClient_Handle Hnd, HandleUnlock(); SearchByTarget( Mx, Target, ( void * )Cookie_const ); - //HandleUnlock(); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSearchAsync \n" ); return UPNP_E_SUCCESS; -} /****************** End of UpnpSearchAsync *********************/ -#endif // INCLUDE_CLIENT_APIS +} +#endif /* INCLUDE_CLIENT_APIS */ #endif -//----------------------------------------------------------------------------- -// -// GENA interface -// -//----------------------------------------------------------------------------- + + +/******************************************************************************* + * + * GENA interface + * + ******************************************************************************/ + #if EXCLUDE_GENA == 0 #ifdef INCLUDE_DEVICE_APIS - -/************************************************************************** - * Function: UpnpSetMaxSubscriptions - * - * Parameters: - * IN UpnpDevice_Handle Hnd: The handle of the device for which - * the maximum subscriptions is being set. - * IN int MaxSubscriptions: The maximum number of subscriptions to be - * allowed per service. - * - * Description: - * This function sets the maximum subscriptions of the control points - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSetMaxSubscriptions( IN UpnpDevice_Handle Hnd, - IN int MaxSubscriptions ) +int UpnpSetMaxSubscriptions(UpnpDevice_Handle Hnd, int MaxSubscriptions) { struct Handle_Info *SInfo = NULL; @@ -1524,30 +1627,12 @@ UpnpSetMaxSubscriptions( IN UpnpDevice_Handle Hnd, return UPNP_E_SUCCESS; -} /***************** End of UpnpSetMaxSubscriptions ********************/ -#endif // INCLUDE_DEVICE_APIS +} +#endif /* INCLUDE_DEVICE_APIS */ + #ifdef INCLUDE_DEVICE_APIS - -/************************************************************************** - * Function: UpnpSetMaxSubscriptionTimeOut - * - * Parameters: - * IN UpnpDevice_Handle Hnd: The handle of the device for which the - * maximum subscription time-out is being set. - * IN int MaxSubscriptionTimeOut:The maximum subscription time-out - * to be accepted - * - * Description: - * This function sets the maximum subscription timer. Control points - * will require to send the subscription request before timeout. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSetMaxSubscriptionTimeOut( IN UpnpDevice_Handle Hnd, - IN int MaxSubscriptionTimeOut ) +int UpnpSetMaxSubscriptionTimeOut(UpnpDevice_Handle Hnd, int MaxSubscriptionTimeOut) { struct Handle_Info *SInfo = NULL; @@ -1555,8 +1640,8 @@ UpnpSetMaxSubscriptionTimeOut( IN UpnpDevice_Handle Hnd, return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSetMaxSubscriptionTimeOut \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSetMaxSubscriptionTimeOut\n" ); HandleLock(); @@ -1570,46 +1655,22 @@ UpnpSetMaxSubscriptionTimeOut( IN UpnpDevice_Handle Hnd, SInfo->MaxSubscriptionTimeOut = MaxSubscriptionTimeOut; HandleUnlock(); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSetMaxSubscriptionTimeOut \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSetMaxSubscriptionTimeOut\n"); return UPNP_E_SUCCESS; -} /****************** End of UpnpSetMaxSubscriptionTimeOut ******************/ -#endif // INCLUDE_DEVICE_APIS +} +#endif /* INCLUDE_DEVICE_APIS */ + #ifdef INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: UpnpSubscribeAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point for which - * the subscription request is to be sent. - * IN const char * EvtUrl_const: URL that control point wants to - * subscribe - * IN int TimeOut: The requested subscription time. Upon - * return, it contains the actual subscription time - * returned from the service - * IN Upnp_FunPtr Fun : callback function to tell result of the - * subscription request - * IN const void * Cookie_const: cookie passed by client to give back - * in the callback function. - * - * Description: - * This function performs the same operation as UpnpSubscribeAsync - * but returns immediately and calls the registered callback function - * when the operation is complete. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSubscribeAsync( IN UpnpClient_Handle Hnd, - IN const char *EvtUrl_const, - IN int TimeOut, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) +int UpnpSubscribeAsync( + UpnpClient_Handle Hnd, + const char *EvtUrl_const, + int TimeOut, + Upnp_FunPtr Fun, + const void *Cookie_const) { struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; @@ -1620,8 +1681,8 @@ UpnpSubscribeAsync( IN UpnpClient_Handle Hnd, return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSubscribeAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSubscribeAsync\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { @@ -1653,267 +1714,225 @@ UpnpSubscribeAsync( IN UpnpClient_Handle Hnd, strcpy( Param->Url, EvtUrl ); Param->TimeOut = TimeOut; Param->Fun = Fun; - Param->Cookie = ( void * )Cookie_const; + Param->Cookie = (void *)Cookie_const; - TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); - TPJobSetFreeFunction( &job, ( free_routine ) free ); - TPJobSetPriority( &job, MED_PRIORITY ); - ThreadPoolAdd( &gSendThreadPool, &job, NULL ); + TPJobInit(&job, (start_routine)UpnpThreadDistribution, Param); + TPJobSetFreeFunction(&job, (free_routine)free); + TPJobSetPriority(&job, MED_PRIORITY); + ThreadPoolAdd(&gSendThreadPool, &job, NULL); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSubscribeAsync \n" ); - - return UPNP_E_SUCCESS; - -} /****************** End of UpnpSubscribeAsync *********************/ -#endif // INCLUDE_CLIENT_APIS - -#ifdef INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: UpnpSubscribe - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point. - * IN const char *PublisherUrl: The URL of the service to subscribe to. - * INOUT int *TimeOut: Pointer to a variable containing the requested - * subscription time. Upon return, it contains the - * actual subscription time returned from the service. - * OUT Upnp_SID SubsId: Pointer to a variable to receive the - * subscription ID (SID). - * - * Description: - * This function registers a control point to receive event - * notifications from another device. This operation is synchronous - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSubscribe( IN UpnpClient_Handle Hnd, - IN const char *EvtUrl_const, - INOUT int *TimeOut, - OUT Upnp_SID SubsId ) -{ - struct Handle_Info *SInfo = NULL; - int RetVal; - char *EvtUrl = ( char * )EvtUrl_const; - - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSubscribe \n" ); - - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( EvtUrl == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( TimeOut == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - HandleUnlock(); - RetVal = genaSubscribe( Hnd, EvtUrl, TimeOut, SubsId ); - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSubscribe \n" ); - - return RetVal; - -} /****************** End of UpnpSubscribe *********************/ -#endif // INCLUDE_CLIENT_APIS - -#ifdef INCLUDE_CLIENT_APIS - -int UpnpUnSubscribe(UpnpClient_Handle Hnd, const Upnp_SID SubsId) -{ - struct Handle_Info *SInfo = NULL; - int RetVal; - - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpUnSubscribe \n" ); - - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - HandleUnlock(); - RetVal = genaUnSubscribe( Hnd, SubsId ); - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpUnSubscribe \n" ); - - return RetVal; - -} /****************** End of UpnpUnSubscribe *********************/ -#endif // INCLUDE_CLIENT_APIS - -#ifdef INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: UpnpUnSubscribeAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the subscribed control point. - * IN Upnp_SID SubsId: The ID returned when the control point - * subscribed to the service. - * IN Upnp_FunPtr Fun: Pointer to a callback function to be called - * when the operation is complete. - * IN const void *Cookie:Pointer to user data to pass to the - * callback function when invoked. - * - * Description: - * This function removes a subscription of a control point - * from a service previously subscribed to using UpnpSubscribe or - * UpnpSubscribeAsync,generating a callback when the operation is complete. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpUnSubscribeAsync( IN UpnpClient_Handle Hnd, - IN Upnp_SID SubsId, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) -{ - ThreadPoolJob job; - struct Handle_Info *SInfo = NULL; - struct UpnpNonblockParam *Param; - - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpUnSubscribeAsync \n" ); - - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( Fun == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - - HandleUnlock(); - Param = - ( struct UpnpNonblockParam * ) - malloc( sizeof( struct UpnpNonblockParam ) ); - if( Param == NULL ) - return UPNP_E_OUTOF_MEMORY; - - Param->FunName = UNSUBSCRIBE; - Param->Handle = Hnd; - strcpy( Param->SubsId, SubsId ); - Param->Fun = Fun; - Param->Cookie = ( void * )Cookie_const; - TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); - TPJobSetFreeFunction( &job, ( free_routine ) free ); - TPJobSetPriority( &job, MED_PRIORITY ); - ThreadPoolAdd( &gSendThreadPool, &job, NULL ); - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpUnSubscribeAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSubscribeAsync\n"); return UPNP_E_SUCCESS; } -#endif // INCLUDE_CLIENT_APIS +#endif /* INCLUDE_CLIENT_APIS */ + #ifdef INCLUDE_CLIENT_APIS - -int UpnpRenewSubscription(UpnpClient_Handle Hnd, int *TimeOut, const Upnp_SID SubsId) +int UpnpSubscribe( + UpnpClient_Handle Hnd, + const char *EvtUrl_const, + int *TimeOut, + Upnp_SID SubsId) { - struct Handle_Info *SInfo = NULL; - int RetVal; + int retVal; + struct Handle_Info *SInfo = NULL; + char *EvtUrl = (char *)EvtUrl_const; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSubscribe\n"); - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpRenewSubscription \n" ); + if (EvtUrl == NULL) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + if (EvtUrl_const == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( TimeOut == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - HandleUnlock(); - RetVal = genaRenewSubscription( Hnd, SubsId, TimeOut ); + if (SubsId == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpRenewSubscription \n" ); + if (TimeOut == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } - return RetVal; + HandleReadLock(); + if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) { + HandleUnlock(); + retVal = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + HandleUnlock(); + + retVal = genaSubscribe(Hnd, EvtUrl, TimeOut, SubsId); + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSubscribe, retVal=%d\n", retVal); + + return retVal; +} +#endif /* INCLUDE_CLIENT_APIS */ -} /****************** End of UpnpRenewSubscription *********************/ -#endif // INCLUDE_CLIENT_APIS #ifdef INCLUDE_CLIENT_APIS +int UpnpUnSubscribe(UpnpClient_Handle Hnd, const Upnp_SID SubsId) +{ + struct Handle_Info *SInfo = NULL; + int retVal; -/************************************************************************** - * Function: UpnpRenewSubscriptionAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point that - * is renewing the subscription. - * IN int TimeOut: The requested subscription time. The - * actual timeout value is returned when - * the callback function is called. - * IN Upnp_SID SubsId: The ID for the subscription to renew. - * IN Upnp_FunPtr Fun: Pointer to a callback function to be - * invoked when the renewal is complete. - * IN const void *Cookie : Pointer to user data passed - * to the callback function when invoked. - * - * Description: - * This function renews a subscription that is about - * to expire, generating a callback when the operation is complete. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpRenewSubscriptionAsync( IN UpnpClient_Handle Hnd, - INOUT int TimeOut, - IN Upnp_SID SubsId, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribe\n"); + + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } + + if (SubsId == NULL) { + HandleUnlock(); + return UPNP_E_INVALID_PARAM; + } + HandleReadLock(); + if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) { + HandleUnlock(); + retVal = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + HandleUnlock(); + + retVal = genaUnSubscribe(Hnd, SubsId); + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpUnSubscribe, retVal=%d\n", retVal); + + return retVal; +} +#endif /* INCLUDE_CLIENT_APIS */ + + +#ifdef INCLUDE_CLIENT_APIS +int UpnpUnSubscribeAsync( + UpnpClient_Handle Hnd, + Upnp_SID SubsId, + Upnp_FunPtr Fun, + const void *Cookie_const) +{ + int retVal; + ThreadPoolJob job; + struct Handle_Info *SInfo = NULL; + struct UpnpNonblockParam *Param; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribeAsync\n"); + + if (UpnpSdkInit != 1) { + retVal = UPNP_E_FINISH; + goto exit_function; + } + + if (SubsId == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + if (Fun == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + HandleReadLock(); + if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) { + HandleUnlock(); + retVal = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + HandleUnlock(); + + Param = (struct UpnpNonblockParam *)malloc(sizeof(struct UpnpNonblockParam)); + if (Param == NULL) { + retVal = UPNP_E_OUTOF_MEMORY; + goto exit_function; + } + + Param->FunName = UNSUBSCRIBE; + Param->Handle = Hnd; + strcpy( Param->SubsId, SubsId ); + Param->Fun = Fun; + Param->Cookie = (void *)Cookie_const; + TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); + TPJobSetFreeFunction( &job, ( free_routine ) free ); + TPJobSetPriority( &job, MED_PRIORITY ); + ThreadPoolAdd( &gSendThreadPool, &job, NULL ); + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnSubscribeAsync\n"); + + return UPNP_E_SUCCESS; +} +#endif /* INCLUDE_CLIENT_APIS */ + + +#ifdef INCLUDE_CLIENT_APIS +int UpnpRenewSubscription( + UpnpClient_Handle Hnd, + int *TimeOut, + const Upnp_SID SubsId) +{ + struct Handle_Info *SInfo = NULL; + int retVal; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRenewSubscription\n"); + + if (UpnpSdkInit != 1) { + return UPNP_E_FINISH; + } + + if (SubsId == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + if (TimeOut == NULL) { + retVal = UPNP_E_INVALID_PARAM; + goto exit_function; + } + + HandleReadLock(); + if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) { + HandleUnlock(); + retVal = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + HandleUnlock(); + + retVal = genaRenewSubscription(Hnd, SubsId, TimeOut); + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpRenewSubscription, retVal=%d\n", retVal); + + return retVal; +} +#endif /* INCLUDE_CLIENT_APIS */ + + +#ifdef INCLUDE_CLIENT_APIS +int UpnpRenewSubscriptionAsync( + UpnpClient_Handle Hnd, + int TimeOut, + Upnp_SID SubsId, + Upnp_FunPtr Fun, + const void *Cookie_const) { ThreadPoolJob job; struct Handle_Info *SInfo = NULL; @@ -1923,8 +1942,8 @@ UpnpRenewSubscriptionAsync( IN UpnpClient_Handle Hnd, return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpRenewSubscriptionAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpRenewSubscriptionAsync\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { HandleUnlock(); @@ -1963,62 +1982,36 @@ UpnpRenewSubscriptionAsync( IN UpnpClient_Handle Hnd, TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpRenewSubscriptionAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpRenewSubscriptionAsync\n"); return UPNP_E_SUCCESS; +} +#endif /* INCLUDE_CLIENT_APIS */ -} /****************** End of UpnpRenewSubscriptionAsync *******************/ -#endif // INCLUDE_CLIENT_APIS #ifdef INCLUDE_DEVICE_APIS - -/************************************************************************** - * Function: UpnpNotify - * - * Parameters: - * IN UpnpDevice_Handle: The handle to the device sending the event. - * IN const char *DevID: The device ID of the subdevice of the - * service generating the event. - * IN const char *ServID: The unique identifier of the service - * generating the event. - * IN const char **VarName: Pointer to an array of variables that - * have changed. - * IN const char **NewVal: Pointer to an array of new values for - * those variables. - * IN int cVariables: The count of variables included in this - * notification. - * - * Description: - * This function sends out an event change notification to all - * control points subscribed to a particular service. This function is - * synchronous and generates no callbacks. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpNotify( IN UpnpDevice_Handle Hnd, - IN const char *DevID_const, - IN const char *ServName_const, - IN const char **VarName_const, - IN const char **NewVal_const, - IN int cVariables ) +int UpnpNotify( + UpnpDevice_Handle Hnd, + const char *DevID_const, + const char *ServName_const, + const char **VarName_const, + const char **NewVal_const, + int cVariables) { - struct Handle_Info *SInfo = NULL; int retVal; - char *DevID = ( char * )DevID_const; - char *ServName = ( char * )ServName_const; - char **VarName = ( char ** )VarName_const; - char **NewVal = ( char ** )NewVal_const; + char *DevID = (char *)DevID_const; + char *ServName = (char *)ServName_const; + char **VarName = (char **)VarName_const; + char **NewVal = (char **)NewVal_const; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpNotify \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpNotify\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) { @@ -2042,47 +2035,23 @@ UpnpNotify( IN UpnpDevice_Handle Hnd, retVal = genaNotifyAll( Hnd, DevID, ServName, VarName, NewVal, cVariables ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpNotify \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpNotify\n"); return retVal; +} -} /****************** End of UpnpNotify *********************/ -/************************************************************************** - * Function: UpnpNotifyExt - * - * Parameters: - * IN UpnpDevice_Handle: The handle to the device sending the - * event. - * IN const char *DevID: The device ID of the subdevice of the - * service generating the event. - * IN const char *ServID: The unique identifier of the service - * generating the event. - * IN IXML_Document *PropSet: The DOM document for the property set. - * Property set documents must conform to the XML schema - * defined in section 4.3 of the Universal Plug and Play - * Device Architecture specification. - * - * Description: - * This function is similar to UpnpNotify except that it takes - * a DOM document for the event rather than an array of strings. This - * function is synchronous and generates no callbacks. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpNotifyExt( IN UpnpDevice_Handle Hnd, - IN const char *DevID_const, - IN const char *ServName_const, - IN IXML_Document * PropSet ) +int UpnpNotifyExt( + UpnpDevice_Handle Hnd, + const char *DevID_const, + const char *ServName_const, + IXML_Document *PropSet) { - struct Handle_Info *SInfo = NULL; int retVal; - char *DevID = ( char * )DevID_const; - char *ServName = ( char * )ServName_const; + char *DevID = (char *)DevID_const; + char *ServName = (char *)ServName_const; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; @@ -2112,13 +2081,11 @@ UpnpNotifyExt( IN UpnpDevice_Handle Hnd, "Exiting UpnpNotify \n" ); return retVal; +} +#endif /* INCLUDE_DEVICE_APIS */ -} /****************** End of UpnpNotify *********************/ - -#endif // INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS - int UpnpAcceptSubscription( UpnpDevice_Handle Hnd, const char *DevID_const, @@ -2128,194 +2095,179 @@ int UpnpAcceptSubscription( int cVariables, const Upnp_SID SubsId) { - struct Handle_Info *SInfo = NULL; - int retVal; - char *DevID = ( char * )DevID_const; - char *ServName = ( char * )ServName_const; - char **VarName = ( char ** )VarName_const; - char **NewVal = ( char ** )NewVal_const; + int ret = 0; + int line = 0; + struct Handle_Info *SInfo = NULL; + char *DevID = (char *)DevID_const; + char *ServName = (char *)ServName_const; + char **VarName = (char **)VarName_const; + char **NewVal = (char **)NewVal_const; - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpAcceptSubscription\n"); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpAcceptSubscription \n" ); + if (UpnpSdkInit != 1) { + line = __LINE__; + ret = UPNP_E_FINISH; + goto exit_function; + } - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( DevID == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( ServName == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - /* Now accepts an empty state list, so the code below is commented out */ -#if 0 - if( VarName == NULL || NewVal == NULL || cVariables < 0 ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } -#endif + HandleReadLock(); - HandleUnlock(); - retVal = - genaInitNotify( Hnd, DevID, ServName, VarName, NewVal, cVariables, - SubsId ); - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpAcceptSubscription \n" ); - return retVal; - -} /***************** End of UpnpAcceptSubscription *********************/ - -/************************************************************************** - * Function: UpnpAcceptSubscriptionExt - * - * Parameters: - * IN UpnpDevice_Handle Hnd: The handle of the device. - * IN const char *DevID: The device ID of the subdevice of the - * service generating the event. - * IN const char *ServID: The unique service identifier of the service - * generating the event. - * IN IXML_Document *PropSet: The DOM document for the property set. - * Property set documents must conform to the XML schema - * defined in section 4.3 of the Universal Plug and Play - * Device Architecture specification. - * IN Upnp_SID SubsId: The subscription ID of the newly - * registered control point. - * - * Description: - * This function is similar to UpnpAcceptSubscription except that it - * takes a DOM document for the variables to event rather than an array - * of strings. This function is sychronous and generates no callbacks. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpAcceptSubscriptionExt( IN UpnpDevice_Handle Hnd, - IN const char *DevID_const, - IN const char *ServName_const, - IN IXML_Document * PropSet, - IN Upnp_SID SubsId ) -{ - struct Handle_Info *SInfo = NULL; - int retVal; - char *DevID = ( char * )DevID_const; - char *ServName = ( char * )ServName_const; - - if( UpnpSdkInit != 1 ) { - return UPNP_E_FINISH; - } - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpAcceptSubscription \n" ); - - HandleReadLock(); - if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - if( DevID == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( ServName == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } - if( SubsId == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } + if (GetHandleInfo(Hnd, &SInfo) != HND_DEVICE) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + if (DevID == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } + if (ServName == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } + if (SubsId == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } /* Now accepts an empty state list, so the code below is commented out */ #if 0 - if( PropSet == NULL ) { - HandleUnlock(); - return UPNP_E_INVALID_PARAM; - } + if (VarName == NULL || NewVal == NULL || cVariables < 0) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } #endif - HandleUnlock(); - retVal = genaInitNotifyExt( Hnd, DevID, ServName, PropSet, SubsId ); + HandleUnlock(); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpAcceptSubscription \n" ); + line = __LINE__; + ret = genaInitNotify( + Hnd, DevID, ServName, VarName, NewVal, cVariables, SubsId); - return retVal; +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, line, + "Exiting UpnpAcceptSubscription, ret = %d\n", ret); -} /****************** End of UpnpAcceptSubscription *********************/ + return ret; +} + + +int UpnpAcceptSubscriptionExt( + UpnpDevice_Handle Hnd, + const char *DevID_const, + const char *ServName_const, + IXML_Document *PropSet, + Upnp_SID SubsId) +{ + int ret = 0; + int line = 0; + struct Handle_Info *SInfo = NULL; + char *DevID = (char *)DevID_const; + char *ServName = (char *)ServName_const; + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpAcceptSubscription\n"); + + if (UpnpSdkInit != 1) { + line = __LINE__; + ret = UPNP_E_FINISH; + goto exit_function; + } + + HandleReadLock(); + + if (GetHandleInfo(Hnd, &SInfo) != HND_DEVICE) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_HANDLE; + goto exit_function; + } + if (DevID == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } + if (ServName == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } + if (SubsId == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } + /* Now accepts an empty state list, so the code below is commented out */ +#if 0 + if (PropSet == NULL) { + HandleUnlock(); + line = __LINE__; + ret = UPNP_E_INVALID_PARAM; + goto exit_function; + } +#endif + + HandleUnlock(); + + line = __LINE__; + ret = genaInitNotifyExt(Hnd, DevID, ServName, PropSet, SubsId); + +exit_function: + UpnpPrintf(UPNP_ALL, API, __FILE__, line, + "Exiting UpnpAcceptSubscription, ret = %d.\n", ret); + + return ret; +} +#endif /* INCLUDE_DEVICE_APIS */ +#endif /* EXCLUDE_GENA == 0 */ + + +/******************************************************************************* + * + * SOAP interface + * + ******************************************************************************/ -#endif // INCLUDE_DEVICE_APIS -#endif // EXCLUDE_GENA == 0 -//--------------------------------------------------------------------------- -// -// SOAP interface -// -//--------------------------------------------------------------------------- #if EXCLUDE_SOAP == 0 #ifdef INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: UpnpSendAction - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point - * sending the action. - * IN const char *ActionURL: The action URL of the service. - * IN const char *ServiceType: The type of the service. - * IN const char *DevUDN: This parameter is ignored. - * IN IXML_Document *Action: The DOM document for the action. - * OUT IXML_Document **RespNode: The DOM document for the response - * to the action. The UPnP Library allocates this document - * and the caller needs to free it. - * - * Description: - * This function sends a message to change a state variable in a service. - * This is a synchronous call that does not return until the action is - * complete. - * - * Note that a positive return value indicates a SOAP-protocol error code. - * In this case, the error description can be retrieved from RespNode. - * A negative return value indicates a UPnP Library error. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSendAction( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *ServiceType_const, - IN const char *DevUDN_const, - IN IXML_Document * Action, - OUT IXML_Document ** RespNodePtr ) +int UpnpSendAction( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *ServiceType_const, + const char *DevUDN_const, + IXML_Document *Action, + IXML_Document **RespNodePtr) { struct Handle_Info *SInfo = NULL; int retVal = 0; - char *ActionURL = ( char * )ActionURL_const; - char *ServiceType = ( char * )ServiceType_const; - - //char *DevUDN = (char *)DevUDN_const; // udn not used? + char *ActionURL = (char *)ActionURL_const; + char *ServiceType = (char *)ServiceType_const; + /* udn not used? */ + /*char *DevUDN = (char *)DevUDN_const;*/ if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSendAction \n" ); - if(DevUDN_const !=NULL) { - UpnpPrintf(UPNP_ALL,API,__FILE__,__LINE__,"non NULL DevUDN is ignored\n"); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSendAction\n"); + if (DevUDN_const !=NULL) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "non NULL DevUDN is ignored\n"); } DevUDN_const = NULL; @@ -2338,64 +2290,35 @@ UpnpSendAction( IN UpnpClient_Handle Hnd, retVal = SoapSendAction( ActionURL, ServiceType, Action, RespNodePtr ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSendAction \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSendAction\n"); return retVal; +} -} /****************** End of UpnpSendAction *********************/ -/************************************************************************** - * Function: UpnpSendActionEx - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point sending - * the action. - * IN const char *ActionURL_const: The action URL of the service. - * IN const char *ServiceType_const: The type of the service. - * IN const char *DevUDN_const: This parameter is ignored. - * IN IXML_Document *Header: The DOM document for the SOAP header. - * This may be NULL if the header is not required. - * IN IXML_Document *Action: The DOM document for the action. - * OUT IXML_Document **RespNodePtr: The DOM document for the response to - * the action. The UPnP library allocates this document and the - * caller needs to free it. - * - * Description: - * this function sends a message to change a state variable in a - * service. This is a synchronous call that does not return until the - * action is complete. - * - * Note that a positive return value indicates a SOAP-protocol error code. - * In this case, the error description can be retrieved from {\bf RespNode}. - * A negative return value indicates a UPnP Library error. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSendActionEx( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *ServiceType_const, - IN const char *DevUDN_const, - IN IXML_Document * Header, - IN IXML_Document * Action, - OUT IXML_Document ** RespNodePtr ) +int UpnpSendActionEx( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *ServiceType_const, + const char *DevUDN_const, + IXML_Document *Header, + IXML_Document *Action, + IXML_Document **RespNodePtr) { - struct Handle_Info *SInfo = NULL; int retVal = 0; - char *ActionURL = ( char * )ActionURL_const; - char *ServiceType = ( char * )ServiceType_const; - - //char *DevUDN = (char *)DevUDN_const; // udn not used? + char *ActionURL = (char *)ActionURL_const; + char *ServiceType = (char *)ServiceType_const; + /* udn not used? */ + /*char *DevUDN = (char *)DevUDN_const;*/ if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSendActionEx \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSendActionEx\n"); if( Header == NULL ) { retVal = UpnpSendAction( Hnd, ActionURL_const, ServiceType_const, @@ -2420,64 +2343,38 @@ UpnpSendActionEx( IN UpnpClient_Handle Hnd, retVal = SoapSendActionEx( ActionURL, ServiceType, Header, Action, RespNodePtr ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSendAction \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSendAction \n"); return retVal; +} -} /****************** End of UpnpSendActionEx *********************/ -/************************************************************************** - * Function: UpnpSendActionAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point - * sending the action. - * IN const char *ActionURL: The action URL of the service. - * IN const char *ServiceType: The type of the service. - * IN const char *DevUDN: This parameter is ignored. - * IN IXML_Document *Action: The DOM document for the action to - * perform on this device. - * IN Upnp_FunPtr Fun: Pointer to a callback function to - * be invoked when the operation completes - * IN const void *Cookie: Pointer to user data that to be - * passed to the callback when invoked. - * - * Description: - * this function sends a message to change a state variable - * in a service, generating a callback when the operation is complete. - * See UpnpSendAction for comments on positive return values. These - * positive return values are sent in the event struct associated with the - * UPNP_CONTROL_ACTION_COMPLETE event. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSendActionAsync( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *ServiceType_const, - IN const char *DevUDN_const, - IN IXML_Document * Act, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) +int UpnpSendActionAsync( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *ServiceType_const, + const char *DevUDN_const, + IXML_Document *Act, + Upnp_FunPtr Fun, + const void *Cookie_const) { + int rc; ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; DOMString tmpStr; - char *ActionURL = ( char * )ActionURL_const; - char *ServiceType = ( char * )ServiceType_const; + char *ActionURL = (char *)ActionURL_const; + char *ServiceType = (char *)ServiceType_const; + /* udn not used? */ + /*char *DevUDN = (char *)DevUDN_const;*/ - //char *DevUDN = (char *)DevUDN_const; - int rc; - - if( UpnpSdkInit != 1 ) { + if(UpnpSdkInit != 1) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSendActionAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSendActionAsync\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { @@ -2531,50 +2428,22 @@ UpnpSendActionAsync( IN UpnpClient_Handle Hnd, TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSendActionAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSendActionAsync \n"); return UPNP_E_SUCCESS; +} -} /****************** End of UpnpSendActionAsync *********************/ -/************************************************************************* - * Function: UpnpSendActionExAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point - * sending the action. - * IN const char *ActionURL_const: The action URL of the service. - * IN const char *ServiceType_const: The type of the service. - * IN const char *DevUDN_const: This parameter is ignored. - * IN IXML_Document *Header: The DOM document for the SOAP header. - * This may be NULL if the header is not required. - * IN IXML_Document *Act: The DOM document for the action to - * perform on this device. - * IN Upnp_FunPtr Fun: Pointer to a callback function to be invoked - * when the operation completes. - * IN const void *Cookie_const: Pointer to user data that to be - * passed to the callback when invoked. - * - * Description: - * this function sends sends a message to change a state variable - * in a service, generating a callback when the operation is complete. - * See UpnpSendAction for comments on positive return values. These - * positive return values are sent in the event struct associated with - * the UPNP_CONTROL_ACTION_COMPLETE event. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpSendActionExAsync( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *ServiceType_const, - IN const char *DevUDN_const, - IN IXML_Document * Header, - IN IXML_Document * Act, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) +int UpnpSendActionExAsync( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *ServiceType_const, + const char *DevUDN_const, + IXML_Document *Header, + IXML_Document *Act, + Upnp_FunPtr Fun, + const void *Cookie_const) { struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; @@ -2589,8 +2458,8 @@ UpnpSendActionExAsync( IN UpnpClient_Handle Hnd, return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpSendActionExAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpSendActionExAsync\n"); if( Header == NULL ) { retVal = UpnpSendActionAsync( Hnd, ActionURL_const, @@ -2667,51 +2536,32 @@ UpnpSendActionExAsync( IN UpnpClient_Handle Hnd, TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpSendActionAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpSendActionAsync\n"); return UPNP_E_SUCCESS; +} -} /****************** End of UpnpSendActionExAsync *********************/ -/************************************************************************* - * Function: UpnpGetServiceVarStatusAsync - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point. - * IN const char *ActionURL: The URL of the service. - * IN const char *VarName: The name of the variable to query. - * IN Upnp_FunPtr Fun: Pointer to a callback function to - * be invoked when the operation is complete. - * IN const void *Cookie: Pointer to user data to pass to the - * callback function when invoked. - * - * Description: - * this function queries the state of a variable of a - * service, generating a callback when the operation is complete. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpGetServiceVarStatusAsync( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *VarName_const, - IN Upnp_FunPtr Fun, - IN const void *Cookie_const ) +int UpnpGetServiceVarStatusAsync( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *VarName_const, + Upnp_FunPtr Fun, + const void *Cookie_const) { ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; - char *ActionURL = ( char * )ActionURL_const; - char *VarName = ( char * )VarName_const; + char *ActionURL = (char *)ActionURL_const; + char *VarName = (char *)VarName_const; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpGetServiceVarStatusAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpGetServiceVarStatusAsync\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { @@ -2747,51 +2597,31 @@ UpnpGetServiceVarStatusAsync( IN UpnpClient_Handle Hnd, ThreadPoolAdd( &gSendThreadPool, &job, NULL ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpGetServiceVarStatusAsync \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpGetServiceVarStatusAsync\n"); return UPNP_E_SUCCESS; +} -} /****************** End of UpnpGetServiceVarStatusAsync ****************/ -/************************************************************************** - * Function: UpnpGetServiceVarStatus - * - * Parameters: - * IN UpnpClient_Handle Hnd: The handle of the control point. - * IN const char *ActionURL: The URL of the service. - * IN const char *VarName: The name of the variable to query. - * OUT DOMString *StVarVal: The pointer to store the value - * for VarName. The UPnP Library allocates this string and - * the caller needs to free it. - * - * Description: - * this function queries the state of a state variable of a service on - * another device. This is a synchronous call. A positive return value - * indicates a SOAP error code, whereas a negative return code indicates - * a UPnP SDK error code. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpGetServiceVarStatus( IN UpnpClient_Handle Hnd, - IN const char *ActionURL_const, - IN const char *VarName_const, - OUT DOMString * StVar ) +int UpnpGetServiceVarStatus( + UpnpClient_Handle Hnd, + const char *ActionURL_const, + const char *VarName_const, + DOMString *StVar) { struct Handle_Info *SInfo = NULL; int retVal = 0; char *StVarPtr; - char *ActionURL = ( char * )ActionURL_const; - char *VarName = ( char * )VarName_const; + char *ActionURL = (char *)ActionURL_const; + char *VarName = (char *)VarName_const; - if( UpnpSdkInit != 1 ) { + if(UpnpSdkInit != 1) { return UPNP_E_FINISH; } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpGetServiceVarStatus \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpGetServiceVarStatus\n"); HandleReadLock(); if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) { @@ -2811,242 +2641,122 @@ UpnpGetServiceVarStatus( IN UpnpClient_Handle Hnd, retVal = SoapGetServiceVarStatus( ActionURL, VarName, &StVarPtr ); *StVar = StVarPtr; - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpGetServiceVarStatus \n" ); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpGetServiceVarStatus \n"); return retVal; - -} /****************** End of UpnpGetServiceVarStatus *********************/ -#endif // INCLUDE_CLIENT_APIS -#endif // EXCLUDE_SOAP - -//--------------------------------------------------------------------------- -// -// Client API's -// -//--------------------------------------------------------------------------- - -/************************************************************************** - * Function: UpnpOpenHttpPost - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ - -int -UpnpOpenHttpPost( IN const char *url, - IN OUT void **handle, - IN const char *contentType, - IN int contentLength, - IN int timeout ) -{ - return http_OpenHttpPost( url, handle, contentType, contentLength, - timeout ); } +#endif /* INCLUDE_CLIENT_APIS */ +#endif /* EXCLUDE_SOAP */ -/************************************************************************** - * Function: UpnpWriteHttpPost - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpWriteHttpPost( IN void *handle, - IN char *buf, - IN unsigned int *size, - IN int timeout ) -{ - return http_WriteHttpPost( handle, buf, size, timeout ); -} -/************************************************************************** - * Function: UpnpCloseHttpPost +/******************************************************************************* * - * Parameters: - * - * Description: + * Client API * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpCloseHttpPost( IN void *handle, - IN OUT int *httpStatus, - int timeout ) -{ - return http_CloseHttpPost( handle, httpStatus, timeout ); -} + ******************************************************************************/ -/************************************************************************** - * Function: UpnpOpenHttpGet - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpOpenHttpGet( IN const char *url_str, - IN OUT void **Handle, - IN OUT char **contentType, - OUT int *contentLength, - OUT int *httpStatus, - IN int timeout ) + +int UpnpOpenHttpPost( + const char *url, + void **handle, + const char *contentType, + int contentLength, + int timeout) { - return http_OpenHttpGet( url_str, Handle, contentType, contentLength, - httpStatus, timeout ); + return http_OpenHttpPost( + url, handle, contentType, contentLength, timeout); } - -/************************************************************************** - * Function: UpnpOpenHttpGetProxy - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpOpenHttpGetProxy( IN const char *url_str, - IN const char *proxy_str, - IN OUT void **Handle, - IN OUT char **contentType, - OUT int *contentLength, - OUT int *httpStatus, - IN int timeout ) +int UpnpWriteHttpPost( + void *handle, + char *buf, + unsigned int *size, + int timeout) { - return http_OpenHttpGetProxy( url_str, proxy_str, Handle, contentType, contentLength, - httpStatus, timeout ); -} - -/************************************************************************** - * Function: UpnpOpenHttpGetEx - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpOpenHttpGetEx( IN const char *url_str, - IN OUT void **Handle, - IN OUT char **contentType, - OUT int *contentLength, - OUT int *httpStatus, - IN int lowRange, - IN int highRange, - IN int timeout ) -{ - return http_OpenHttpGetEx( url_str, - Handle, - contentType, - contentLength, - httpStatus, lowRange, highRange, timeout ); + return http_WriteHttpPost(handle, buf, size, timeout); } - -/************************************************************************** - * Function: UpnpCancelHttpGet - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpCancelHttpGet( IN void *Handle ) +int UpnpCloseHttpPost( + void *handle, + int *httpStatus, + int timeout) { - return http_CancelHttpGet( Handle ); -} - -/************************************************************************** - * Function: UpnpCloseHttpGet - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpCloseHttpGet( IN void *Handle ) -{ - return http_CloseHttpGet( Handle ); -} - -/************************************************************************** - * Function: UpnpReadHttpGet - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpReadHttpGet( IN void *Handle, - IN OUT char *buf, - IN OUT unsigned int *size, - IN int timeout ) -{ - return http_ReadHttpGet( Handle, buf, size, timeout ); + return http_CloseHttpPost(handle, httpStatus, timeout); } - -/************************************************************************** - * Function: UpnpHttpGetProgress - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful. - * UPNP_E_INVALID_PARAM if the provided pointers were invalid. - ***************************************************************************/ -int -UpnpHttpGetProgress( IN void *Handle, - OUT unsigned int *length, - OUT unsigned int *total ) +int UpnpOpenHttpGet( + const char *url_str, + void **Handle, + char **contentType, + int *contentLength, + int *httpStatus, + int timeout) { - return http_HttpGetProgress(Handle, length, total); + return http_OpenHttpGet( + url_str, Handle, contentType, contentLength, httpStatus, timeout); } -/************************************************************************** - * Function: UpnpDownloadUrlItem - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpDownloadUrlItem( const char *url, - char **outBuf, - char *contentType ) + +int UpnpOpenHttpGetProxy( + const char *url_str, + const char *proxy_str, + void **Handle, + char **contentType, + int *contentLength, + int *httpStatus, + int timeout) +{ + return http_OpenHttpGetProxy( + url_str, proxy_str, Handle, contentType, contentLength, + httpStatus, timeout); +} + + +int UpnpOpenHttpGetEx( + const char *url_str, + void **Handle, + char **contentType, + int *contentLength, + int *httpStatus, + int lowRange, + int highRange, + int timeout) +{ + return http_OpenHttpGetEx( + url_str, Handle, contentType, contentLength, httpStatus, + lowRange, highRange, timeout); +} + + +int UpnpCancelHttpGet(void *Handle) +{ + return http_CancelHttpGet(Handle); +} + + +int UpnpCloseHttpGet(void *Handle) +{ + return http_CloseHttpGet(Handle); +} + + +int UpnpReadHttpGet(void *Handle, char *buf, unsigned int *size, int timeout) +{ + return http_ReadHttpGet(Handle, buf, size, timeout); +} + + +int UpnpHttpGetProgress(void *Handle, unsigned int *length, unsigned int *total) +{ + return http_HttpGetProgress(Handle, length, total); +} + + +int UpnpDownloadUrlItem(const char *url, char **outBuf, char *contentType) { int ret_code; int dummy; @@ -3058,546 +2768,295 @@ UpnpDownloadUrlItem( const char *url, ret_code = http_Download( url, HTTP_DEFAULT_TIMEOUT, outBuf, &dummy, contentType ); if( ret_code > 0 ) { - // error reply was received + /* error reply was received */ ret_code = UPNP_E_INVALID_URL; } return ret_code; } -/************************************************************************** - * Function: UpnpDownloadXmlDoc - * - * Parameters: - * - * Description: - * - * Return Values: int - * UPNP_E_SUCCESS if successful else sends appropriate error. - ***************************************************************************/ -int -UpnpDownloadXmlDoc( const char *url, - IXML_Document ** xmlDoc ) + +int UpnpDownloadXmlDoc(const char *url, IXML_Document **xmlDoc) { - int ret_code; - char *xml_buf; - char content_type[LINE_SIZE]; + int ret_code; + char *xml_buf; + char content_type[LINE_SIZE]; - if( url == NULL || xmlDoc == NULL ) { - return UPNP_E_INVALID_PARAM; - } + if (url == NULL || xmlDoc == NULL) { + return UPNP_E_INVALID_PARAM; + } - ret_code = UpnpDownloadUrlItem( url, &xml_buf, content_type ); - if( ret_code != UPNP_E_SUCCESS ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "retCode: %d\n", ret_code ); - return ret_code; - } + ret_code = UpnpDownloadUrlItem(url, &xml_buf, content_type); + if (ret_code != UPNP_E_SUCCESS) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "Error downloading document, retCode: %d\n", ret_code); + return ret_code; + } - if( strncasecmp( content_type, "text/xml", strlen( "text/xml" ) ) ) { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Not text/xml\n" ); - // Linksys WRT54G router returns - // "CONTENT-TYPE: application/octet-stream". - // Let's be nice to Linksys and try to parse document anyway. - // If the data sended is not a xml file, ixmlParseBufferEx - // will fail and the function will return UPNP_E_INVALID_DESC too. + if (strncasecmp(content_type, "text/xml", strlen("text/xml"))) { + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Not text/xml\n"); + /* Linksys WRT54G router returns + * "CONTENT-TYPE: application/octet-stream". + * Let's be nice to Linksys and try to parse document anyway. + * If the data sended is not a xml file, ixmlParseBufferEx + * will fail and the function will return UPNP_E_INVALID_DESC too. */ #if 0 - free( xml_buf ); - return UPNP_E_INVALID_DESC; + free(xml_buf); + return UPNP_E_INVALID_DESC; #endif - } + } - ret_code = ixmlParseBufferEx( xml_buf, xmlDoc ); - free( xml_buf ); - - if( ret_code != IXML_SUCCESS ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "Invalid desc\n" ); - if( ret_code == IXML_INSUFFICIENT_MEMORY ) { - return UPNP_E_OUTOF_MEMORY; - } else { - return UPNP_E_INVALID_DESC; - } - } else { + ret_code = ixmlParseBufferEx(xml_buf, xmlDoc); + free(xml_buf); + if (ret_code != IXML_SUCCESS) { + if (ret_code == IXML_INSUFFICIENT_MEMORY) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "Out of memory, ixml error code: %d\n", + ret_code); + return UPNP_E_OUTOF_MEMORY; + } else { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "Invalid Description, ixml error code: %d\n", + ret_code); + return UPNP_E_INVALID_DESC; + } + } else { #ifdef DEBUG - xml_buf = ixmlPrintNode( ( IXML_Node * ) * xmlDoc ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Printing the Parsed xml document \n %s\n", xml_buf ); - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "****************** END OF Parsed XML Doc *****************\n" ); - ixmlFreeDOMString( xml_buf ); + xml_buf = ixmlPrintNode((IXML_Node *)*xmlDoc); + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "Printing the Parsed xml document \n %s\n", xml_buf); + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "****************** END OF Parsed XML Doc *****************\n"); + ixmlFreeDOMString(xml_buf); #endif - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpDownloadXmlDoc\n" ); - return UPNP_E_SUCCESS; - } + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpDownloadXmlDoc\n"); + + return UPNP_E_SUCCESS; + } } -//---------------------------------------------------------------------------- -// -// UPNP-API Internal function implementation -// -//---------------------------------------------------------------------------- - -/************************************************************************** - * Function: UpnpThreadDistribution - * - * Parameters: - * - * Description: - * Function to schedule async functions in threadpool. - * - * Return Values: VOID - * - ***************************************************************************/ -#ifdef INCLUDE_CLIENT_APIS -void -UpnpThreadDistribution( struct UpnpNonblockParam *Param ) +int UpnpGetIfInfo(const char *IfName) { - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside UpnpThreadDistribution \n" ); - - switch ( Param->FunName ) { -#if EXCLUDE_GENA == 0 - case SUBSCRIBE: { - struct Upnp_Event_Subscribe Evt; - Evt.ErrCode = genaSubscribe( - Param->Handle, Param->Url, - ( int * )&( Param->TimeOut ), - ( char * )Evt.Sid ); - strcpy( Evt.PublisherUrl, Param->Url ); - Evt.TimeOut = Param->TimeOut; - Param->Fun( UPNP_EVENT_SUBSCRIBE_COMPLETE, &Evt, Param->Cookie ); - free( Param ); - break; - } - case UNSUBSCRIBE: { - struct Upnp_Event_Subscribe Evt; - Evt.ErrCode = - genaUnSubscribe( Param->Handle, - Param->SubsId ); - strcpy( ( char * )Evt.Sid, Param->SubsId ); - strcpy( Evt.PublisherUrl, "" ); - Evt.TimeOut = 0; - Param->Fun( UPNP_EVENT_UNSUBSCRIBE_COMPLETE, - &Evt, Param->Cookie ); - free( Param ); - break; - } - case RENEW: { - struct Upnp_Event_Subscribe Evt; - Evt.ErrCode = - genaRenewSubscription( Param->Handle, - Param->SubsId, - &( Param->TimeOut ) ); - Evt.TimeOut = Param->TimeOut; - strcpy( ( char * )Evt.Sid, Param->SubsId ); - Param->Fun( UPNP_EVENT_RENEWAL_COMPLETE, &Evt, - Param->Cookie ); - free( Param ); - break; - } -#endif // EXCLUDE_GENA == 0 -#if EXCLUDE_SOAP == 0 - case ACTION: { - struct Upnp_Action_Complete Evt; - Evt.ActionResult = NULL; - Evt.ErrCode = - SoapSendAction( Param->Url, Param->ServiceType, - Param->Act, &Evt.ActionResult ); - Evt.ActionRequest = Param->Act; - strcpy( Evt.CtrlUrl, Param->Url ); - Param->Fun( UPNP_CONTROL_ACTION_COMPLETE, &Evt, - Param->Cookie ); - ixmlDocument_free( Evt.ActionRequest ); - ixmlDocument_free( Evt.ActionResult ); - free( Param ); - break; - } - case STATUS: { - struct Upnp_State_Var_Complete Evt; - Evt.ErrCode = SoapGetServiceVarStatus( - Param->Url, Param->VarName, &( Evt.CurrentVal ) ); - strcpy( Evt.StateVarName, Param->VarName ); - strcpy( Evt.CtrlUrl, Param->Url ); - Param->Fun( UPNP_CONTROL_GET_VAR_COMPLETE, &Evt, - Param->Cookie ); - free( Evt.CurrentVal ); - free( Param ); - break; - } -#endif // EXCLUDE_SOAP == 0 - default: - break; - } // end of switch(Param->FunName) - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Exiting UpnpThreadDistribution \n" ); - -} /****************** End of UpnpThreadDistribution *********************/ -#endif // INCLUDE_CLIENT_APIS - -/************************************************************************** - * Function: GetCallBackFn - * - * Parameters: - * - * Description: - * This function is to get callback function ptr from a handle - * - * Return Values: Upnp_FunPtr - * - ***************************************************************************/ -Upnp_FunPtr -GetCallBackFn( UpnpClient_Handle Hnd ) -{ - return ( ( struct Handle_Info * )HandleTable[Hnd] )->Callback; - -} /****************** End of GetCallBackFn *********************/ - -/************************************************************************** - * Function: InitHandleList - * - * Parameters: VOID - * - * Description: - * This function is to initialize handle table - * - * Return Values: VOID - * - ***************************************************************************/ -void -InitHandleList() -{ - int i; - - for( i = 0; i < NUM_HANDLE; i++ ) - HandleTable[i] = NULL; - -} /****************** End of InitHandleList *********************/ - -/************************************************************************** - * Function: GetFreeHandle - * - * Parameters: VOID - * - * Description: - * This function is to get a free handle - * - * Return Values: VOID - * - ***************************************************************************/ -int -GetFreeHandle() -{ - int i = 1; - - /* - Handle 0 is not used as NULL translates to 0 when passed as a handle - */ - while( i < NUM_HANDLE ) { - if( HandleTable[i++] == NULL ) - break; - } - - if( i == NUM_HANDLE ) - return UPNP_E_OUTOF_HANDLE; //Error - else - return --i; - -} /****************** End of GetFreeHandle *********************/ - -/************************************************************************** - * Function: GetClientHandleInfo - * - * Parameters: - * IN UpnpClient_Handle *client_handle_out: client handle pointer ( key - * for the client handle structure). - * OUT struct Handle_Info **HndInfo: Client handle structure passed by - * this function. - * - * Description: - * This function is to get client handle info - * - * Return Values: HND_CLIENT - * - ***************************************************************************/ -//Assumes at most one client -Upnp_Handle_Type -GetClientHandleInfo( IN UpnpClient_Handle * client_handle_out, - OUT struct Handle_Info ** HndInfo ) -{ - ( *client_handle_out ) = 1; - if( GetHandleInfo( 1, HndInfo ) == HND_CLIENT ) { - return HND_CLIENT; - } - ( *client_handle_out ) = 2; - if( GetHandleInfo( 2, HndInfo ) == HND_CLIENT ) { - return HND_CLIENT; - } - ( *client_handle_out ) = -1; - return HND_INVALID; - -} /****************** End of GetClientHandleInfo *********************/ - -/************************************************************************** - * Function: GetDeviceHandleInfo - * - * Parameters: - * IN UpnpDevice_Handle * device_handle_out: device handle pointer - * (key for the client handle structure). - * OUT struct Handle_Info **HndInfo: Device handle structure passed by - * this function. - * - * Description: - * This function is to get device handle info. - * - * Return Values: HND_DEVICE - * - ***************************************************************************/ -Upnp_Handle_Type -GetDeviceHandleInfo( UpnpDevice_Handle * device_handle_out, - struct Handle_Info ** HndInfo ) -{ - ( *device_handle_out ) = 1; - if( GetHandleInfo( 1, HndInfo ) == HND_DEVICE ) - return HND_DEVICE; - - ( *device_handle_out ) = 2; - if( GetHandleInfo( 2, HndInfo ) == HND_DEVICE ) - return HND_DEVICE; - ( *device_handle_out ) = -1; - - return HND_INVALID; - -} /****************** End of GetDeviceHandleInfo *********************/ - -/************************************************************************** - * Function: GetDeviceHandleInfo - * - * Parameters: - * IN UpnpClient_Handle * device_handle_out: handle pointer - * (key for the client handle structure). - * OUT struct Handle_Info **HndInfo: handle structure passed by - * this function. - * - * Description: - * This function is to get handle info. - * - * Return Values: HND_DEVICE - * - ***************************************************************************/ -Upnp_Handle_Type -GetHandleInfo( UpnpClient_Handle Hnd, - struct Handle_Info ** HndInfo ) -{ - - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "GetHandleInfo: Handle is %d\n", Hnd ); - - if( Hnd < 1 || Hnd >= NUM_HANDLE ) { - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "GetHandleInfo : Handle out of range\n" ); - return UPNP_E_INVALID_HANDLE; - } - if( HandleTable[Hnd] != NULL ) { - *HndInfo = ( struct Handle_Info * )HandleTable[Hnd]; - return ( ( struct Handle_Info * )*HndInfo )->HType; - } - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "GetHandleInfo : exiting\n" ); - - return UPNP_E_INVALID_HANDLE; - -} /****************** End of GetHandleInfo *********************/ - -/************************************************************************** - * Function: FreeHandle - * - * Parameters: - * IN int Upnp_Handle: handle index - * - * Description: - * This function is to to free handle info. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else return appropriate error - ***************************************************************************/ -int -FreeHandle( int Upnp_Handle ) -{ - if( Upnp_Handle < 1 || Upnp_Handle >= NUM_HANDLE ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "FreeHandleInfo : Handle out of range\n" ); - return UPNP_E_INVALID_HANDLE; - } - - if( HandleTable[Upnp_Handle] == NULL ) { - return UPNP_E_INVALID_HANDLE; - } - free( HandleTable[Upnp_Handle] ); - HandleTable[Upnp_Handle] = NULL; - return UPNP_E_SUCCESS; - -} /****************** End of FreeHandle *********************/ - - -/************************************************************************** - * Function: PrintHandleInfo - * - * Parameters: - * IN UpnpClient_Handle Hnd: handle index - * - * Description: - * This function is to print handle info. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else return appropriate error - ***************************************************************************/ -int PrintHandleInfo( IN UpnpClient_Handle Hnd ) -{ - struct Handle_Info * HndInfo; - if (HandleTable[Hnd] != NULL) { - HndInfo = HandleTable[Hnd]; - UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, - "Printing information for Handle_%d\n", Hnd); - UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, - "HType_%d\n", HndInfo->HType); -#ifdef INCLUDE_DEVICE_APIS - if(HndInfo->HType != HND_CLIENT) - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "DescURL_%s\n", HndInfo->DescURL ); -#endif - } else { - return UPNP_E_INVALID_HANDLE; - } - - return UPNP_E_SUCCESS; -} - - /****************** End of PrintHandleInfo *********************/ - -void printNodes( IXML_Node * tmpRoot, int depth ) -{ - int i; - IXML_NodeList *NodeList1; - IXML_Node *ChildNode1; - unsigned short NodeType; - const DOMString NodeValue; - const DOMString NodeName; - NodeList1 = ixmlNode_getChildNodes(tmpRoot); - for (i = 0; i < 100; ++i) { - ChildNode1 = ixmlNodeList_item(NodeList1, i); - if (ChildNode1 == NULL) { - break; - } - - printNodes(ChildNode1, depth+1); - NodeType = ixmlNode_getNodeType(ChildNode1); - NodeValue = ixmlNode_getNodeValue(ChildNode1); - NodeName = ixmlNode_getNodeName(ChildNode1); - UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, - "DEPTH-%2d-IXML_Node Type %d, " - "IXML_Node Name: %s, IXML_Node Value: %s\n", - depth, NodeType, NodeName, NodeValue); - } -} - - /****************** End of printNodes *********************/ - - //******************************************************** - //* Name: getlocalhostname - //* Description: Function to get local IP address - //* Gets the ip address for the DEFAULT_INTERFACE - //* interface which is up and not a loopback - //* assumes at most MAX_INTERFACES interfaces - //* Called by: UpnpInit - //* In: char *out - //* Out: Ip address - //* Return codes: UPNP_E_SUCCESS - //* Error codes: UPNP_E_INIT - //******************************************************** - - /************************************************************************** - * Function: getlocalhostname - * - * Parameters: - * OUT char *out: IP address of the interface. - * - * Description: - * This function is to get local IP address. It gets the ip address for - * the DEFAULT_INTERFACE interface which is up and not a loopback - * assumes at most MAX_INTERFACES interfaces - * - * Return Values: int - * UPNP_E_SUCCESS if successful else return appropriate error - ***************************************************************************/ - int getlocalhostname( OUT char *out ) { - #ifdef WIN32 - struct hostent *h=NULL; - struct sockaddr_in LocalAddr; + // ---------------------------------------------------- + // WIN32 implementation will use the IpHlpAPI library. + // ---------------------------------------------------- + PIP_ADAPTER_ADDRESSES adapts = NULL; + PIP_ADAPTER_ADDRESSES adapts_item; + PIP_ADAPTER_UNICAST_ADDRESS uni_addr; + SOCKADDR* ip_addr; + struct in_addr v4_addr; + struct in6_addr v6_addr; + ULONG adapts_sz = 0; + ULONG ret; + int ifname_found = 0; + int valid_addr_found = 0; - gethostname(out,LINE_SIZE); - h=gethostbyname(out); - if (h!=NULL){ - memcpy(&LocalAddr.sin_addr,h->h_addr_list[0],4); - strcpy( out, inet_ntoa(LocalAddr.sin_addr)); - } - return UPNP_E_SUCCESS; -#elif (defined(BSD) && BSD >= 199306) - struct ifaddrs *ifap, *ifa; - - if (getifaddrs(&ifap) != 0) { - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "DiscoverInterfaces: getifaddrs() returned error\n" ); + // Get Adapters addresses required size. + ret = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, + NULL, adapts, &adapts_sz ); + if( ret != ERROR_BUFFER_OVERFLOW ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "GetAdaptersAddresses failed to find list of adapters\n" ); return UPNP_E_INIT; } - // cycle through available interfaces - for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { - // Skip loopback, point-to-point and down interfaces, - // except don't skip down interfaces - // if we're trying to get a list of configurable interfaces. - if( ( ifa->ifa_flags & IFF_LOOPBACK ) - || ( !( ifa->ifa_flags & IFF_UP ) ) ) { + // Allocate enough memory. + adapts = (PIP_ADAPTER_ADDRESSES)malloc( adapts_sz ); + if( adapts == NULL ) { + return UPNP_E_OUTOF_MEMORY; + } + + // Do the call that will actually return the info. + ret = GetAdaptersAddresses( AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, + NULL, adapts, &adapts_sz ); + if( ret != ERROR_SUCCESS ) { + free( adapts ); + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "GetAdaptersAddresses failed to find list of adapters\n" ); + return UPNP_E_INIT; + } + + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } + + adapts_item = adapts; + while( adapts_item != NULL ) { + + if( adapts_item->Flags & IP_ADAPTER_NO_MULTICAST ) { continue; } - if( ifa->ifa_addr->sa_family == AF_INET ) { - // We don't want the loopback interface. - if( ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr == - htonl( INADDR_LOOPBACK ) ) { + + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. continue; } + } - strncpy( out, inet_ntoa( ((struct sockaddr_in *)(ifa->ifa_addr))-> - sin_addr ), LINE_SIZE ); - out[LINE_SIZE-1] = '\0'; - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside getlocalhostname : after strncpy %s\n", - out ); + // Loop thru this adapter's unicast IP addresses. + uni_addr = adapts_item->FirstUnicastAddress; + while( uni_addr ) { + ip_addr = uni_addr->Address.lpSockaddr; + switch( ip_addr->sa_family ) { + case AF_INET: + memcpy( &v4_addr, &((struct sockaddr_in *)ip_addr)->sin_addr, sizeof(v4_addr) ); + valid_addr_found = 1; + break; + case AF_INET6: + // Only keep IPv6 link-local addresses. + if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ip_addr)->sin6_addr) ) { + memcpy( &v6_addr, &((struct sockaddr_in6 *)ip_addr)->sin6_addr, sizeof(v6_addr) ); + valid_addr_found = 1; + } + break; + default: + if( valid_addr_found == 0 ) { + // Address is not IPv4 or IPv6 and no valid address has + // yet been found for this interface. Discard interface name. + ifname_found = 0; + } + break; + } + + // Next address. + uni_addr = uni_addr->Next; + } + + if( valid_addr_found == 1 ) { + gIF_INDEX = adapts_item->IfIndex; + break; + } + + // Next adapter. + adapts_item = adapts_item->Next; + } + + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; + } + + inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4)); + inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6)); +#elif (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) + struct ifaddrs *ifap, *ifa; + struct in_addr v4_addr; + struct in6_addr v6_addr; + int ifname_found = 0; + int valid_addr_found = 0; + + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } + + // Get system interface addresses. + if( getifaddrs(&ifap) != 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "getifaddrs failed to find list of addresses\n" ); + return UPNP_E_INIT; + } + + // cycle through available interfaces and their addresses. + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) + { + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that + // don't support MULTICAST. + if( ( ifa->ifa_flags & IFF_LOOPBACK ) + || ( !( ifa->ifa_flags & IFF_UP ) ) + || ( !( ifa->ifa_flags & IFF_MULTICAST ) ) ) { + continue; + } + + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. + continue; + } + } + + // Keep interface addresses for later. + switch( ifa->ifa_addr->sa_family ) + { + case AF_INET: + memcpy( &v4_addr, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, sizeof(v4_addr) ); + valid_addr_found = 1; + break; + case AF_INET6: + // Only keep IPv6 link-local addresses. + if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr) ) { + memcpy( &v6_addr, &((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr, sizeof(v6_addr) ); + valid_addr_found = 1; + } + break; + default: + if( valid_addr_found == 0 ) { + // Address is not IPv4 or IPv6 and no valid address has + // yet been found for this interface. Discard interface name. + ifname_found = 0; + } break; } } freeifaddrs(ifap); - return ifa ? UPNP_E_SUCCESS : UPNP_E_INIT; + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; + } + + inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4)); + inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6)); + gIF_INDEX = if_nametoindex(gIF_NAME); #else char szBuffer[MAX_INTERFACES * sizeof( struct ifreq )]; struct ifconf ifConf; struct ifreq ifReq; - int nResult; + FILE* inet6_procfd; int i; int LocalSock; - struct sockaddr_in LocalAddr; - int j = 0; + struct in6_addr v6_addr; + int if_idx; + char addr6[8][5]; + char buf[65]; // INET6_ADDRSTRLEN + int ifname_found = 0; + int valid_addr_found = 0; - /* purify */ - memset(&ifConf, 0, sizeof(ifConf)); - memset(&ifReq, 0, sizeof(ifReq)); - memset(szBuffer, 0, sizeof(szBuffer)); + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. if( ( LocalSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) { @@ -3605,20 +3064,19 @@ void printNodes( IXML_Node * tmpRoot, int depth ) "Can't create addrlist socket\n" ); return UPNP_E_INIT; } + // Get the interface configuration information... ifConf.ifc_len = sizeof szBuffer; ifConf.ifc_ifcu.ifcu_buf = ( caddr_t ) szBuffer; - nResult = ioctl( LocalSock, SIOCGIFCONF, &ifConf ); - if( nResult < 0 ) { + if( ioctl( LocalSock, SIOCGIFCONF, &ifConf ) < 0 ) { UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "DiscoverInterfaces: SIOCGIFCONF returned error\n" ); - return UPNP_E_INIT; } - // Cycle through the list of interfaces looking for IP addresses. - for( i = 0; ( ( i < ifConf.ifc_len ) && ( j < DEFAULT_INTERFACE ) ); ) { + // Cycle through the list of interfaces looking for IP addresses. + for( i = 0; i < ifConf.ifc_len ; ) { struct ifreq *pifReq = ( struct ifreq * )( ( caddr_t ) ifConf.ifc_req + i ); i += sizeof *pifReq; @@ -3630,93 +3088,494 @@ void printNodes( IXML_Node * tmpRoot, int depth ) "Can't get interface flags for %s:\n", ifReq.ifr_name ); } - // Skip loopback, point-to-point and down interfaces, - // except don't skip down interfaces - // if we're trying to get a list of configurable interfaces. + + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that + // don't support MULTICAST. if( ( ifReq.ifr_flags & IFF_LOOPBACK ) - || ( !( ifReq.ifr_flags & IFF_UP ) ) ) { + || ( !( ifReq.ifr_flags & IFF_UP ) ) + || ( !( ifReq.ifr_flags & IFF_MULTICAST ) ) ) { continue; } - if( pifReq->ifr_addr.sa_family == AF_INET ) { - // Get a pointer to the address... - memcpy( &LocalAddr, &pifReq->ifr_addr, - sizeof pifReq->ifr_addr ); - // We don't want the loopback interface. - if( LocalAddr.sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) { + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. continue; } - } - //increment j if we found an address which is not loopback - //and is up - j++; + // Check address family. + if( pifReq->ifr_addr.sa_family == AF_INET ) { + // Copy interface name, IPv4 address and interface index. + strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ); + inet_ntop(AF_INET, &((struct sockaddr_in*)&pifReq->ifr_addr)->sin_addr, gIF_IPV4, sizeof(gIF_IPV4)); + gIF_INDEX = if_nametoindex(gIF_NAME); + + valid_addr_found = 1; + break; + } else { + // Address is not IPv4 + ifname_found = 0; + } } close( LocalSock ); - strncpy( out, inet_ntoa( LocalAddr.sin_addr ), LINE_SIZE ); - - UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, - "Inside getlocalhostname : after strncpy %s\n", - out ); - return UPNP_E_SUCCESS; -#endif + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; } + + // Try to get the IPv6 address for the same interface + // from "/proc/net/if_inet6", if possible. + inet6_procfd = fopen( "/proc/net/if_inet6", "r" ); + if( inet6_procfd != NULL ) { + while( fscanf(inet6_procfd, + "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*20s\n", + addr6[0],addr6[1],addr6[2],addr6[3], + addr6[4],addr6[5],addr6[6],addr6[7], &if_idx) != EOF) { + // Get same interface as IPv4 address retrieved. + if( gIF_INDEX == if_idx ) { + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s", + addr6[0],addr6[1],addr6[2],addr6[3], + addr6[4],addr6[5],addr6[6],addr6[7]); + // Validate formed address and check for link-local. + if( inet_pton(AF_INET6, buf, &v6_addr) > 0 && + IN6_IS_ADDR_LINKLOCAL(&v6_addr) ) { + // Got valid IPv6 link-local adddress. + strncpy( gIF_IPV6, buf, sizeof(gIF_IPV6) ); + break; + } + } + } + fclose( inet6_procfd ); + } +#endif + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Interface name=%s, index=%d, v4=%s, v6=%s\n", + gIF_NAME, gIF_INDEX, gIF_IPV4, gIF_IPV6 ); + + return UPNP_E_SUCCESS; +} + + +/*! + * \brief Schedule async functions in threadpool. + */ +#ifdef INCLUDE_CLIENT_APIS +void UpnpThreadDistribution(struct UpnpNonblockParam *Param) +{ + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside UpnpThreadDistribution \n"); + + switch (Param->FunName) { +#if EXCLUDE_GENA == 0 + case SUBSCRIBE: { + struct Upnp_Event_Subscribe Evt; + + Evt.ErrCode = genaSubscribe( + Param->Handle, + Param->Url, + (int *)&Param->TimeOut, + (char *)Evt.Sid); + strcpy(Evt.PublisherUrl, Param->Url); + Evt.TimeOut = Param->TimeOut; + Param->Fun(UPNP_EVENT_SUBSCRIBE_COMPLETE, &Evt, Param->Cookie); + free(Param); + break; + } + case UNSUBSCRIBE: { + struct Upnp_Event_Subscribe Evt; + Evt.ErrCode = genaUnSubscribe( + Param->Handle, + Param->SubsId); + strcpy((char *)Evt.Sid, Param->SubsId); + strcpy(Evt.PublisherUrl, ""); + Evt.TimeOut = 0; + Param->Fun(UPNP_EVENT_UNSUBSCRIBE_COMPLETE, &Evt, Param->Cookie); + free(Param); + break; + } + case RENEW: { + struct Upnp_Event_Subscribe Evt; + Evt.ErrCode = genaRenewSubscription( + Param->Handle, + Param->SubsId, + &Param->TimeOut); + Evt.TimeOut = Param->TimeOut; + strcpy((char *)Evt.Sid, Param->SubsId); + Param->Fun(UPNP_EVENT_RENEWAL_COMPLETE, &Evt, Param->Cookie); + free(Param); + break; + } +#endif /* EXCLUDE_GENA == 0 */ +#if EXCLUDE_SOAP == 0 + case ACTION: { + struct Upnp_Action_Complete Evt; + Evt.ActionResult = NULL; + Evt.ErrCode = SoapSendAction( + Param->Url, + Param->ServiceType, + Param->Act, &Evt.ActionResult); + Evt.ActionRequest = Param->Act; + strcpy(Evt.CtrlUrl, Param->Url); + Param->Fun(UPNP_CONTROL_ACTION_COMPLETE, &Evt, Param->Cookie); + ixmlDocument_free(Evt.ActionRequest); + ixmlDocument_free(Evt.ActionResult); + free(Param); + break; + } + case STATUS: { + struct Upnp_State_Var_Complete Evt; + Evt.ErrCode = SoapGetServiceVarStatus( + Param->Url, + Param->VarName, + &Evt.CurrentVal); + strcpy(Evt.StateVarName, Param->VarName); + strcpy(Evt.CtrlUrl, Param->Url); + Param->Fun(UPNP_CONTROL_GET_VAR_COMPLETE, &Evt, Param->Cookie); + free(Evt.CurrentVal); + free(Param); + break; + } +#endif /* EXCLUDE_SOAP == 0 */ + default: + break; + } + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Exiting UpnpThreadDistribution\n"); +} +#endif /* INCLUDE_CLIENT_APIS */ + + +/*! + * \brief Get callback function ptr from a handle. + * + * \return Upnp_FunPtr + */ +Upnp_FunPtr GetCallBackFn(UpnpClient_Handle Hnd) +{ + return ((struct Handle_Info *)HandleTable[Hnd])->Callback; +} + + +int GetFreeHandle() +{ + /* Handle 0 is not used as NULL translates to 0 when passed as a handle */ + int i = 1; + + while (i < NUM_HANDLE && HandleTable[i] != NULL) { + ++i; + } + + if (i == NUM_HANDLE) { + return UPNP_E_OUTOF_HANDLE; + } else { + return i; + } +} + + +/* Assumes at most one client */ +Upnp_Handle_Type GetClientHandleInfo( + UpnpClient_Handle *client_handle_out, + struct Handle_Info **HndInfo) +{ + Upnp_Handle_Type ret = HND_CLIENT; + UpnpClient_Handle client; + + if (GetHandleInfo(1, HndInfo) == HND_CLIENT) { + client = 1; + } else if (GetHandleInfo(2, HndInfo) == HND_CLIENT) { + client = 2; + } else { + client = -1; + ret = HND_INVALID; + } + + *client_handle_out = client; + return ret; +} + + +Upnp_Handle_Type GetDeviceHandleInfo( + const int AddressFamily, + UpnpDevice_Handle *device_handle_out, + struct Handle_Info **HndInfo) +{ + /* Check if we've got a registered device of the address family specified. */ + if ((AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 0) || + (AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 0)) { + *device_handle_out = -1; + return HND_INVALID; + } + + /* Find it. */ + for (*device_handle_out=1; *device_handle_out < NUM_HANDLE; (*device_handle_out)++) { + if (GetHandleInfo(*device_handle_out, HndInfo) == HND_DEVICE) { + if ((*HndInfo)->DeviceAf == AddressFamily) { + return HND_DEVICE; + } + } + } + + *device_handle_out = -1; + return HND_INVALID; +} + + +Upnp_Handle_Type GetHandleInfo( + UpnpClient_Handle Hnd, + struct Handle_Info **HndInfo) +{ + Upnp_Handle_Type ret = UPNP_E_INVALID_HANDLE; + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "GetHandleInfo: entering, Handle is %d\n", Hnd); + + if (Hnd < 1 || Hnd >= NUM_HANDLE) { + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "GetHandleInfo: Handle out of range\n"); + } else if (HandleTable[Hnd] == NULL) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "GetHandleInfo: HandleTable[%d] is NULL\n", + Hnd); + } else if (HandleTable[Hnd] != NULL) { + *HndInfo = (struct Handle_Info *)HandleTable[Hnd]; + ret = ((struct Handle_Info *)*HndInfo)->HType; + } + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "GetHandleInfo: exiting\n"); + + return ret; +} + + +int FreeHandle(int Upnp_Handle) +{ + int ret = UPNP_E_INVALID_HANDLE; + + UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, + "FreeHandle: entering, Handle is %d\n", Upnp_Handle); + + if (Upnp_Handle < 1 || Upnp_Handle >= NUM_HANDLE) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "FreeHandle: Handle %d is out of range\n", + Upnp_Handle); + } else if (HandleTable[Upnp_Handle] == NULL) { + UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, + "FreeHandle: HandleTable[%d] is NULL\n", + Upnp_Handle); + } else { + free( HandleTable[Upnp_Handle] ); + HandleTable[Upnp_Handle] = NULL; + ret = UPNP_E_SUCCESS; + } + + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "FreeHandle: exiting, ret = %d.\n", ret); + + return ret; +} + + +int PrintHandleInfo(UpnpClient_Handle Hnd) +{ + struct Handle_Info * HndInfo; + if (HandleTable[Hnd] != NULL) { + HndInfo = HandleTable[Hnd]; + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Printing information for Handle_%d\n", Hnd); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "HType_%d\n", HndInfo->HType); +#ifdef INCLUDE_DEVICE_APIS + if(HndInfo->HType != HND_CLIENT) + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "DescURL_%s\n", HndInfo->DescURL); +#endif /* INCLUDE_DEVICE_APIS */ + } else { + return UPNP_E_INVALID_HANDLE; + } + + return UPNP_E_SUCCESS; +} + + +int getlocalhostname(char *out, const int out_len) +{ + int ret = UPNP_E_SUCCESS; + char tempstr[16]; + const char *p = NULL; + +#ifdef WIN32 + struct hostent *h = NULL; + struct sockaddr_in LocalAddr; + + gethostname(out, out_len); + h = gethostbyname(out); + if (h != NULL) { + memcpy(&LocalAddr.sin_addr, h->h_addr_list[0], 4); + p = inet_ntop(AF_INET, &LocalAddr.sin_addr, tempstr, sizeof(tempstr)); + if (p) { + strncpy(out, p, out_len); + } else { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "getlocalhostname: inet_ntop returned error\n" ); + ret = UPNP_E_INIT; + } + } else { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "getlocalhostname: gethostbyname returned error\n" ); + ret = UPNP_E_INIT; + } + +#elif (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) + struct ifaddrs *ifap, *ifa; + + if (getifaddrs(&ifap) != 0) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "DiscoverInterfaces: getifaddrs() returned error\n"); + return UPNP_E_INIT; + } + + /* cycle through available interfaces */ + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + /* Skip loopback, point-to-point and down interfaces, + * except don't skip down interfaces + * if we're trying to get a list of configurable interfaces. */ + if ((ifa->ifa_flags & IFF_LOOPBACK) || + (!( ifa->ifa_flags & IFF_UP))) { + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { + /* We don't want the loopback interface. */ + if (((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr == + htonl(INADDR_LOOPBACK)) { + continue; + } + p = inet_ntop(AF_INET, + &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, + tempstr, sizeof(tempstr)); + if (p) { + strncpy(out, p, out_len); + } else { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "getlocalhostname: inet_ntop returned error\n"); + ret = UPNP_E_INIT; + } + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside getlocalhostname: after strncpy %s\n", out); + break; + } + } + freeifaddrs(ifap); + + ret = ifa ? UPNP_E_SUCCESS : UPNP_E_INIT; +#else + char szBuffer[MAX_INTERFACES * sizeof (struct ifreq)]; + struct ifconf ifConf; + struct ifreq ifReq; + int nResult; + int i; + int LocalSock; + struct sockaddr_in LocalAddr; + int j = 0; + + /* purify */ + memset(&ifConf, 0, sizeof(ifConf)); + memset(&ifReq, 0, sizeof(ifReq)); + memset(szBuffer, 0, sizeof(szBuffer)); + + /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ + LocalSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (LocalSock < 0) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Can't create addrlist socket\n"); + return UPNP_E_INIT; + } + /* Get the interface configuration information... */ + ifConf.ifc_len = sizeof szBuffer; + ifConf.ifc_ifcu.ifcu_buf = (caddr_t) szBuffer; + nResult = ioctl(LocalSock, SIOCGIFCONF, &ifConf); + if (nResult < 0) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "DiscoverInterfaces: SIOCGIFCONF returned error\n"); + + return UPNP_E_INIT; + } + + /* Cycle through the list of interfaces looking for IP addresses. */ + for (i = 0; i < ifConf.ifc_len && j < DEFAULT_INTERFACE; ) { + struct ifreq *pifReq = + (struct ifreq *)((caddr_t)ifConf.ifc_req + i); + i += sizeof *pifReq; + /* See if this is the sort of interface we want to deal with. */ + strcpy(ifReq.ifr_name, pifReq->ifr_name); + if (ioctl(LocalSock, SIOCGIFFLAGS, &ifReq) < 0) { + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Can't get interface flags for %s:\n", + ifReq.ifr_name); + } + /* Skip loopback, point-to-point and down interfaces, + * except don't skip down interfaces + * if we're trying to get a list of configurable interfaces. */ + if ((ifReq.ifr_flags & IFF_LOOPBACK) || + (!(ifReq.ifr_flags & IFF_UP))) { + continue; + } + if (pifReq->ifr_addr.sa_family == AF_INET) { + /* Get a pointer to the address...*/ + memcpy(&LocalAddr, &pifReq->ifr_addr, + sizeof pifReq->ifr_addr); + /* We don't want the loopback interface. */ + if (LocalAddr.sin_addr.s_addr == + htonl(INADDR_LOOPBACK)) { + continue; + } + } + /* increment j if we found an address which is not loopback + * and is up */ + j++; + } + close(LocalSock); + + p = inet_ntop(AF_INET, &LocalAddr.sin_addr, tempstr, sizeof(tempstr)); + if (p) { + strncpy(out, p, out_len); + } else { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "getlocalhostname: inet_ntop returned error\n" ); + ret = UPNP_E_INIT; + } + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "Inside getlocalhostname: after strncpy %s\n", out); +#endif + return ret; +} + #ifdef INCLUDE_DEVICE_APIS #if EXCLUDE_SSDP == 0 - - /************************************************************************** - * Function: AutoAdvertise - * - * Parameters: - * IN void *input: information provided to the thread. - * - * Description: - * This function is a timer thread scheduled by UpnpSendAdvertisement - * to the send advetisement again. - * - * Return Values: VOID - * - ***************************************************************************/ -void -AutoAdvertise( void *input ) +void AutoAdvertise(void *input) { - upnp_timeout *event = ( upnp_timeout * ) input; + upnp_timeout *event = (upnp_timeout *)input; - UpnpSendAdvertisement( event->handle, *( ( int * )event->Event ) ); - free_upnp_timeout( event ); + UpnpSendAdvertisement(event->handle, *((int *)event->Event)); + free_upnp_timeout(event); } -#endif //INCLUDE_DEVICE_APIS -#endif +#endif /* EXCLUDE_SSDP == 0 */ +#endif /* INCLUDE_DEVICE_APIS */ + -/* - **************************** */ #ifdef INTERNAL_WEB_SERVER - - /************************************************************************** - * Function: UpnpSetWebServerRootDir - * - * Parameters: - * IN const char* rootDir:Path of the root directory of the web server. - * - * Description: - * This function sets the document root directory for - * the internal web server. This directory is considered the - * root directory (i.e. "/") of the web server. - * This function also activates or deactivates the web server. - * To disable the web server, pass NULL for rootDir to - * activate, pass a valid directory string. - * - * Note that this function is not available when the web server is not - * compiled into the UPnP Library. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else returns appropriate error - ***************************************************************************/ -int -UpnpSetWebServerRootDir( IN const char *rootDir ) +int UpnpSetWebServerRootDir(const char *rootDir) { if( UpnpSdkInit == 0 ) return UPNP_E_FINISH; @@ -3726,37 +3585,15 @@ UpnpSetWebServerRootDir( IN const char *rootDir ) membuffer_destroy( &gDocumentRootDir ); - return ( web_server_set_root_dir( rootDir ) ); + return web_server_set_root_dir(rootDir); } -#endif // INTERNAL_WEB_SERVER -/* - *************************** */ +#endif /* INTERNAL_WEB_SERVER */ - /************************************************************************** - * Function: UpnpAddVirtualDir - * - * Parameters: - * IN const char *newDirName:The name of the new directory mapping to add. - * - * Description: - * This function adds a virtual directory mapping. - * - * All webserver requests containing the given directory are read using - * functions contained in a UpnpVirtualDirCallbacks structure registered - * via UpnpSetVirtualDirCallbacks. - * - * Note that this function is not available when the web server is not - * compiled into the UPnP Library. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else returns appropriate error - ***************************************************************************/ -int -UpnpAddVirtualDir( IN const char *newDirName ) + +int UpnpAddVirtualDir(const char *newDirName) { - - virtualDirList *pNewVirtualDir, - *pLast; + virtualDirList *pNewVirtualDir; + virtualDirList *pLast; virtualDirList *pCurVirtualDir; char dirName[NAME_SIZE]; @@ -3808,22 +3645,9 @@ UpnpAddVirtualDir( IN const char *newDirName ) return UPNP_E_SUCCESS; } - /************************************************************************** - * Function: UpnpRemoveVirtualDir - * - * Parameters: - * IN const char *newDirName:The name of the directory mapping to remove. - * - * Description: - * This function removes a virtual directory mapping. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else returns appropriate error - ***************************************************************************/ -int -UpnpRemoveVirtualDir( IN const char *dirName ) -{ +int UpnpRemoveVirtualDir(const char *dirName) +{ virtualDirList *pPrev; virtualDirList *pCur; int found = 0; @@ -3870,24 +3694,11 @@ UpnpRemoveVirtualDir( IN const char *dirName ) return UPNP_E_SUCCESS; else return UPNP_E_INVALID_PARAM; - } - /************************************************************************** - * Function: UpnpRemoveAllVirtualDirs - * - * Parameters: VOID - * - * Description: - * This function removes all the virtual directory mappings. - * - * Return Values: VOID - * - ***************************************************************************/ -void -UpnpRemoveAllVirtualDirs(void) -{ +void UpnpRemoveAllVirtualDirs(void) +{ virtualDirList *pCur; virtualDirList *pNext; @@ -3905,24 +3716,10 @@ UpnpRemoveAllVirtualDirs(void) } pVirtualDirList = NULL; - } - /************************************************************************** - * Function: UpnpEnableWebserver - * - * Parameters: - * IN int enable: TRUE to enable, FALSE to disable. - * - * Description: - * This function enables or disables the webserver. A value of - * TRUE enables the webserver, FALSE disables it. - * - * Return Values: int - * UPNP_E_SUCCESS if successful else returns appropriate error - ***************************************************************************/ -int -UpnpEnableWebserver( IN int enable ) + +int UpnpEnableWebserver(int enable) { int retVal; @@ -3945,7 +3742,7 @@ UpnpEnableWebserver( IN int enable ) bWebServerState = WEB_SERVER_DISABLED; SetHTTPGetCallback( NULL ); break; -#endif +#endif /* INTERNAL_WEB_SERVER */ default: return UPNP_E_INVALID_PARAM; } @@ -3953,151 +3750,147 @@ UpnpEnableWebserver( IN int enable ) return UPNP_E_SUCCESS; } - /************************************************************************** - * Function: UpnpIsWebserverEnabled + +/*! + * \brief Checks if the webserver is enabled or disabled. * - * Parameters: VOID - * - * Description: - * This function checks if the webserver is enabled or disabled. - * - * Return Values: int - * 1, if webserver enabled - * 0, if webserver disabled - ***************************************************************************/ -int -UpnpIsWebserverEnabled(void) + * \return 1, if webserver is enabled or 0, if webserver is disabled. + */ +int UpnpIsWebserverEnabled(void) { - if( UpnpSdkInit != 1 ) { - return 0; - } - - return ( bWebServerState == WEB_SERVER_ENABLED ); -} - - /************************************************************************** - * Function: UpnpSetVirtualDirCallbacks - * - * Parameters: - * IN struct UpnpVirtualDirCallbacks *callbacks:a structure that - * contains the callback functions. - * - * Description: - * This function sets the callback function to be used to - * access a virtual directory. - * - * Return Values: int - * UPNP_E_SUCCESS on success, or UPNP_E_INVALID_PARAM - ***************************************************************************/ -int -UpnpSetVirtualDirCallbacks( IN struct UpnpVirtualDirCallbacks *callbacks ) -{ - struct UpnpVirtualDirCallbacks *pCallback; - - if( UpnpSdkInit != 1 ) { - // SDK is not initialized - return UPNP_E_FINISH; - } - - pCallback = &virtualDirCallback; - - if( callbacks == NULL ) - return UPNP_E_INVALID_PARAM; - - pCallback->get_info = callbacks->get_info; - pCallback->open = callbacks->open; - pCallback->close = callbacks->close; - pCallback->read = callbacks->read; - pCallback->write = callbacks->write; - pCallback->seek = callbacks->seek; - - return UPNP_E_SUCCESS; -} - - /************************************************************************** - * Function: UpnpSetContentLength - * OBSOLETE METHOD : use {\bf UpnpSetMaxContentLength} instead. - ***************************************************************************/ -int -UpnpSetContentLength( IN UpnpClient_Handle Hnd, - /** The handle of the device instance - for which the coincoming content length needs - to be set. */ - - IN int contentLength - /** Permissible content length */ - ) -{ - int errCode = UPNP_E_SUCCESS; - struct Handle_Info *HInfo = NULL; - - do { - if( UpnpSdkInit != 1 ) { - errCode = UPNP_E_FINISH; - break; - } - - HandleLock(); - - errCode = GetHandleInfo( Hnd, &HInfo ); - - if( errCode != HND_DEVICE ) { - errCode = UPNP_E_INVALID_HANDLE; - break; - } - - if( contentLength > MAX_SOAP_CONTENT_LENGTH ) { - errCode = UPNP_E_OUTOF_BOUNDS; - break; - } - - g_maxContentLength = contentLength; - - } while( 0 ); - - HandleUnlock(); - return errCode; + if (UpnpSdkInit != 1) { + return 0; + } + return bWebServerState == WEB_SERVER_ENABLED; } -/************************************************************************** - * Function: UpnpSetMaxContentLength - * - * Parameters: - * IN int contentLength: The maximum size to be set - * - * Description: - * Sets the maximum content-length that the SDK will process on an - * incoming SOAP requests or responses. This API allows devices that have - * memory constraints to exhibit consistent behaviour if the size of the - * incoming SOAP message exceeds the memory that device can allocate. - * The default maximum content-length is {\tt DEFAULT_SOAP_CONTENT_LENGTH} - * = 16K bytes. - * - * Return Values: int - * UPNP_E_SUCCESS: The operation completed successfully. - * - ***************************************************************************/ -int -UpnpSetMaxContentLength ( - IN size_t contentLength - /** Permissible content length, in bytes */ - ) +int UpnpVirtualDir_set_GetInfoCallback(VDCallback_GetInfo callback) { - int errCode = UPNP_E_SUCCESS; - - do { - if( UpnpSdkInit != 1 ) { - errCode = UPNP_E_FINISH; - break; - } - - g_maxContentLength = contentLength; - - } while( 0 ); - - return errCode; + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.get_info = callback; + } + return ret; +} + + +int UpnpVirtualDir_set_OpenCallback(VDCallback_Open callback) +{ + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.open = callback; + } + + return ret; +} + + +int UpnpVirtualDir_set_ReadCallback(VDCallback_Read callback) +{ + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.read = callback; + } + + return ret; +} + + +int UpnpVirtualDir_set_WriteCallback(VDCallback_Write callback) +{ + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.write = callback; + } + + return ret; +} + + +int UpnpVirtualDir_set_SeekCallback(VDCallback_Seek callback) +{ + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.seek = callback; + } + + return ret; +} + + +int UpnpVirtualDir_set_CloseCallback(VDCallback_Close callback) +{ + int ret = UPNP_E_SUCCESS; + if (!callback) { + ret = UPNP_E_INVALID_PARAM; + } else { + virtualDirCallback.close = callback; + } + + return ret; +} + + +int UpnpSetContentLength( + UpnpClient_Handle Hnd, + int contentLength) +{ + int errCode = UPNP_E_SUCCESS; + struct Handle_Info *HInfo = NULL; + + do { + if (UpnpSdkInit != 1) { + errCode = UPNP_E_FINISH; + break; + } + + HandleLock(); + + errCode = GetHandleInfo(Hnd, &HInfo); + + if (errCode != HND_DEVICE) { + errCode = UPNP_E_INVALID_HANDLE; + break; + } + + if (contentLength > MAX_SOAP_CONTENT_LENGTH) { + errCode = UPNP_E_OUTOF_BOUNDS; + break; + } + + g_maxContentLength = contentLength; + } while(0); + + HandleUnlock(); + return errCode; +} + + +int UpnpSetMaxContentLength(size_t contentLength) +{ + int errCode = UPNP_E_SUCCESS; + + do { + if (UpnpSdkInit != 1) { + errCode = UPNP_E_FINISH; + break; + } + g_maxContentLength = contentLength; + } while(0); + + return errCode; } diff --git a/upnp/src/api/upnpdebug.c b/upnp/src/api/upnpdebug.c index e2246a6..c34f08f 100644 --- a/upnp/src/api/upnpdebug.c +++ b/upnp/src/api/upnpdebug.c @@ -6,12 +6,12 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * * Redistributions of source code must retain the above copyright notice, + * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, + * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * * Neither name of Intel Corporation nor the names of its contributors + * - Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -30,148 +30,92 @@ ******************************************************************************/ #include "config.h" + + +#include "ithread.h" +#include "ixml.h" +#include "upnp.h" #include "upnpdebug.h" + + +#include #include #include -#include "ithread.h" -#include "upnp.h" -#include #include -//Mutex to synchronize all the log file opeartions in the debug mode +/*! Mutex to synchronize all the log file opeartions in the debug mode */ static ithread_mutex_t GlobalDebugMutex; -// Global log level +/*! Global log level */ static Upnp_LogLevel g_log_level = UPNP_DEFAULT_LOG_LEVEL; -//File handle for the error log file +/*! File handle for the error log file */ static FILE *ErrFileHnd = NULL; -//File handle for the information log file +/*! File handle for the information log file */ static FILE *InfoFileHnd = NULL; -//Name of the error file +/*! Name of the error file */ static const char *errFileName = "IUpnpErrFile.txt"; -//Name of the info file +/*! Name of the info file */ static const char *infoFileName = "IUpnpInfoFile.txt"; +#ifdef DEBUG -/*************************************************************************** - * Function : UpnpSetLogFileNames - * - * Parameters: - * IN const char* ErrFileName: name of the error file - * IN const char *InfoFileName: name of the information file - * IN int size: Size of the buffer - * IN int starLength: This parameter provides the width of the banner - * - * Description: - * This functions takes the buffer and writes the buffer in the file as - * per the requested banner - * Returns: void - ***************************************************************************/ -void -UpnpSetLogFileNames ( IN const char *ErrFileName, - IN const char *InfoFileName ) + +int UpnpInitLog(void) { - if( ErrFileName ) { - errFileName = ErrFileName; - } - if( InfoFileName ) { - infoFileName = InfoFileName; - } + ithread_mutex_init(&GlobalDebugMutex, NULL); + if(DEBUG_TARGET == 1) { + if((ErrFileHnd = fopen( errFileName, "a")) == NULL) { + return -1; + } + if((InfoFileHnd = fopen( infoFileName, "a")) == NULL) { + return -1; + } + } + return UPNP_E_SUCCESS; } -/*************************************************************************** - * Function : UpnpInitLog - * - * Parameters: void - * - * Description: - * This functions initializes the log files - * - * Returns: int - * -1 : If fails - * UPNP_E_SUCCESS : if success - ***************************************************************************/ -int -UpnpInitLog(void) -{ - ithread_mutex_init( &GlobalDebugMutex, NULL ); - - if( DEBUG_TARGET == 1 ) { - if( ( ErrFileHnd = fopen( errFileName, "a" ) ) == NULL ) - return -1; - if( ( InfoFileHnd = fopen( infoFileName, "a" ) ) == NULL ) - return -1; - } - return UPNP_E_SUCCESS; -} - - -/*************************************************************************** - * Function : UpnpSetLogLevel - * - * Parameters: Upnp_LogLevel log_level - * - * Description: - * This functions set the log level (see {\tt Upnp_LogLevel} - * Returns: void - ***************************************************************************/ -void -UpnpSetLogLevel (Upnp_LogLevel log_level) +void UpnpSetLogLevel(Upnp_LogLevel log_level) { g_log_level = log_level; } -/*************************************************************************** - * Function : UpnpCloseLog - * - * Parameters: void - * - * Description: - * This functions closes the log files - * Returns: void - ***************************************************************************/ -void -UpnpCloseLog(void) +void UpnpCloseLog(void) { - if( DEBUG_TARGET == 1 ) { - fflush( ErrFileHnd ); - fflush( InfoFileHnd ); - fclose( ErrFileHnd ); - fclose( InfoFileHnd ); - } - ithread_mutex_destroy( &GlobalDebugMutex ); - + if (DEBUG_TARGET == 1) { + fflush(ErrFileHnd); + fflush(InfoFileHnd); + fclose(ErrFileHnd); + fclose(InfoFileHnd); + } + ithread_mutex_destroy(&GlobalDebugMutex); +} + + +void UpnpSetLogFileNames( + const char *ErrFileName, + const char *InfoFileName) +{ + if (ErrFileName) { + errFileName = ErrFileName; + } + if (InfoFileName) { + infoFileName = InfoFileName; + } } -/*************************************************************************** - * Function : DebugAtThisLevel - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * - * Description: - * This functions returns true if debug output should be done in this - * module. - * - * Returns: int - ***************************************************************************/ -#ifdef DEBUG int DebugAtThisLevel( - IN Upnp_LogLevel DLevel, - IN Dbg_Module Module) + Upnp_LogLevel DLevel, + Dbg_Module Module) { int ret = DLevel <= g_log_level; ret &= @@ -186,38 +130,15 @@ int DebugAtThisLevel( return ret; } -#endif -/*************************************************************************** - * Function : UpnpPrintf - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * IN char *DbgFileName: Name of the file from where debug statement is - * coming - * IN int DbgLineNo : Line number of the file from where debug statement - * is coming - * IN char * FmtStr, ...: Variable number of arguments that will go - * in the debug statement - * - * Description: - * This functions prints the debug statement either on the startdard - * output or log file along with the information from where this debug - * statement is coming - * Returns: void - ***************************************************************************/ -#ifdef DEBUG void UpnpPrintf( - IN Upnp_LogLevel DLevel, - IN Dbg_Module Module, - IN const char *DbgFileName, - IN int DbgLineNo, - IN const char *FmtStr, - ... ) + Upnp_LogLevel DLevel, + Dbg_Module Module, + const char *DbgFileName, + int DbgLineNo, + const char *FmtStr, + ...) { va_list ArgList; @@ -249,27 +170,9 @@ void UpnpPrintf( va_end(ArgList); ithread_mutex_unlock(&GlobalDebugMutex); } -#endif -/*************************************************************************** - * Function : UpnpGetDebugFile - * - * Parameters: - * IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide - * whether debug statement will go to standard output, - * or any of the log files. - * IN Dbg_Module Module: debug will go in the name of this module - * - * Description: - * This function checks if the module is turned on for debug - * and returns the file descriptor corresponding to the debug level - * Returns: FILE * - * NULL : if the module is turn off for debug - * else returns the right file descriptor - ***************************************************************************/ -#ifdef DEBUG -FILE *GetDebugFile( Upnp_LogLevel DLevel, Dbg_Module Module ) +FILE *GetDebugFile(Upnp_LogLevel DLevel, Dbg_Module Module) { FILE *ret; @@ -287,28 +190,12 @@ FILE *GetDebugFile( Upnp_LogLevel DLevel, Dbg_Module Module ) return ret; } -#endif -/*************************************************************************** - * Function : UpnpDisplayFileAndLine - * - * Parameters: - * IN FILE *fd: File descriptor where line number and file name will be - * written - * IN char *DbgFileName: Name of the file - * IN int DbgLineNo : Line number of the file - * - * Description: - * This function writes the file name and file number from where - * debug statement is coming to the log file - * Returns: void - ***************************************************************************/ -#ifdef DEBUG void UpnpDisplayFileAndLine( - IN FILE * fd, - IN const char *DbgFileName, - IN int DbgLineNo) + FILE *fd, + const char *DbgFileName, + int DbgLineNo) { #define NLINES 2 #define MAX_LINE_SIZE 512 @@ -324,7 +211,12 @@ void UpnpDisplayFileAndLine( /* Put the debug lines in the buffer */ sprintf(buf[0], "DEBUG - THREAD ID: 0x%lX", - (unsigned long int)ithread_self()); +#ifdef WIN32 + (unsigned long int)ithread_self().p +#else + (unsigned long int)ithread_self() +#endif + ); if (DbgFileName) { sprintf(buf[1], "FILE: %s, LINE: %d", @@ -336,29 +228,13 @@ void UpnpDisplayFileAndLine( UpnpDisplayBanner(fd, lines, NLINES, NUMBER_OF_STARS); fflush(fd); } -#endif -/*************************************************************************** - * Function : UpnpDisplayBanner - * - * Parameters: - * IN FILE *fd: file descriptor where the banner will be written - * IN char **lines: The buffer that will be written - * IN int size: Size of the buffer - * IN int starLength: This parameter provides the width of the banner - * - * Description: - * This functions takes the buffer and writes the buffer in the file as - * per the requested banner - * Returns: void - ***************************************************************************/ -#ifdef DEBUG void UpnpDisplayBanner( - IN FILE * fd, - IN const char **lines, - IN size_t size, - IN int starLength) + FILE * fd, + const char **lines, + size_t size, + int starLength) { int leftMarginLength = starLength / 2 + 1; int rightMarginLength = starLength / 2 + 1; @@ -399,12 +275,81 @@ void UpnpDisplayBanner( rightMargin[rightMarginLength] = 0; fprintf( fd, "*%s%s%s*\n", leftMargin, line, rightMargin ); } - fprintf( fd, "%s\n\n", stars ); + fprintf(fd, "%s\n\n", stars); - free( currentLine ); - free( stars ); - free( rightMargin ); - free( leftMargin ); + free(currentLine); + free(stars); + free(rightMargin); + free(leftMargin); } -#endif - + + +void PrintThreadPoolStats( + ThreadPool *tp, + const char *DbgFileName, + int DbgLineNo, + const char *msg) +{ + ThreadPoolStats stats; + ThreadPoolGetStats(tp, &stats); + UpnpPrintf(UPNP_INFO, API, DbgFileName, DbgLineNo, + "%s\n" + "High Jobs pending: %d\n" + "Med Jobs Pending: %d\n" + "Low Jobs Pending: %d\n" + "Average wait in High Q in milliseconds: %lf\n" + "Average wait in Med Q in milliseconds: %lf\n" + "Average wait in Low Q in milliseconds: %lf\n" + "Max Threads Used: %d\n" + "Worker Threads: %d\n" + "Persistent Threads: %d\n" + "Idle Threads: %d\n" + "Total Threads: %d\n" + "Total Work Time: %lf\n" + "Total Idle Time: %lf\n", + msg, + stats.currentJobsHQ, + stats.currentJobsMQ, + stats.currentJobsLQ, + stats.avgWaitHQ, + stats.avgWaitMQ, + stats.avgWaitLQ, + stats.maxThreads, + stats.workerThreads, + stats.persistentThreads, + stats.idleThreads, + stats.totalThreads, + stats.totalWorkTime, + stats.totalIdleTime); +} + + +void printNodes(IXML_Node *tmpRoot, int depth) +{ + int i; + IXML_NodeList *NodeList1; + IXML_Node *ChildNode1; + unsigned short NodeType; + const DOMString NodeValue; + const DOMString NodeName; + NodeList1 = ixmlNode_getChildNodes(tmpRoot); + for (i = 0; i < 100; ++i) { + ChildNode1 = ixmlNodeList_item(NodeList1, i); + if (ChildNode1 == NULL) { + break; + } + + printNodes(ChildNode1, depth+1); + NodeType = ixmlNode_getNodeType(ChildNode1); + NodeValue = ixmlNode_getNodeValue(ChildNode1); + NodeName = ixmlNode_getNodeName(ChildNode1); + UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, + "DEPTH-%2d-IXML_Node Type %d, " + "IXML_Node Name: %s, IXML_Node Value: %s\n", + depth, NodeType, NodeName, NodeValue); + } +} + + +#endif /* DEBUG */ + diff --git a/upnp/src/gena/gena_ctrlpt.c b/upnp/src/gena/gena_ctrlpt.c index 9cf292d..38a43b9 100644 --- a/upnp/src/gena/gena_ctrlpt.c +++ b/upnp/src/gena/gena_ctrlpt.c @@ -127,7 +127,7 @@ static int ScheduleGenaAutoRenew( /*! [in] The time out value of the subscription. */ IN int TimeOut, /*! [in] Subscription being renewed. */ - IN client_subscription *sub) + IN ClientSubscription *sub) { struct Upnp_Event_Subscribe *RenewEventStruct = NULL; upnp_timeout *RenewEvent = NULL; @@ -300,14 +300,24 @@ static int gena_subscribe( "TIMEOUT: Second-", timeout_str ); } else { // subscribe + if( dest_url.hostport.IPaddress.ss_family == AF_INET6 ) { return_code = http_MakeMessage( &request, 1, 1, "q" "sssdsc" "sc" "sscc", HTTPMETHOD_SUBSCRIBE, &dest_url, - "CALLBACK: ", + "CALLBACK: ", + "NT: upnp:event", + "TIMEOUT: Second-", timeout_str ); + } else { + return_code = http_MakeMessage( + &request, 1, 1, + "q" "sssdsc" "sc" "sscc", + HTTPMETHOD_SUBSCRIBE, &dest_url, + "CALLBACK: ", "NT: upnp:event", "TIMEOUT: Second-", timeout_str); } + } if (return_code != 0) { return return_code; } @@ -368,7 +378,7 @@ static int gena_subscribe( int genaUnregisterClient(UpnpClient_Handle client_handle) { - client_subscription sub_copy; + ClientSubscription sub_copy; int return_code = UPNP_E_SUCCESS; struct Handle_Info *handle_info = NULL; http_parser_t response; @@ -413,10 +423,10 @@ int genaUnSubscribe( UpnpClient_Handle client_handle, const Upnp_SID in_sid) { - client_subscription *sub = NULL; + ClientSubscription *sub = NULL; int return_code = GENA_SUCCESS; struct Handle_Info *handle_info; - client_subscription sub_copy; + ClientSubscription sub_copy; http_parser_t response; // validate handle and sid @@ -467,7 +477,7 @@ int genaSubscribe( Upnp_SID out_sid) { int return_code = GENA_SUCCESS; - client_subscription *newSubscription = NULL; + ClientSubscription *newSubscription = NULL; uuid_upnp uid; Upnp_SID temp_sid; char *ActualSID = NULL; @@ -517,7 +527,7 @@ int genaSubscribe( strcpy( EventURL, PublisherURL ); // fill subscription - newSubscription = (client_subscription *)malloc(sizeof (client_subscription)); + newSubscription = (ClientSubscription *)malloc(sizeof (ClientSubscription)); if (newSubscription == NULL) { return_code = UPNP_E_OUTOF_MEMORY; goto error_handler; @@ -552,8 +562,8 @@ int genaRenewSubscription( int *TimeOut) { int return_code = GENA_SUCCESS; - client_subscription *sub = NULL; - client_subscription sub_copy; + ClientSubscription *sub = NULL; + ClientSubscription sub_copy; struct Handle_Info *handle_info; char *ActualSID; ThreadPoolJob tempJob; @@ -657,7 +667,7 @@ void gena_process_notification_event( IXML_Document *ChangedVars = NULL; int eventKey; token sid; - client_subscription *subscription = NULL; + ClientSubscription *subscription = NULL; struct Handle_Info *handle_info; void *cookie; Upnp_FunPtr callback; diff --git a/upnp/src/gena/gena_device.c b/upnp/src/gena/gena_device.c index 537b01f..da66e38 100644 --- a/upnp/src/gena/gena_device.c +++ b/upnp/src/gena/gena_device.c @@ -1241,7 +1241,7 @@ void gena_process_subscription_request( HandleLock(); // CURRENTLY, ONLY ONE DEVICE - if (GetDeviceHandleInfo( + if (GetDeviceHandleInfo(info->foreign_sockaddr.ss_family , &device_handle, &handle_info) != HND_DEVICE) { free(event_url_path); error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); @@ -1409,7 +1409,7 @@ void gena_process_subscription_renewal_request( HandleLock(); // CURRENTLY, ONLY SUPPORT ONE DEVICE - if (GetDeviceHandleInfo( + if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family, &device_handle, &handle_info ) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); @@ -1520,7 +1520,7 @@ void gena_process_unsubscribe_request( HandleLock(); // CURRENTLY, ONLY SUPPORT ONE DEVICE - if (GetDeviceHandleInfo( + if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family, &device_handle, &handle_info ) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); diff --git a/upnp/src/genlib/client_table/client_table.c b/upnp/src/genlib/client_table/client_table.c index 1b6dd45..b32efff 100644 --- a/upnp/src/genlib/client_table/client_table.c +++ b/upnp/src/genlib/client_table/client_table.c @@ -43,8 +43,8 @@ * Function : copy_client_subscription * * Parameters : -* client_subscription * in ; - source client subscription -* client_subscription * out ; - destination client subscription +* ClientSubscription * in ; - source client subscription +* ClientSubscription * out ; - destination client subscription * * Description : Make a copy of the client subscription data * @@ -54,8 +54,8 @@ * * Note : ************************************************************************/ -CLIENTONLY( int copy_client_subscription( client_subscription * in, - client_subscription * out ) { +CLIENTONLY( int copy_client_subscription( ClientSubscription * in, + ClientSubscription * out ) { int len = strlen( in->ActualSID ) + 1; int len1 = strlen( in->EventURL ) + 1; memcpy( out->sid, in->sid, SID_SIZE ); @@ -77,7 +77,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * Function : free_client_subscription * * Parameters : -* client_subscription * sub ; - Client subscription to be freed +* ClientSubscription * sub ; - Client subscription to be freed * * Description : Free memory allocated for client subscription data. * Remove timer thread associated with this subscription event. @@ -86,7 +86,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * * Note : ************************************************************************/ - void free_client_subscription( client_subscription * sub ) { + void free_client_subscription( ClientSubscription * sub ) { upnp_timeout * event; ThreadPoolJob tempJob; if( sub ) { if( sub->ActualSID ) free( sub->ActualSID ); if( sub->EventURL ) @@ -106,7 +106,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * Function : freeClientSubList * * Parameters : -* client_subscription * list ; Client subscription +* ClientSubscription * list ; Client subscription * * Description : Free the client subscription table. * @@ -114,8 +114,8 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * * Note : ************************************************************************/ - void freeClientSubList( client_subscription * list ) { - client_subscription * next; while( list ) { + void freeClientSubList( ClientSubscription * list ) { + ClientSubscription * next; while( list ) { free_client_subscription( list ); next = list->next; free( list ); list = next;} } @@ -124,7 +124,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * Function : RemoveClientSubClientSID * * Parameters : -* client_subscription **head ; Head of the subscription list +* ClientSubscription **head ; Head of the subscription list * const Upnp_SID sid ; Subscription ID to be mactched * * Description : Remove the client subscription matching the @@ -135,10 +135,10 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * * Note : ************************************************************************/ - void RemoveClientSubClientSID( client_subscription ** head, + void RemoveClientSubClientSID( ClientSubscription ** head, const Upnp_SID sid ) { - client_subscription * finger = ( *head ); - client_subscription * previous = NULL; while( finger ) { + ClientSubscription * finger = ( *head ); + ClientSubscription * previous = NULL; while( finger ) { if( !( strcmp( sid, finger->sid ) ) ) { if( previous ) previous->next = finger->next; @@ -156,20 +156,20 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * Function : GetClientSubClientSID * * Parameters : -* client_subscription *head ; Head of the subscription list +* ClientSubscription *head ; Head of the subscription list * const Upnp_SID sid ; Subscription ID to be matched * * Description : Return the client subscription from the client table * that matches const Upnp_SID sid subscrition id value. * -* Return : client_subscription * ; The matching subscription +* Return : ClientSubscription * ; The matching subscription * * Note : ************************************************************************/ - client_subscription * - GetClientSubClientSID( client_subscription * head, + ClientSubscription * + GetClientSubClientSID( ClientSubscription * head, const Upnp_SID sid ) { - client_subscription * next = head; while( next ) { + ClientSubscription * next = head; while( next ) { if( !strcmp( next->sid, sid ) ) break; else @@ -182,21 +182,21 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in, * Function : GetClientSubActualSID * * Parameters : -* client_subscription *head ; Head of the subscription list +* ClientSubscription *head ; Head of the subscription list * token * sid ; Subscription ID to be matched * * Description : Returns the client subscription from the client * subscription table that has the matching token * sid buffer * value. * -* Return : client_subscription * ; The matching subscription +* Return : ClientSubscription * ; The matching subscription * * Note : ************************************************************************/ - client_subscription * - GetClientSubActualSID( client_subscription * head, + ClientSubscription * + GetClientSubActualSID( ClientSubscription * head, token * sid ) { - client_subscription * next = head; while( next ) { + ClientSubscription * next = head; while( next ) { if( !memcmp( next->ActualSID, sid->buff, sid->size ) ) break; diff --git a/upnp/src/genlib/miniserver/miniserver.c b/upnp/src/genlib/miniserver/miniserver.c index 80ec29c..870b9ab 100644 --- a/upnp/src/genlib/miniserver/miniserver.c +++ b/upnp/src/genlib/miniserver/miniserver.c @@ -1,57 +1,64 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ -/************************************************************************ -* Purpose: This file implements the functionality and utility functions -* used by the Miniserver module. -************************************************************************/ #include "config.h" -#ifndef WIN32 - #include - #include - #include - #include - #include - #include -#else /* WIN32 */ - #include - typedef int socklen_t; - #define EAFNOSUPPORT 97 -#endif /* WIN32 */ +/*! + * \file + * + * \brief This file implements the functionality and utility functions + * used by the Miniserver module. + * + * The miniserver is a central point for processing all network requests. + * It is made of: + * - The SSDP sockets for discovery. + * - The HTTP listeners for description / control / eventing. + * + */ -#include "unixutil.h" + +#include "miniserver.h" + + +#include "httpreadwrite.h" #include "ithread.h" +#include "ssdplib.h" +#include "statcodes.h" +#include "ThreadPool.h" +#include "unixutil.h" /* for socklen_t, EAFNOSUPPORT */ +#include "upnpapi.h" +#include "util.h" + #include #include @@ -60,27 +67,27 @@ #include #include -#include "ssdplib.h" - -#include "util.h" -#include "miniserver.h" -#include "ThreadPool.h" -#include "httpreadwrite.h" -#include "statcodes.h" -#include "upnpapi.h" #define APPLICATION_LISTENING_PORT 49152 + struct mserv_request_t { - int connfd; // connection handle - struct in_addr foreign_ip_addr; - unsigned short foreign_ip_port; + /*! Connection handle. */ + int connfd; + struct sockaddr_storage foreign_sockaddr; }; -typedef enum { MSERV_IDLE, MSERV_RUNNING, MSERV_STOPPING } MiniServerState; + +typedef enum { + MSERV_IDLE, + MSERV_RUNNING, + MSERV_STOPPING +} MiniServerState; + unsigned short miniStopSockPort; + //////////////////////////////////////////////////////////////////////////// // module vars static MiniServerCallback gGetCallback = NULL; @@ -88,765 +95,925 @@ static MiniServerCallback gSoapCallback = NULL; static MiniServerCallback gGenaCallback = NULL; static MiniServerState gMServState = MSERV_IDLE; -/************************************************************************ - * Function: SetHTTPGetCallback - * - * Parameters : - * MiniServerCallback callback - HTTP Callback to be invoked - * - * Description: - * Set HTTP Get Callback - * - * Return: void - ************************************************************************/ -void -SetHTTPGetCallback( MiniServerCallback callback ) + +void SetHTTPGetCallback(MiniServerCallback callback) { - gGetCallback = callback; + gGetCallback = callback; } -/************************************************************************ - * Function: SetSoapCallback - * - * Parameters: - * MiniServerCallback callback - SOAP Callback to be invoked - * - * Description: - * Set SOAP Callback - * - * Return: void - ************************************************************************/ + #ifdef INCLUDE_DEVICE_APIS -void -SetSoapCallback( MiniServerCallback callback ) +void SetSoapCallback(MiniServerCallback callback) { - gSoapCallback = callback; + gSoapCallback = callback; } #endif /* INCLUDE_DEVICE_APIS */ -/************************************************************************ - * Function: SetGenaCallback - * - * Parameters: - * MiniServerCallback callback - GENA Callback to be invoked - * - * Description: - * Set GENA Callback - * - * Return: void - ************************************************************************/ -void -SetGenaCallback( MiniServerCallback callback ) +void SetGenaCallback(MiniServerCallback callback) { - gGenaCallback = callback; + gGenaCallback = callback; } -/************************************************************************ - * Function : dispatch_request + +#ifdef INTERNAL_WEB_SERVER +/*! + * \brief Based on the type pf message, appropriate callback is issued. * - * Parameters : - * IN SOCKINFO *info - Socket Information object. - * http_parser_t* hparser - HTTP parser object. - * - * Description : - * Based on the type pf message, appropriate callback is issued - * - * Return: int - * 0 - On Success - * HTTP_INTERNAL_SERVER_ERROR - Callback is NULL - ************************************************************************/ -static int -dispatch_request( IN SOCKINFO * info, - http_parser_t * hparser ) + * \return 0 on Success or HTTP_INTERNAL_SERVER_ERROR if Callback is NULL. + */ +static int dispatch_request( + /*! [in] Socket Information object. */ + IN SOCKINFO *info, + /*! [in] HTTP parser object. */ + http_parser_t *hparser) { - MiniServerCallback callback; - - switch ( hparser->msg.method ) { - //Soap Call - case SOAPMETHOD_POST: - case HTTPMETHOD_MPOST: - callback = gSoapCallback; - break; - - //Gena Call - case HTTPMETHOD_NOTIFY: - case HTTPMETHOD_SUBSCRIBE: - case HTTPMETHOD_UNSUBSCRIBE: - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "miniserver %d: got GENA msg\n", info->socket ); - callback = gGenaCallback; - break; - - //HTTP server call - case HTTPMETHOD_GET: - case HTTPMETHOD_POST: - case HTTPMETHOD_HEAD: - case HTTPMETHOD_SIMPLEGET: - callback = gGetCallback; - break; - - default: - callback = NULL; - } - - if( callback == NULL ) { - return HTTP_INTERNAL_SERVER_ERROR; - } - - callback( hparser, &hparser->msg, info ); - return 0; -} - -/************************************************************************ - * Function: handle_error - * - * Parameters: - * IN SOCKINFO *info - Socket Inforamtion Object - * int http_error_code - HTTP Error Code - * int major - Major Version Number - * int minor - Minor Version Number - * - * Description: - * Send Error Message - * - * Return: void - ************************************************************************/ -static UPNP_INLINE void -handle_error( IN SOCKINFO * info, - int http_error_code, - int major, - int minor ) -{ - http_SendStatusResponse( info, http_error_code, major, minor ); -} - -/************************************************************************ - * Function: free_handle_request_arg - * - * Parameters: - * void *args ; Request Message to be freed - * - * Description: - * Free memory assigned for handling request and unitialize socket - * functionality - * - * Return: void - ************************************************************************/ -static void -free_handle_request_arg( void *args ) -{ - struct mserv_request_t *request = ( struct mserv_request_t * )args; - - shutdown( request->connfd, SD_BOTH ); - UpnpCloseSocket( request->connfd ); - free( request ); -} - -/************************************************************************ - * Function: handle_request - * - * Parameters: - * void *args - Request Message to be handled - * - * Description: - * Receive the request and dispatch it for handling - * - * Return: void - ************************************************************************/ -static void -handle_request( void *args ) -{ - SOCKINFO info; - int http_error_code; - int ret_code; - int major = 1; - int minor = 1; - http_parser_t parser; - http_message_t *hmsg = NULL; - int timeout = HTTP_DEFAULT_TIMEOUT; - struct mserv_request_t *request = ( struct mserv_request_t * )args; - int connfd = request->connfd; - - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "miniserver %d: READING\n", connfd ); - //parser_request_init( &parser ); ////LEAK_FIX_MK - hmsg = &parser.msg; - - if( sock_init_with_ip( &info, connfd, request->foreign_ip_addr, - request->foreign_ip_port ) != UPNP_E_SUCCESS ) { - free( request ); - httpmsg_destroy( hmsg ); - return; - } - // read - ret_code = http_RecvMessage( &info, &parser, HTTPMETHOD_UNKNOWN, - &timeout, &http_error_code ); - if( ret_code != 0 ) { - goto error_handler; - } - - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "miniserver %d: PROCESSING...\n", connfd ); - // dispatch - http_error_code = dispatch_request( &info, &parser ); - if( http_error_code != 0 ) { - goto error_handler; - } - - http_error_code = 0; - - error_handler: - if( http_error_code > 0 ) { - if( hmsg ) { - major = hmsg->major_version; - minor = hmsg->minor_version; - } - handle_error( &info, http_error_code, major, minor ); - } - - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "miniserver %d: COMPLETE\n", connfd ); - sock_destroy( &info, SD_BOTH ); //should shutdown completely - - httpmsg_destroy( hmsg ); - free( request ); -} - -/************************************************************************ - * Function: schedule_request_job - * - * Parameters: - * IN int connfd - Socket Descriptor on which connection is accepted - * IN struct sockaddr_in* clientAddr - Clients Address information - * - * Description: - * Initilize the thread pool to handle a request. - * Sets priority for the job and adds the job to the thread pool - * - * Return: void - ************************************************************************/ -static UPNP_INLINE void -schedule_request_job( IN int connfd, - IN struct sockaddr_in *clientAddr ) -{ - struct mserv_request_t *request; - ThreadPoolJob job; - - request = - ( struct mserv_request_t * ) - malloc( sizeof( struct mserv_request_t ) ); - if( request == NULL ) { - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv %d: out of memory\n", connfd ); - shutdown( request->connfd, SD_BOTH ); - UpnpCloseSocket( connfd ); - return; - } - - request->connfd = connfd; - request->foreign_ip_addr = clientAddr->sin_addr; - request->foreign_ip_port = ntohs( clientAddr->sin_port ); - - TPJobInit( &job, ( start_routine ) handle_request, ( void * )request ); - TPJobSetFreeFunction( &job, free_handle_request_arg ); - TPJobSetPriority( &job, MED_PRIORITY ); - - if( ThreadPoolAdd( &gMiniServerThreadPool, &job, NULL ) != 0 ) { - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv %d: cannot schedule request\n", connfd ); - free( request ); - shutdown( connfd, SD_BOTH ); - UpnpCloseSocket( connfd ); - return; - } - -} - -/************************************************************************ - * Function: RunMiniServer - * - * Parameters: - * MiniServerSockArray *miniSock - Socket Array - * - * Description: - * Function runs the miniserver. The MiniServer accepts a - * new request and schedules a thread to handle the new request. - * Checks for socket state and invokes appropriate read and shutdown - * actions for the Miniserver and SSDP sockets - * - * Return: void - ************************************************************************/ -static void -RunMiniServer( MiniServerSockArray *miniSock ) -{ - char errorBuffer[ERROR_BUFFER_LEN]; - struct sockaddr_in clientAddr; - socklen_t clientLen; - SOCKET connectHnd; - SOCKET miniServSock = miniSock->miniServerSock; - SOCKET miniServStopSock = miniSock->miniServerStopSock; - SOCKET ssdpSock = miniSock->ssdpSock; -#ifdef INCLUDE_CLIENT_APIS - SOCKET ssdpReqSock = miniSock->ssdpReqSock; -#endif - - fd_set expSet; - fd_set rdSet; - unsigned int maxMiniSock; - int byteReceived; - char requestBuf[256]; - int ret = 0; - - maxMiniSock = max( miniServSock, miniServStopSock) ; - maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpSock) ); -#ifdef INCLUDE_CLIENT_APIS - maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpReqSock) ); -#endif - ++maxMiniSock; - - gMServState = MSERV_RUNNING; - while( TRUE ) { - FD_ZERO( &rdSet ); - FD_ZERO( &expSet ); - - FD_SET( miniServStopSock, &expSet ); - FD_SET( miniServSock, &rdSet ); - FD_SET( miniServStopSock, &rdSet ); - FD_SET( ssdpSock, &rdSet ); -#ifdef INCLUDE_CLIENT_APIS - FD_SET( ssdpReqSock, &rdSet ); -#endif - - ret = select( maxMiniSock, &rdSet, NULL, &expSet, NULL ); - if ( ret == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, - "Error in select(): %s\n", errorBuffer ); - /* Avoid 100% CPU in case of repeated error in select() */ - isleep( 1 ); - continue; - } else { - if( FD_ISSET( miniServSock, &rdSet ) ) { - clientLen = sizeof( struct sockaddr_in ); - connectHnd = accept( miniServSock, - ( struct sockaddr * )&clientAddr, &clientLen ); - if( connectHnd == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "miniserver: Error in accept(): %s\n", errorBuffer ); - continue; - } - schedule_request_job( connectHnd, &clientAddr ); - } -#ifdef INCLUDE_CLIENT_APIS - // ssdp - if( FD_ISSET( ssdpReqSock, &rdSet ) ) { - readFromSSDPSocket( ssdpReqSock ); - } -#endif - if( FD_ISSET( ssdpSock, &rdSet ) ) { - readFromSSDPSocket( ssdpSock ); - } - if( FD_ISSET( miniServStopSock, &rdSet ) ) { - clientLen = sizeof( struct sockaddr_in ); - memset( (char *)&clientAddr, 0, sizeof (struct sockaddr_in) ); - byteReceived = - recvfrom( miniServStopSock, requestBuf, 25, 0, - ( struct sockaddr * )&clientAddr, - &clientLen ); - if( byteReceived > 0 ) { - requestBuf[byteReceived] = '\0'; - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "Received response: %s From host %s \n", - requestBuf, inet_ntoa( clientAddr.sin_addr ) ); - UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__, - "Received multicast packet: \n %s\n", - requestBuf ); - if( NULL != strstr( requestBuf, "ShutDown" ) ) { - break; - } - } - } - } - } - - shutdown( miniServSock, SD_BOTH ); - UpnpCloseSocket( miniServSock ); - shutdown( miniServStopSock, SD_BOTH ); - UpnpCloseSocket( miniServStopSock ); - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); -#ifdef INCLUDE_CLIENT_APIS - shutdown( ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( ssdpReqSock ); -#endif - - free( miniSock ); - gMServState = MSERV_IDLE; - - return; -} - -/************************************************************************ - * Function: get_port - * - * Parameters: - * int sockfd - Socket Descriptor - * - * Description: - * Returns port to which socket, sockfd, is bound. - * - * Return: int - * -1 on error; check errno - * > 0 means port number - ************************************************************************/ -static int -get_port( int sockfd ) -{ - struct sockaddr_in sockinfo; - socklen_t len; - int code; - int port; - - len = sizeof( struct sockaddr_in ); - code = getsockname( sockfd, ( struct sockaddr * )&sockinfo, &len ); - if( code == -1 ) { - return -1; - } - - port = ntohs( sockinfo.sin_port ); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "sockfd = %d, .... port = %d\n", sockfd, port ); - - return port; -} - -/************************************************************************ - * Function: get_miniserver_sockets - * - * Parameters: - * MiniServerSockArray *out - Socket Array - * unsigned short listen_port - port on which the server is - * listening for incoming connections - * - * Description: - * Creates a STREAM socket, binds to INADDR_ANY and listens for - * incoming connecttions. Returns the actual port which the sockets - * sub-system returned. - * - * Also creates a DGRAM socket, binds to the loop back address and - * returns the port allocated by the socket sub-system. - * - * Return: int - * UPNP_E_OUTOF_SOCKET - Failed to create a socket - * UPNP_E_SOCKET_BIND - Bind() failed - * UPNP_E_LISTEN - Listen() failed - * UPNP_E_INTERNAL_ERROR - Port returned by the socket layer is < 0 - * UPNP_E_SUCCESS - Success - ************************************************************************/ -int -get_miniserver_sockets( MiniServerSockArray * out, - unsigned short listen_port ) -{ - char errorBuffer[ERROR_BUFFER_LEN]; - struct sockaddr_in serverAddr; - int listenfd; - int success; - unsigned short actual_port; - int reuseaddr_on = 0; - int sockError = UPNP_E_SUCCESS; - int errCode = 0; - int miniServerStopSock; - int ret = 0; - - listenfd = socket( AF_INET, SOCK_STREAM, 0 ); - if ( listenfd == -1 ) { - return UPNP_E_OUTOF_SOCKET; // error creating socket - } - // As per the IANA specifications for the use of ports by applications - // override the listen port passed in with the first available - if( listen_port < APPLICATION_LISTENING_PORT ) - listen_port = APPLICATION_LISTENING_PORT; - - memset( &serverAddr, 0, sizeof( serverAddr ) ); - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = htonl( INADDR_ANY ); - - // Getting away with implementation of re-using address:port and instead - // choosing to increment port numbers. - // Keeping the re-use address code as an optional behaviour that can be - // turned on if necessary. - // TURN ON the reuseaddr_on option to use the option. - if ( reuseaddr_on ) { - // THIS IS ALLOWS US TO BIND AGAIN IMMEDIATELY - // AFTER OUR SERVER HAS BEEN CLOSED - // THIS MAY CAUSE TCP TO BECOME LESS RELIABLE - // HOWEVER IT HAS BEEN SUGESTED FOR TCP SERVERS - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: resuseaddr set\n" ); - sockError = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&reuseaddr_on, sizeof (int) ); - if ( sockError == -1 ) { - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_SOCKET_BIND; - } - - sockError = bind( listenfd, (struct sockaddr *)&serverAddr, - sizeof (struct sockaddr_in) ); - } else { - do { - serverAddr.sin_port = htons( listen_port++ ); - sockError = bind( listenfd, (struct sockaddr *)&serverAddr, - sizeof (struct sockaddr_in) ); - if ( sockError == -1 ) { -#ifdef WIN32 - errCode = WSAGetLastError(); -#else - errCode = errno; -#endif - if( errno == EADDRINUSE ) { - errCode = 1; - } - } else - errCode = 0; - - } while ( errCode != 0 ); - } - - if ( sockError == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: Error in bind(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_SOCKET_BIND; // bind failed - } - - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: bind success\n" ); - - success = listen( listenfd, SOMAXCONN ); - if ( success == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: Error in listen(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_LISTEN; - } - - actual_port = get_port( listenfd ); - if( actual_port <= 0 ) { - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_INTERNAL_ERROR; - } - - out->miniServerPort = actual_port; - - miniServerStopSock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( miniServerStopSock == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__, - "Error in socket(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_OUTOF_SOCKET; - } - - // bind to local socket - memset( ( char * )&serverAddr, 0, sizeof( struct sockaddr_in ) ); - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); - ret = bind( miniServerStopSock, (struct sockaddr *)&serverAddr, - sizeof (serverAddr) ); - if ( ret == -1 ) { - UpnpPrintf( UPNP_CRITICAL, - MSERV, __FILE__, __LINE__, - "Error in binding localhost!!!\n" ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - shutdown( miniServerStopSock, SD_BOTH ); - UpnpCloseSocket( miniServerStopSock ); - - return UPNP_E_SOCKET_BIND; - } - - miniStopSockPort = get_port( miniServerStopSock ); - if ( miniStopSockPort <= 0 ) { - shutdown( miniServerStopSock, SD_BOTH ); - UpnpCloseSocket( miniServerStopSock ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); - - return UPNP_E_INTERNAL_ERROR; - } - - out->stopPort = miniStopSockPort; - out->miniServerSock = listenfd; - out->miniServerStopSock = miniServerStopSock; - - return UPNP_E_SUCCESS; -} - -/************************************************************************ - * Function: StartMiniServer - * - * Parameters : - * unsigned short listen_port - Port on which the server listens for - * incoming connections - * - * Description: - * Initialize the sockets functionality for the - * Miniserver. Initialize a thread pool job to run the MiniServer - * and the job to the thread pool. If listen port is 0, port is - * dynamically picked - * - * Use timer mechanism to start the MiniServer, failure to meet the - * allowed delay aborts the attempt to launch the MiniServer. - * - * Return: int - * Actual port socket is bound to - On Success - * A negative number UPNP_E_XXX - On Error - ************************************************************************/ -int -StartMiniServer( unsigned short listen_port ) -{ - int success; - int count; - int max_count = 10000; - - MiniServerSockArray *miniSocket; - ThreadPoolJob job; - - if( gMServState != MSERV_IDLE ) { - return UPNP_E_INTERNAL_ERROR; // miniserver running - } - - miniSocket = (MiniServerSockArray *) malloc( sizeof (MiniServerSockArray) ); - if( miniSocket == NULL ) { - return UPNP_E_OUTOF_MEMORY; - } - - success = get_miniserver_sockets( miniSocket, listen_port ); - if( success != UPNP_E_SUCCESS ) { - free( miniSocket ); - return success; - } - - success = get_ssdp_sockets( miniSocket ); - if( success != UPNP_E_SUCCESS ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); - shutdown( miniSocket->miniServerStopSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerStopSock ); - free( miniSocket ); - - return success; - } - - TPJobInit( &job, (start_routine)RunMiniServer, (void *)miniSocket ); - TPJobSetPriority( &job, MED_PRIORITY ); - TPJobSetFreeFunction( &job, ( free_routine ) free ); - - success = ThreadPoolAddPersistent( &gMiniServerThreadPool, &job, NULL ); - if ( success < 0 ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); - shutdown( miniSocket->miniServerStopSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerStopSock ); - shutdown( miniSocket->ssdpSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpSock ); -#ifdef INCLUDE_CLIENT_APIS - shutdown( miniSocket->ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpReqSock ); -#endif - - return UPNP_E_OUTOF_MEMORY; - } - // wait for miniserver to start - count = 0; - while ( gMServState != MSERV_RUNNING && count < max_count ) { - usleep( 50 * 1000 ); // 0.05s - count++; - } - - // taking too long to start that thread - if ( count >= max_count ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); - shutdown( miniSocket->miniServerStopSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerStopSock ); - shutdown( miniSocket->ssdpSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpSock ); -#ifdef INCLUDE_CLIENT_APIS - shutdown( miniSocket->ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpReqSock ); -#endif - - return UPNP_E_INTERNAL_ERROR; - } - - return miniSocket->miniServerPort; -} - -/************************************************************************ - * Function: StopMiniServer - * - * Parameters: - * void - * - * Description: - * Stop and Shutdown the MiniServer and free socket - * resources. - * - * Return: int - * Always returns 0 - ************************************************************************/ -int -StopMiniServer() -{ - char errorBuffer[ERROR_BUFFER_LEN]; - int socklen = sizeof( struct sockaddr_in ); - int sock; - struct sockaddr_in ssdpAddr; - char buf[256] = "ShutDown"; - int bufLen = strlen( buf ); - - if( gMServState == MSERV_RUNNING ) { - gMServState = MSERV_STOPPING; - } else { - return 0; - } - - sock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( sock == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, - "SSDP_SERVER: StopSSDPServer: Error in socket() %s\n", errorBuffer ); - return 0; - } - - while( gMServState != MSERV_IDLE ) { - ssdpAddr.sin_family = AF_INET; - ssdpAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); - ssdpAddr.sin_port = htons( miniStopSockPort ); - sendto( sock, buf, bufLen, 0, (struct sockaddr *)&ssdpAddr, socklen ); - usleep( 1000 ); - if( gMServState == MSERV_IDLE ) { - break; + MiniServerCallback callback; + + switch (hparser->msg.method) { + /* Soap Call */ + case SOAPMETHOD_POST: + case HTTPMETHOD_MPOST: + callback = gSoapCallback; + break; + + /* Gena Call */ + case HTTPMETHOD_NOTIFY: + case HTTPMETHOD_SUBSCRIBE: + case HTTPMETHOD_UNSUBSCRIBE: + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver %d: got GENA msg\n", info->socket); + callback = gGenaCallback; + break; + + /* HTTP server call */ + case HTTPMETHOD_GET: + case HTTPMETHOD_POST: + case HTTPMETHOD_HEAD: + case HTTPMETHOD_SIMPLEGET: + callback = gGetCallback; + break; + + default: + callback = NULL; } - isleep( 1 ); - } - shutdown( sock, SD_BOTH ); - UpnpCloseSocket( sock ); - return 0; + if (callback == NULL) { + return HTTP_INTERNAL_SERVER_ERROR; + } + + callback(hparser, &hparser->msg, info); + + return 0; +} + + +/*! + * \brief Send Error Message. + */ +static UPNP_INLINE void handle_error( + /*! [in] Socket Information object. */ + SOCKINFO *info, + /*! [in] HTTP Error Code. */ + int http_error_code, + /*! [in] Major Version Number. */ + int major, + /*! [in] Minor Version Number. */ + int minor) +{ + http_SendStatusResponse(info, http_error_code, major, minor); +} + + +/*! + * \brief Free memory assigned for handling request and unitialize socket + * functionality. + */ +static void free_handle_request_arg( + /*! [in] Request Message to be freed. */ + void *args) +{ + struct mserv_request_t *request = (struct mserv_request_t *)args; + + shutdown(request->connfd, SD_BOTH); + UpnpCloseSocket(request->connfd); + free(request); +} + + +/*! + * \brief Receive the request and dispatch it for handling. + */ +static void handle_request( + /*! [in] Request Message to be handled. */ + void *args) +{ + SOCKINFO info; + int http_error_code; + int ret_code; + int major = 1; + int minor = 1; + http_parser_t parser; + http_message_t *hmsg = NULL; + int timeout = HTTP_DEFAULT_TIMEOUT; + struct mserv_request_t *request = (struct mserv_request_t *)args; + int connfd = request->connfd; + + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver %d: READING\n", connfd ); + //parser_request_init( &parser ); ////LEAK_FIX_MK + hmsg = &parser.msg; + + ret_code = sock_init_with_ip( + &info, connfd, (struct sockaddr *)&request->foreign_sockaddr); + if (ret_code != UPNP_E_SUCCESS) { + free(request); + httpmsg_destroy(hmsg); + return; + } + + // read + ret_code = http_RecvMessage( + &info, &parser, HTTPMETHOD_UNKNOWN, &timeout, &http_error_code); + if (ret_code != 0) { + goto error_handler; + } + + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver %d: PROCESSING...\n", connfd); + + // dispatch + http_error_code = dispatch_request( &info, &parser ); + if (http_error_code != 0) { + goto error_handler; + } + + http_error_code = 0; + +error_handler: + if (http_error_code > 0) { + if (hmsg) { + major = hmsg->major_version; + minor = hmsg->minor_version; + } + handle_error(&info, http_error_code, major, minor); + } + + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver %d: COMPLETE\n", connfd); + sock_destroy(&info, SD_BOTH); // should shutdown completely + + httpmsg_destroy(hmsg); + free(request); +} + + +/*! + * \brief Initilize the thread pool to handle a request, sets priority for the + * job and adds the job to the thread pool. + */ +static UPNP_INLINE void schedule_request_job( + /*! [in] Socket Descriptor on which connection is accepted. */ + int connfd, + /*! [in] Clients Address information. */ + struct sockaddr *clientAddr) +{ + struct mserv_request_t *request; + ThreadPoolJob job; + + request = (struct mserv_request_t *)malloc(sizeof (struct mserv_request_t)); + if (request == NULL) { + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv %d: out of memory\n", connfd ); + shutdown( connfd, SD_BOTH ); + UpnpCloseSocket( connfd ); + return; + } + + request->connfd = connfd; + memcpy(&request->foreign_sockaddr, clientAddr, + sizeof(request->foreign_sockaddr)); + + TPJobInit(&job, (start_routine)handle_request, (void *)request); + TPJobSetFreeFunction(&job, free_handle_request_arg); + TPJobSetPriority(&job, MED_PRIORITY); + + if (ThreadPoolAdd(&gMiniServerThreadPool, &job, NULL) != 0) { + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv %d: cannot schedule request\n", connfd); + free(request); + shutdown(connfd, SD_BOTH); + UpnpCloseSocket(connfd); + return; + } +} +#endif + + +/*! + * \brief Run the miniserver. + * + * The MiniServer accepts a new request and schedules a thread to handle the + * new request. Checks for socket state and invokes appropriate read and + * shutdown actions for the Miniserver and SSDP sockets. + */ +static void RunMiniServer( + /*! [in] Socket Array. */ + MiniServerSockArray *miniSock) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + struct sockaddr_storage clientAddr; + socklen_t clientLen; + SOCKET connectHnd; + SOCKET miniServStopSock = miniSock->miniServerStopSock; + SOCKET ssdpSock4 = miniSock->ssdpSock4; + SOCKET ssdpSock6 = miniSock->ssdpSock6; +#ifdef INTERNAL_WEB_SERVER + SOCKET miniServSock4 = miniSock->miniServerSock4; + SOCKET miniServSock6 = miniSock->miniServerSock6; +#endif /* INTERNAL_WEB_SERVER */ +#ifdef INCLUDE_CLIENT_APIS + SOCKET ssdpReqSock4 = miniSock->ssdpReqSock4; + SOCKET ssdpReqSock6 = miniSock->ssdpReqSock6; +#endif /* INCLUDE_CLIENT_APIS */ + char buf_ntop[64]; + fd_set expSet; + fd_set rdSet; + unsigned int maxMiniSock = 0; + int byteReceived; + char requestBuf[256]; + int ret = 0; + +#ifdef INTERNAL_WEB_SERVER + if (miniServSock4 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, miniServSock4); + } + if (miniServSock6 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, miniServSock6); + } +#endif /* INTERNAL_WEB_SERVER */ + if (ssdpSock4 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, ssdpSock4); + } + if (ssdpSock6 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, ssdpSock6); + } +#ifdef INCLUDE_CLIENT_APIS + if (ssdpReqSock4 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, ssdpReqSock4); + } + if (ssdpReqSock6 != INVALID_SOCKET) { + maxMiniSock = max(maxMiniSock, ssdpReqSock6); + } +#endif /* INCLUDE_CLIENT_APIS */ + maxMiniSock = max(maxMiniSock, miniServStopSock); + ++maxMiniSock; + + gMServState = MSERV_RUNNING; + while(TRUE) { + FD_ZERO(&rdSet); + FD_ZERO(&expSet); + + FD_SET(miniServStopSock, &expSet); + FD_SET(miniServStopSock, &rdSet); +#ifdef INTERNAL_WEB_SERVER + if(miniServSock4 != INVALID_SOCKET) { + FD_SET(miniServSock4, &rdSet); + } + if(miniServSock6 != INVALID_SOCKET) { + FD_SET(miniServSock6, &rdSet); + } +#endif /* INTERNAL_WEB_SERVER */ + if(ssdpSock4 != INVALID_SOCKET) { + FD_SET(ssdpSock4, &rdSet); + } + if(ssdpSock6 != INVALID_SOCKET) { + FD_SET(ssdpSock6, &rdSet); + } +#ifdef INCLUDE_CLIENT_APIS + if(ssdpReqSock4 != INVALID_SOCKET) { + FD_SET(ssdpReqSock4, &rdSet); + } + if(ssdpReqSock6 != INVALID_SOCKET) { + FD_SET(ssdpReqSock6, &rdSet); + } +#endif /* INCLUDE_CLIENT_APIS */ + + ret = select(maxMiniSock, &rdSet, NULL, &expSet, NULL); + if (ret == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in select(): %s\n", errorBuffer); + /* Avoid 100% CPU in case of repeated error in select() */ + isleep(1); + continue; + } else { +#ifdef INTERNAL_WEB_SERVER + if (miniServSock6 != INVALID_SOCKET && + FD_ISSET(miniServSock6, &rdSet)) { + clientLen = sizeof( clientAddr ); + connectHnd = accept(miniServSock6, + (struct sockaddr *)&clientAddr, &clientLen); + if (connectHnd == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver: Error in accept(): %s\n", + errorBuffer); + continue; + } + schedule_request_job( + connectHnd, (struct sockaddr *)&clientAddr); + } + if (miniServSock4 != INVALID_SOCKET && + FD_ISSET(miniServSock4, &rdSet)) { + clientLen = sizeof(clientAddr); + connectHnd = accept(miniServSock4, + (struct sockaddr *)&clientAddr, &clientLen); + if (connectHnd == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver: Error in accept(): %s\n", + errorBuffer); + continue; + } + schedule_request_job( + connectHnd, (struct sockaddr *)&clientAddr); + } +#endif /* INTERNAL_WEB_SERVER */ +#ifdef INCLUDE_CLIENT_APIS + // ssdp + if (ssdpReqSock6 != INVALID_SOCKET && + FD_ISSET(ssdpReqSock6, &rdSet)) { + readFromSSDPSocket(ssdpReqSock6); + } + if (ssdpReqSock4 != INVALID_SOCKET && + FD_ISSET( ssdpReqSock4, &rdSet)) { + readFromSSDPSocket(ssdpReqSock4); + } +#endif /* INCLUDE_CLIENT_APIS */ + if (ssdpSock6 != INVALID_SOCKET && + FD_ISSET(ssdpSock6, &rdSet)) { + readFromSSDPSocket(ssdpSock6); + } + if (ssdpSock4 != INVALID_SOCKET && + FD_ISSET(ssdpSock4, &rdSet)) { + readFromSSDPSocket(ssdpSock4); + } + if (FD_ISSET( miniServStopSock, &rdSet)) { + clientLen = sizeof(clientAddr); + memset((char *)&clientAddr, 0, sizeof(clientAddr)); + byteReceived = recvfrom(miniServStopSock, requestBuf, + 25, 0, (struct sockaddr *)&clientAddr, &clientLen); + if (byteReceived > 0) { + requestBuf[byteReceived] = '\0'; + inet_ntop(AF_INET, + &((struct sockaddr_in*)&clientAddr)->sin_addr, + buf_ntop, sizeof(buf_ntop)); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "Received response: %s From host %s \n", + requestBuf, buf_ntop ); + UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__, + "Received multicast packet: \n %s\n", + requestBuf); + if (NULL != strstr(requestBuf, "ShutDown")) { + break; + } + } + } + } + } + +#ifdef INTERNAL_WEB_SERVER + shutdown(miniServSock4, SD_BOTH); + UpnpCloseSocket(miniServSock4); + shutdown(miniServSock6, SD_BOTH); + UpnpCloseSocket(miniServSock6); +#endif /* INTERNAL_WEB_SERVER */ + shutdown(miniServStopSock, SD_BOTH); + UpnpCloseSocket(miniServStopSock); + shutdown(ssdpSock4, SD_BOTH); + UpnpCloseSocket(ssdpSock4); + shutdown(ssdpSock6, SD_BOTH); + UpnpCloseSocket(ssdpSock6); +#ifdef INCLUDE_CLIENT_APIS + shutdown(ssdpReqSock4, SD_BOTH); + UpnpCloseSocket(ssdpReqSock4); + shutdown(ssdpReqSock6, SD_BOTH); + UpnpCloseSocket(ssdpReqSock6); +#endif /* INCLUDE_CLIENT_APIS */ + + free(miniSock); + gMServState = MSERV_IDLE; + + return; +} + + +/*! + * \brief Returns port to which socket, sockfd, is bound. + * + * \return -1 on error; check errno, otherwise > 0 means port number. + */ +static int get_port( + /*! [in] Socket descriptor. */ + int sockfd) +{ + struct sockaddr_storage sockinfo; + socklen_t len; + int code; + int port = 0; + + len = sizeof(sockinfo); + code = getsockname(sockfd, (struct sockaddr *)&sockinfo, &len); + if (code == -1) { + return -1; + } + + if (sockinfo.ss_family == AF_INET) { + port = ntohs(((struct sockaddr_in*)&sockinfo)->sin_port); + } else if(sockinfo.ss_family == AF_INET6) { + port = ntohs(((struct sockaddr_in6*)&sockinfo)->sin6_port); + } + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "sockfd = %d, .... port = %d\n", sockfd, port); + + return port; +} + + +#ifdef INTERNAL_WEB_SERVER +/*! + * \brief Creates a STREAM socket, binds to INADDR_ANY and listens for + * incoming connecttions. Returns the actual port which the sockets + * sub-system returned. + * + * Also creates a DGRAM socket, binds to the loop back address and + * returns the port allocated by the socket sub-system. + * + * \return + * \li UPNP_E_OUTOF_SOCKET: Failed to create a socket. + * \li UPNP_E_SOCKET_BIND: Bind() failed. + * \li UPNP_E_LISTEN: Listen() failed. + * \li UPNP_E_INTERNAL_ERROR: Port returned by the socket layer is < 0. + * \li UPNP_E_SUCCESS: Success. + */ +static int get_miniserver_sockets( + /*! [in] Socket Array. */ + MiniServerSockArray *out, + /*! [in] port on which the server is listening for incoming IPv4 connections. */ + unsigned short listen_port4, + /*! [in] port on which the server is listening for incoming IPv6 connections. */ + unsigned short listen_port6) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + struct sockaddr_storage __ss_v4; + struct sockaddr_storage __ss_v6; + struct sockaddr_in* serverAddr4 = (struct sockaddr_in*)&__ss_v4; + struct sockaddr_in6* serverAddr6 = (struct sockaddr_in6*)&__ss_v6; + SOCKET listenfd4, listenfd6; + int ret_code; + unsigned short actual_port4, actual_port6; + int reuseaddr_on = 0; + int sockError = UPNP_E_SUCCESS; + int errCode = 0; + + // Create listen socket for IPv4/IPv6. An error here may indicate + // that we don't have an IPv4/IPv6 stack. + listenfd4 = socket(AF_INET, SOCK_STREAM, 0); + listenfd6 = socket(AF_INET6, SOCK_STREAM, 0); + if (listenfd4 == INVALID_SOCKET && listenfd6 == INVALID_SOCKET) { + return UPNP_E_OUTOF_SOCKET; + } + + // As per the IANA specifications for the use of ports by applications + // override the listen port passed in with the first available + if (listen_port4 < APPLICATION_LISTENING_PORT) { + listen_port4 = APPLICATION_LISTENING_PORT; + } + if (listen_port6 < APPLICATION_LISTENING_PORT) { + listen_port6 = APPLICATION_LISTENING_PORT; + } + + memset(&__ss_v4, 0, sizeof (__ss_v4)); + serverAddr4->sin_family = AF_INET; + serverAddr4->sin_addr.s_addr = htonl(INADDR_ANY); + + memset(&__ss_v6, 0, sizeof (__ss_v6)); + serverAddr6->sin6_family = AF_INET6; + serverAddr6->sin6_addr = in6addr_any; + + // Getting away with implementation of re-using address:port and instead + // choosing to increment port numbers. + // Keeping the re-use address code as an optional behaviour that can be + // turned on if necessary. + // TURN ON the reuseaddr_on option to use the option. + if (reuseaddr_on) { + // THIS IS ALLOWS US TO BIND AGAIN IMMEDIATELY + // AFTER OUR SERVER HAS BEEN CLOSED + // THIS MAY CAUSE TCP TO BECOME LESS RELIABLE + // HOWEVER IT HAS BEEN SUGESTED FOR TCP SERVERS + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: resuseaddr set\n"); + + if (listenfd4 != INVALID_SOCKET) { + sockError = setsockopt(listenfd4, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuseaddr_on, sizeof (int)); + if (sockError == -1) { + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_SOCKET_BIND; + } + + sockError = bind(listenfd4, (struct sockaddr *)&__ss_v4, + sizeof (__ss_v4)); + if (sockError == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv4 bind(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + /* Bind failed */ + return UPNP_E_SOCKET_BIND; + } + } + + if(listenfd6 != INVALID_SOCKET) { + sockError = setsockopt(listenfd6, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuseaddr_on, sizeof (int)); + if (sockError == -1) { + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_SOCKET_BIND; + } + + sockError = bind(listenfd6, (struct sockaddr *)&__ss_v6, sizeof (__ss_v6)); + if (sockError == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv6 bind(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + /* Bind failed */ + return UPNP_E_SOCKET_BIND; + } + } + } else { + if (listenfd4 != INVALID_SOCKET) { + unsigned short orig_listen_port4 = listen_port4; + do { + serverAddr4->sin_port = htons(listen_port4++); + sockError = bind(listenfd4, (struct sockaddr *)serverAddr4, sizeof(*serverAddr4)); + if (sockError == -1) { +#ifdef WIN32 + errCode = WSAGetLastError(); +#else + errCode = errno; +#endif + if (errno == EADDRINUSE) { + errCode = 1; + } + } else { + errCode = 0; + } + } while ( errCode != 0 && (listen_port4 >= orig_listen_port4) ); + + if (sockError == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv4 bind(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_SOCKET_BIND; // bind failed + } + } + + if (listenfd6 != INVALID_SOCKET) { + unsigned short orig_listen_port6 = listen_port6; + do { + serverAddr6->sin6_port = htons(listen_port6++); + sockError = bind(listenfd6, (struct sockaddr *)serverAddr6, sizeof(*serverAddr6)); + if (sockError == -1) { +#ifdef WIN32 + errCode = WSAGetLastError(); +#else + errCode = errno; +#endif + if (errno == EADDRINUSE) { + errCode = 1; + } + } else { + errCode = 0; + } + } while (errCode != 0 && (listen_port6 >= orig_listen_port6)); + + if (sockError == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv6 bind(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + /* Bind failied */ + return UPNP_E_SOCKET_BIND; + } + } + } + + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: bind successful\n" ); + + if (listenfd4 != INVALID_SOCKET) { + ret_code = listen(listenfd4, SOMAXCONN); + if (ret_code == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv start: Error in IPv4 listen(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_LISTEN; + } + + actual_port4 = get_port(listenfd4); + if (actual_port4 <= 0) { + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_INTERNAL_ERROR; + } + + out->miniServerPort4 = actual_port4; + } + + if (listenfd6 != INVALID_SOCKET) { + ret_code = listen(listenfd6, SOMAXCONN); + if (ret_code == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv start: Error in IPv6 listen(): %s\n", + errorBuffer); + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_LISTEN; + } + + actual_port6 = get_port(listenfd6); + if (actual_port6 <= 0) { + shutdown(listenfd4, SD_BOTH); + UpnpCloseSocket(listenfd4); + shutdown(listenfd6, SD_BOTH); + UpnpCloseSocket(listenfd6); + return UPNP_E_INTERNAL_ERROR; + } + + out->miniServerPort6 = actual_port6; + } + + out->miniServerSock4 = listenfd4; + out->miniServerSock6 = listenfd6; + + return UPNP_E_SUCCESS; +} +#endif /* INTERNAL_WEB_SERVER */ + + +/*! + * \brief Creates the miniserver STOP socket. This socket is created and + * listened on to know when it is time to stop the Miniserver. + * + * \return + * \li UPNP_E_OUTOF_SOCKET: Failed to create a socket. + * \li UPNP_E_SOCKET_BIND: Bind() failed. + * \li UPNP_E_INTERNAL_ERROR: Port returned by the socket layer is < 0. + * \li UPNP_E_SUCCESS: Success. + */ +static int get_miniserver_stopsock( + /*! [in] Miniserver Socket Array. */ + MiniServerSockArray *out) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + struct sockaddr_in stop_sockaddr; + int miniServerStopSock = 0; + int ret = 0; + + miniServerStopSock = socket(AF_INET, SOCK_DGRAM, 0); + if (miniServerStopSock == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_CRITICAL, MSERV, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer); + return UPNP_E_OUTOF_SOCKET; + } + + // bind to local socket + memset(&stop_sockaddr, 0, sizeof (stop_sockaddr)); + stop_sockaddr.sin_family = AF_INET; + stop_sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + ret = bind(miniServerStopSock, (struct sockaddr *)&stop_sockaddr, + sizeof(stop_sockaddr)); + if (ret == -1) { + UpnpPrintf(UPNP_CRITICAL, + MSERV, __FILE__, __LINE__, + "Error in binding localhost!!!\n"); + shutdown(miniServerStopSock, SD_BOTH); + UpnpCloseSocket(miniServerStopSock); + return UPNP_E_SOCKET_BIND; + } + + miniStopSockPort = get_port( miniServerStopSock ); + if (miniStopSockPort <= 0) { + shutdown(miniServerStopSock, SD_BOTH); + UpnpCloseSocket(miniServerStopSock); + return UPNP_E_INTERNAL_ERROR; + } + + out->miniServerStopSock = miniServerStopSock; + out->stopPort = miniStopSockPort; + + return UPNP_E_SUCCESS; +} + + +int StartMiniServer( + /*! [in,out] Port on which the server listens for incoming IPv4 connections. */ + unsigned short *listen_port4, + /*! [in,out] Port on which the server listens for incoming IPv6 connections. */ + unsigned short *listen_port6) +{ + int ret_code; + int count; + int max_count = 10000; + + MiniServerSockArray *miniSocket; + ThreadPoolJob job; + + if (gMServState != MSERV_IDLE) { + return UPNP_E_INTERNAL_ERROR; // miniserver running + } + + miniSocket = (MiniServerSockArray *)malloc(sizeof (MiniServerSockArray)); + if (miniSocket == NULL) { + return UPNP_E_OUTOF_MEMORY; + } + memset(miniSocket, 0, sizeof (*miniSocket)); + +#ifdef INTERNAL_WEB_SERVER + // V4 and V6 http listeners. + ret_code = get_miniserver_sockets(miniSocket, *listen_port4, *listen_port6); + if (ret_code != UPNP_E_SUCCESS) { + free(miniSocket); + return ret_code; + } +#endif + + // Stop socket (To end miniserver processing). + ret_code = get_miniserver_stopsock(miniSocket); + if (ret_code != UPNP_E_SUCCESS) { +#ifdef INTERNAL_WEB_SERVER + shutdown(miniSocket->miniServerSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock4); + shutdown(miniSocket->miniServerSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock6); +#endif + free(miniSocket); + return ret_code; + } + + // SSDP socket for discovery / advertising. + ret_code = get_ssdp_sockets(miniSocket); + if (ret_code != UPNP_E_SUCCESS) { +#ifdef INTERNAL_WEB_SERVER + shutdown(miniSocket->miniServerSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock4); + shutdown(miniSocket->miniServerSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock6); +#endif + shutdown(miniSocket->miniServerStopSock, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerStopSock); + free(miniSocket); + return ret_code; + } + + TPJobInit(&job, (start_routine)RunMiniServer, (void *)miniSocket); + TPJobSetPriority(&job, MED_PRIORITY); + TPJobSetFreeFunction(&job, (free_routine)free); + ret_code = ThreadPoolAddPersistent(&gMiniServerThreadPool, &job, NULL); + if (ret_code < 0) { +#ifdef INTERNAL_WEB_SERVER + shutdown(miniSocket->miniServerSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock4); + shutdown(miniSocket->miniServerSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock6); +#endif + shutdown(miniSocket->miniServerStopSock, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerStopSock); + shutdown(miniSocket->ssdpSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpSock4); + shutdown(miniSocket->ssdpSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpSock6); +#ifdef INCLUDE_CLIENT_APIS + shutdown(miniSocket->ssdpReqSock4, SD_BOTH ); + UpnpCloseSocket(miniSocket->ssdpReqSock4 ); + shutdown(miniSocket->ssdpReqSock6, SD_BOTH ); + UpnpCloseSocket(miniSocket->ssdpReqSock6 ); +#endif + return UPNP_E_OUTOF_MEMORY; + } + // wait for miniserver to start + count = 0; + while (gMServState != MSERV_RUNNING && count < max_count) { + usleep(50 * 1000); // 0.05s + count++; + } + + // taking too long to start that thread + if (count >= max_count) { +#ifdef INTERNAL_WEB_SERVER + shutdown(miniSocket->miniServerSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock4); + shutdown(miniSocket->miniServerSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerSock6); +#endif + shutdown(miniSocket->miniServerStopSock, SD_BOTH); + UpnpCloseSocket(miniSocket->miniServerStopSock); + shutdown(miniSocket->ssdpSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpSock4); + shutdown(miniSocket->ssdpSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpSock6); +#ifdef INCLUDE_CLIENT_APIS + shutdown(miniSocket->ssdpReqSock4, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpReqSock4); + shutdown(miniSocket->ssdpReqSock6, SD_BOTH); + UpnpCloseSocket(miniSocket->ssdpReqSock6); +#endif + return UPNP_E_INTERNAL_ERROR; + } +#ifdef INTERNAL_WEB_SERVER + *listen_port4 = miniSocket->miniServerPort4; + *listen_port6 = miniSocket->miniServerPort6; +#endif + + return UPNP_E_SUCCESS; +} + + +int StopMiniServer() +{ + char errorBuffer[ERROR_BUFFER_LEN]; + int socklen = sizeof (struct sockaddr_in); + SOCKET sock; + struct sockaddr_in ssdpAddr; + char buf[256] = "ShutDown"; + int bufLen = strlen(buf); + + if(gMServState == MSERV_RUNNING) { + gMServState = MSERV_STOPPING; + } else { + return 0; + } + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, + "SSDP_SERVER: StopSSDPServer: Error in socket() %s\n", + errorBuffer); + return 0; + } + + while(gMServState != MSERV_IDLE) { + ssdpAddr.sin_family = AF_INET; + ssdpAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + ssdpAddr.sin_port = htons(miniStopSockPort); + sendto(sock, buf, bufLen, 0, (struct sockaddr *)&ssdpAddr, + socklen); + usleep(1000); + if (gMServState == MSERV_IDLE) { + break; + } + isleep(1); + } + shutdown(sock, SD_BOTH); + UpnpCloseSocket(sock); + + return 0; } diff --git a/upnp/src/genlib/net/http/webserver.c b/upnp/src/genlib/net/http/webserver.c index d775c7f..56e69bf 100644 --- a/upnp/src/genlib/net/http/webserver.c +++ b/upnp/src/genlib/net/http/webserver.c @@ -1,33 +1,34 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + /****************************************************************************** * Purpose: This file defines the Web Server and has functions to carry out @@ -52,18 +53,28 @@ #include "upnp.h" #include "upnpapi.h" #include "util.h" +#include "VirtualDir.h" #include #include -#ifndef UPNP_USE_BCBPP +#include + + +#ifdef UPNP_USE_BCBPP + /* Do not #include */ + /* Do not #include */ +#else #include #include -#endif -#ifndef WIN32 +#endif /* !UPNP_USE_BCBPP */ + + +#ifdef WIN32 + /* Do not #include */ +#else #include #endif -#include /* @@ -301,8 +312,8 @@ get_content_type( IN const char *filename, OUT DOMString * content_type ) { const char *extension; - const char *type, - *subtype; + const char *type; + const char *subtype; xboolean ctype_found = FALSE; char *temp = NULL; int length = 0; @@ -311,13 +322,13 @@ get_content_type( IN const char *filename, // get ext extension = strrchr( filename, '.' ); - if( extension != NULL ) { + if (extension != NULL) { if( search_extension( extension + 1, &type, &subtype ) == 0 ) { ctype_found = TRUE; } } - if( !ctype_found ) { + if (!ctype_found) { // unknown content type type = gMediaTypes[APPLICATION_INDEX]; subtype = "octet-stream"; @@ -325,15 +336,13 @@ get_content_type( IN const char *filename, length = strlen( type ) + strlen( "/" ) + strlen( subtype ) + 1; temp = ( char * )malloc( length ); - - if( !temp ) { + if (!temp) { return UPNP_E_OUTOF_MEMORY; } - sprintf( temp, "%s/%s", type, subtype ); ( *content_type ) = ixmlCloneDOMString( temp ); - free( temp ); + free(temp); if( !content_type ) { return UPNP_E_OUTOF_MEMORY; @@ -521,40 +530,33 @@ web_server_set_alias( IN const char *alias_name, return UPNP_E_OUTOF_MEMORY; } -/************************************************************************ - * Function: web_server_init - * - * Parameters: - * none - * - * Description: Initilialize the different documents. Initialize the - * memory for root directory for web server. Call to initialize global - * XML document. Sets bWebServerState to WEB_SERVER_ENABLED - * - * Returns: - * 0 - OK - * UPNP_E_OUTOF_MEMORY: note: alias_content is not freed here - ************************************************************************/ -int -web_server_init( void ) + +int web_server_init() { - int ret_code; + int ret = 0; + if (bWebServerState == WEB_SERVER_DISABLED) { + // decode media list + media_list_init(); + membuffer_init(&gDocumentRootDir); + glob_alias_init(); + pVirtualDirList = NULL; - if( bWebServerState == WEB_SERVER_DISABLED ) { - media_list_init(); // decode media list - membuffer_init( &gDocumentRootDir ); - glob_alias_init(); + // Initialize callbacks + virtualDirCallback.get_info = NULL; + virtualDirCallback.open = NULL; + virtualDirCallback.read = NULL; + virtualDirCallback.write = NULL; + virtualDirCallback.seek = NULL; + virtualDirCallback.close = NULL; - pVirtualDirList = NULL; + if (ithread_mutex_init(&gWebMutex, NULL) == -1) { + ret = UPNP_E_OUTOF_MEMORY; + } else { + bWebServerState = WEB_SERVER_ENABLED; + } + } - ret_code = ithread_mutex_init( &gWebMutex, NULL ); - if( ret_code == -1 ) { - return UPNP_E_OUTOF_MEMORY; - } - bWebServerState = WEB_SERVER_ENABLED; - } - - return 0; + return ret; } /************************************************************************ @@ -593,7 +595,7 @@ web_server_destroy( void ) * Function: get_file_info * * Parameters: - * IN const char* filename ; Filename having the description document + * IN const char *filename; Filename having the description document * OUT struct File_Info * info ; File information object having file * attributes such as filelength, when was the file last * modified, whether a file or a directory and whether the @@ -610,45 +612,45 @@ static int get_file_info( IN const char *filename, OUT struct File_Info *info ) { - int code; - struct stat s; - FILE *fp; - int rc = 0; + int code; + struct stat s; + FILE *fp; + int rc = 0; info->content_type = NULL; - code = stat( filename, &s ); - if( code == -1 ) { - return -1; - } + code = stat(filename, &s); + if (code == -1) { + return -1; + } - if( S_ISDIR( s.st_mode ) ) { + if (S_ISDIR(s.st_mode)) { info->is_directory = TRUE; - } else if( S_ISREG( s.st_mode ) ) { + } else if (S_ISREG(s.st_mode)) { info->is_directory = FALSE; - } else { - return -1; - } + } else { + return -1; + } - // check readable - fp = fopen( filename, "r" ); + // check readable + fp = fopen(filename, "r"); info->is_readable = ( fp != NULL ); - if( fp ) { - fclose( fp ); - } + if (fp) { + fclose(fp); + } info->file_length = s.st_size; info->last_modified = s.st_mtime; rc = get_content_type( filename, &info->content_type ); - UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, - "file info: %s, length: %lld, last_mod=%s readable=%d\n", + UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, + "file info: %s, length: %lld, last_mod=%s readable=%d\n", filename, (long long)info->file_length, asctime( gmtime( &info->last_modified ) ), info->is_readable ); - return rc; + return rc; } /************************************************************************ @@ -690,7 +692,7 @@ web_server_set_root_dir( IN const char *root_dir ) * Function: get_alias * * Parameters: - * IN const char* request_file ; request file passed in to be compared with + * IN const char *request_file; request file passed in to be compared with * OUT struct xml_alias_t* alias ; xml alias object which has a file name * stored * OUT struct File_Info * info ; File information object which will be @@ -706,21 +708,19 @@ web_server_set_root_dir( IN const char *root_dir ) ************************************************************************/ static UPNP_INLINE xboolean get_alias( IN const char *request_file, - OUT struct xml_alias_t *alias, + OUT struct xml_alias_t *alias, OUT struct File_Info *info ) { - int cmp; - - cmp = strcmp( alias->name.buf, request_file ); - if( cmp == 0 ) { - // fill up info + int cmp = strcmp(alias->name.buf, request_file); + if (cmp == 0) { + // fill up info info->file_length = alias->doc.length; info->is_readable = TRUE; info->is_directory = FALSE; info->last_modified = alias->last_modified; - } + } - return cmp == 0; + return cmp == 0; } /************************************************************************ @@ -1209,11 +1209,11 @@ process_request( IN http_message_t * req, xboolean using_virtual_dir; uri_type *url; char *temp_str; - int resp_major, - resp_minor; + int resp_major; + int resp_minor; xboolean alias_grabbed; size_t dummy; - struct UpnpVirtualDirCallbacks *pVirtualDirCallback; + const char *extra_headers = NULL; print_http_headers( req ); @@ -1265,15 +1265,13 @@ process_request( IN http_message_t * req, } } else { - // - // try using alias - // - if( is_valid_alias( &gAliasDoc ) ) { - alias_grab( alias ); + /* try using alias */ + if (is_valid_alias(&gAliasDoc)) { + alias_grab(alias); alias_grabbed = TRUE; using_alias = get_alias( request_doc, alias, &finfo ); - if( using_alias == TRUE ) { + if (using_alias == TRUE) { finfo.content_type = ixmlCloneDOMString( "text/xml" ); if( finfo.content_type == NULL ) { @@ -1283,29 +1281,26 @@ process_request( IN http_message_t * req, } } - if( using_virtual_dir ) { - if( req->method != HTTPMETHOD_POST ) { + if (using_virtual_dir) { + if (req->method != HTTPMETHOD_POST) { // get file info - pVirtualDirCallback = &virtualDirCallback; - if( pVirtualDirCallback->get_info( filename->buf, &finfo ) != - 0 ) { + if (virtualDirCallback.get_info(filename->buf, &finfo) != 0) { err_code = HTTP_NOT_FOUND; goto error_handler; } // try index.html if req is a dir if( finfo.is_directory ) { - if( filename->buf[filename->length - 1] == '/' ) { + if (filename->buf[filename->length - 1] == '/') { temp_str = "index.html"; } else { temp_str = "/index.html"; } - if( membuffer_append_str( filename, temp_str ) != 0 ) { + if ( membuffer_append_str(filename, temp_str) != 0) { goto error_handler; } // get info - if( ( pVirtualDirCallback-> - get_info( filename->buf, &finfo ) != UPNP_E_SUCCESS ) - || finfo.is_directory ) { + if( (virtualDirCallback.get_info(filename->buf, &finfo ) != UPNP_E_SUCCESS ) || + finfo.is_directory) { err_code = HTTP_NOT_FOUND; goto error_handler; } @@ -1321,7 +1316,7 @@ process_request( IN http_message_t * req, // goto error_handler; // } } - } else if( !using_alias ) { + } else if (!using_alias) { if( gDocumentRootDir.length == 0 ) { goto error_handler; } @@ -1392,34 +1387,40 @@ process_request( IN http_message_t * req, goto error_handler; } + /*extra_headers = UpnpFileInfo_get_ExtraHeaders(finfo);*/ + if (!extra_headers) { + extra_headers = ""; + } + if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "T" "GKD" "s" "tcS" "XcCc", - HTTP_PARTIAL_CONTENT, // status code + "R" "T" "GKD" "s" "tcS" "Xc" "sCc", + HTTP_PARTIAL_CONTENT, // status code finfo.content_type, // content type - RespInstr, // range info + RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) { - // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "N" "T" "GD" "s" "tcS" "XcCc", - HTTP_PARTIAL_CONTENT, // status code - RespInstr->ReadSendSize, // content length + "R" "N" "T" "GD" "s" "tcS" "Xc" "sCc", + HTTP_PARTIAL_CONTENT, // status code + RespInstr->ReadSendSize, // content length finfo.content_type, // content type - RespInstr, // range info + RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } @@ -1428,12 +1429,13 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "RK" "TD" "s" "tcS" "XcCc", - HTTP_OK, // status code + "RK" "TD" "s" "tcS" "Xc" "sCc", + HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } @@ -1443,13 +1445,14 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "N" "TD" "s" "tcS" "XcCc", - HTTP_OK, // status code - RespInstr->ReadSendSize, // content length + "R" "N" "TD" "s" "tcS" "Xc" "sCc", + HTTP_OK, // status code + RespInstr->ReadSendSize, // content length finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } else { @@ -1457,12 +1460,13 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "TD" "s" "tcS" "XcCc", - HTTP_OK, // status code + "R" "TD" "s" "tcS" "b" "Xc" "sCc", + HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } @@ -1488,11 +1492,11 @@ process_request( IN http_message_t * req, err_code = UPNP_E_SUCCESS; - error_handler: - free( request_doc ); +error_handler: + free(request_doc); ixmlFreeDOMString( finfo.content_type ); - if( err_code != UPNP_E_SUCCESS && alias_grabbed ) { - alias_release( alias ); + if (err_code != UPNP_E_SUCCESS && alias_grabbed) { + alias_release(alias); } return err_code; @@ -1517,8 +1521,8 @@ process_request( IN http_message_t * req, * HTTP_OK ************************************************************************/ int -http_RecvPostMessage( http_parser_t * parser, - IN SOCKINFO * info, +http_RecvPostMessage( http_parser_t *parser, + IN SOCKINFO *info, char *filename, struct SendInstruction *Instr ) { @@ -1535,12 +1539,10 @@ http_RecvPostMessage( http_parser_t * parser, int ret_code = 0; if( Instr && Instr->IsVirtualFile ) { - Fp = (virtualDirCallback.open)( filename, UPNP_WRITE ); if( Fp == NULL ) { return HTTP_INTERNAL_SERVER_ERROR; } - } else { Fp = fopen( filename, "wb" ); if( Fp == NULL ) { diff --git a/upnp/src/genlib/net/sock.c b/upnp/src/genlib/net/sock.c index 1af6ee8..90bd514 100644 --- a/upnp/src/genlib/net/sock.c +++ b/upnp/src/genlib/net/sock.c @@ -1,60 +1,58 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + /************************************************************************ -* Purpose: This file implements the sockets functionality -************************************************************************/ + * Purpose: This file implements the sockets functionality + ************************************************************************/ + #include "config.h" + + +#include "sock.h" + + +#include "unixutil.h" /* for socklen_t, EAFNOSUPPORT */ +#include "upnp.h" + + #include #include #include #include -#include "sock.h" -#include "upnp.h" -#ifndef WIN32 - #include - #include - #include - #include - #include - #include -#else - #include -#endif -#include "unixutil.h" #ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 + #define MSG_NOSIGNAL 0 #endif /************************************************************************ @@ -62,7 +60,7 @@ * * Parameters : * OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor +* IN SOCKET sockfd ; Socket Descriptor * * Description : Assign the passed in socket descriptor to socket * descriptor in the SOCKINFO structure. @@ -76,7 +74,7 @@ ************************************************************************/ int sock_init( OUT SOCKINFO * info, - IN int sockfd ) + IN SOCKET sockfd ) { assert( info ); @@ -91,10 +89,9 @@ sock_init( OUT SOCKINFO * info, * Function : sock_init_with_ip * * Parameters : -* OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor -* IN struct in_addr foreign_ip_addr ; Remote IP Address -* IN unsigned short foreign_ip_port ; Remote Port number +* OUT SOCKINFO* info ; Socket Information Object +* IN SOCKET sockfd ; Socket Descriptor +* IN struct sockaddr* foreign_sockaddr; remote socket address. * * Description : Calls the sock_init function and assigns the passed in * IP address and port to the IP address and port in the SOCKINFO @@ -109,9 +106,8 @@ sock_init( OUT SOCKINFO * info, ************************************************************************/ int sock_init_with_ip( OUT SOCKINFO * info, - IN int sockfd, - IN struct in_addr foreign_ip_addr, - IN unsigned short foreign_ip_port ) + IN SOCKET sockfd, + IN struct sockaddr* foreign_sockaddr ) { int ret; @@ -120,8 +116,8 @@ sock_init_with_ip( OUT SOCKINFO * info, return ret; } - info->foreign_ip_addr = foreign_ip_addr; - info->foreign_ip_port = foreign_ip_port; + memcpy( &info->foreign_sockaddr, foreign_sockaddr, + sizeof( info->foreign_sockaddr) ); return UPNP_E_SUCCESS; } @@ -149,9 +145,11 @@ int sock_destroy( INOUT SOCKINFO * info, int ShutdownMethod ) { - shutdown( info->socket, ShutdownMethod ); - if( UpnpCloseSocket( info->socket ) == -1 ) { - return UPNP_E_SOCKET_ERROR; + if( info->socket != INVALID_SOCKET ) { + shutdown( info->socket, ShutdownMethod ); + if( UpnpCloseSocket( info->socket ) == -1 ) { + return UPNP_E_SOCKET_ERROR; + } } return UPNP_E_SUCCESS; @@ -190,7 +188,7 @@ sock_read_write( IN SOCKINFO * info, struct timeval timeout; int numBytes; time_t start_time = time( NULL ); - int sockfd = info->socket; + SOCKET sockfd = info->socket; long bytes_sent = 0, byte_left = 0, num_written; @@ -202,9 +200,9 @@ sock_read_write( IN SOCKINFO * info, FD_ZERO( &readSet ); FD_ZERO( &writeSet ); if( bRead ) { - FD_SET( ( unsigned )sockfd, &readSet ); + FD_SET( sockfd, &readSet ); } else { - FD_SET( ( unsigned )sockfd, &writeSet ); + FD_SET( sockfd, &writeSet ); } timeout.tv_sec = *timeoutSecs; diff --git a/upnp/src/inc/VirtualDir.h b/upnp/src/inc/VirtualDir.h new file mode 100644 index 0000000..c01524b --- /dev/null +++ b/upnp/src/inc/VirtualDir.h @@ -0,0 +1,69 @@ + + +#ifndef VIRTUALDIR_H +#define VIRTUALDIR_H + + +/** The \b VirtualDirCallbacks structure contains the pointers to + * file-related callback functions a device application can register to + * virtualize URLs. + */ +struct VirtualDirCallbacks +{ + /** Called by the web server to query information on a file. The callback + * should return 0 on success or -1 on an error. */ + VDCallback_GetInfo get_info; + + /** Called by the web server to open a file. The callback should return + * a valid handle if the file can be opened. Otherwise, it should return + * \c NULL to signify an error. */ + VDCallback_Open open; + + /** Called by the web server to perform a sequential read from an open + * file. The callback should copy \b buflen bytes from the file into + * the buffer. + * @return An integer representing one of the following: + * \li 0: The file contains no more data (EOF). + * \li > 0: A successful read of the number of bytes in the + * return code. + * \li < 0: An error occurred reading the file. + */ + VDCallback_Read read; + + /** Called by the web server to perform a sequential write to an open + * file. The callback should write \b buflen bytes into the file from + * the buffer. It should return the actual number of bytes written, + * which might be less than \b buflen in the case of a write error. + */ + VDCallback_Write write; + + /** Called by the web server to move the file pointer, or offset, into + * an open file. The \b origin parameter determines where to start + * moving the file pointer. A value of \c SEEK_CUR moves the + * file pointer relative to where it is. The \b offset parameter can + * be either positive (move forward) or negative (move backward). + * \c SEEK_END moves relative to the end of the file. A positive + * \b offset extends the file. A negative \b offset moves backward + * in the file. Finally, \c SEEK_SET moves to an absolute position in + * the file. In this case, \b offset must be positive. The callback + * should return 0 on a successful seek or a non-zero value on an error. + */ + VDCallback_Seek seek; + + /** Called by the web server to close a file opened via the \b open + * callback. It should return 0 on success, or a non-zero value on an + * error. + */ + VDCallback_Close close; +}; + + +typedef struct virtual_Dir_List +{ + struct virtual_Dir_List *next; + char dirName[NAME_SIZE]; +} virtualDirList; + + +#endif /* VIRTUALDIR_H */ + diff --git a/upnp/src/inc/client_table.h b/upnp/src/inc/client_table.h index 0c33cf7..ed1ef1e 100644 --- a/upnp/src/inc/client_table.h +++ b/upnp/src/inc/client_table.h @@ -56,15 +56,15 @@ typedef struct CLIENT_SUBSCRIPTION { char * ActualSID; char * EventURL; int RenewEventId; - struct CLIENT_SUBSCRIPTION * next; -} client_subscription; + struct CLIENT_SUBSCRIPTION *next; +} ClientSubscription; /************************************************************************ * Function : copy_client_subscription * * Parameters : -* client_subscription * in ; - source client subscription -* client_subscription * out ; - destination client subscription +* ClientSubscription * in ; - source client subscription +* ClientSubscription * out ; - destination client subscription * * Description : Make a copy of the client subscription data * @@ -74,13 +74,13 @@ typedef struct CLIENT_SUBSCRIPTION { * * Note : ************************************************************************/ -int copy_client_subscription(client_subscription * in, client_subscription * out); +int copy_client_subscription(ClientSubscription * in, ClientSubscription * out); /************************************************************************ * Function : free_client_subscription * * Parameters : -* client_subscription * sub ; - Client subscription to be freed +* ClientSubscription * sub ; - Client subscription to be freed * * Description : Free memory allocated for client subscription data. * Remove timer thread associated with this subscription event. @@ -89,14 +89,14 @@ int copy_client_subscription(client_subscription * in, client_subscription * out * * Note : ************************************************************************/ -void free_client_subscription(client_subscription * sub); +void free_client_subscription(ClientSubscription * sub); /************************************************************************ * Function : freeClientSubList * * Parameters : -* client_subscription * list ; Client subscription +* ClientSubscription * list ; Client subscription * * Description : Free the client subscription table. * @@ -104,13 +104,13 @@ void free_client_subscription(client_subscription * sub); * * Note : ************************************************************************/ -void freeClientSubList(client_subscription * list); +void freeClientSubList(ClientSubscription * list); /************************************************************************ * Function : RemoveClientSubClientSID * * Parameters : -* client_subscription **head ; Head of the subscription list +* ClientSubscription **head ; Head of the subscription list * const Upnp_SID sid ; Subscription ID to be mactched * * Description : Remove the client subscription matching the @@ -121,43 +121,42 @@ void freeClientSubList(client_subscription * list); * * Note : ************************************************************************/ -void RemoveClientSubClientSID(client_subscription **head, +void RemoveClientSubClientSID(ClientSubscription **head, const Upnp_SID sid); /************************************************************************ * Function : GetClientSubClientSID * * Parameters : -* client_subscription *head ; Head of the subscription list +* ClientSubscription *head ; Head of the subscription list * const Upnp_SID sid ; Subscription ID to be matched * * Description : Return the client subscription from the client table * that matches const Upnp_SID sid subscrition id value. * -* Return : client_subscription * ; The matching subscription +* Return : ClientSubscription * ; The matching subscription * * Note : ************************************************************************/ -client_subscription * GetClientSubClientSID(client_subscription *head +ClientSubscription * GetClientSubClientSID(ClientSubscription *head , const Upnp_SID sid); /************************************************************************ * Function : GetClientSubActualSID * * Parameters : -* client_subscription *head ; Head of the subscription list +* ClientSubscription *head ; Head of the subscription list * token * sid ; Subscription ID to be matched * * Description : Returns the client subscription from the client * subscription table that has the matching token * sid buffer * value. * -* Return : client_subscription * ; The matching subscription +* Return : ClientSubscription * ; The matching subscription * * Note : ************************************************************************/ -client_subscription * GetClientSubActualSID(client_subscription *head - , token * sid); +ClientSubscription * GetClientSubActualSID(ClientSubscription *head, token * sid); ) #ifdef __cplusplus diff --git a/upnp/src/inc/global.h b/upnp/src/inc/global.h index 58d4b82..570700d 100644 --- a/upnp/src/inc/global.h +++ b/upnp/src/inc/global.h @@ -1,33 +1,38 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + + +#ifndef GLOBAL_H +#define GLOBAL_H + /* GLOBAL.H - RSAREF types and constants */ /* PROTOTYPES should be set to one if and only if the compiler supports @@ -37,8 +42,9 @@ been defined with C compiler flags. */ + #ifndef PROTOTYPES -#define PROTOTYPES 0 + #define PROTOTYPES 0 #endif /* POINTER defines a generic pointer type */ @@ -50,13 +56,17 @@ typedef unsigned short int UINT2; /* UINT4 defines a four byte word */ typedef unsigned long int UINT4; -/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. - If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it - returns an empty list. +/* + * PROTO_LIST is defined depending on how PROTOTYPES is defined above. + * If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + * returns an empty list. */ - #if PROTOTYPES -#define PROTO_LIST(list) list + #define PROTO_LIST(list) list #else -#define PROTO_LIST(list) () + #define PROTO_LIST(list) () #endif + + +#endif /* GLOBAL_H */ + diff --git a/upnp/src/inc/miniserver.h b/upnp/src/inc/miniserver.h index ab1229a..47ae4c5 100644 --- a/upnp/src/inc/miniserver.h +++ b/upnp/src/inc/miniserver.h @@ -42,17 +42,21 @@ extern SOCKET gMiniServerStopSock; typedef struct MServerSockArray { /* socket for listening for miniserver requests */ - int miniServerSock; + SOCKET miniServerSock4; + SOCKET miniServerSock6; /* socket for stopping miniserver */ - int miniServerStopSock; + SOCKET miniServerStopSock; /* socket for incoming advertisments and search requests */ - int ssdpSock; + SOCKET ssdpSock4; + SOCKET ssdpSock6; - int stopPort; - int miniServerPort; + SOCKET stopPort; + SOCKET miniServerPort4; + SOCKET miniServerPort6; /* socket for sending search requests and receiving search replies */ - CLIENTONLY(int ssdpReqSock;) + CLIENTONLY(SOCKET ssdpReqSock4;) + CLIENTONLY(SOCKET ssdpReqSock6;) } MiniServerSockArray; @@ -66,78 +70,62 @@ typedef void (*MiniServerCallback)( extern "C" { #endif -/************************************************************************ - * Function: SetHTTPGetCallback - * - * Parameters: - * MiniServerCallback callback; - HTTP Callback to be invoked - * - * Description: Set HTTP Get Callback - * - * Return: void - ************************************************************************/ -void SetHTTPGetCallback( MiniServerCallback callback ); -/************************************************************************ - * Function: SetSoapCallback - * - * Parameters: - * MiniServerCallback callback; - SOAP Callback to be invoked - * - * Description: Set SOAP Callback - * - * Return: void - ************************************************************************/ +/*! + * \brief Set HTTP Get Callback. + */ +void SetHTTPGetCallback( + /*! [in] HTTP Callback to be invoked . */ + MiniServerCallback callback); + + +/*! + * \brief Set SOAP Callback. + */ #ifdef INCLUDE_DEVICE_APIS -void SetSoapCallback( MiniServerCallback callback ); +void SetSoapCallback( + /*! [in] SOAP Callback to be invoked . */ + MiniServerCallback callback); #else /* INCLUDE_DEVICE_APIS */ -static inline void SetSoapCallback( MiniServerCallback callback ) {} +static inline void SetSoapCallback(MiniServerCallback callback) {} #endif /* INCLUDE_DEVICE_APIS */ -/************************************************************************ - * Function: SetGenaCallback - * - * Parameters: - * MiniServerCallback callback; - GENA Callback to be invoked - * - * D6escription: Set GENA Callback - * - * Return: void - ************************************************************************/ -void SetGenaCallback( MiniServerCallback callback ); -/************************************************************************ - * Function: StartMiniServer - * - * Parameters: - * unsigned short listen_port ; Port on which the server listens for - * incoming connections - * - * Description: Initialize the sockets functionality for the - * Miniserver. Initialize a thread pool job to run the MiniServer - * and the job to the thread pool. If listen port is 0, port is - * dynamically picked - * - * Use timer mechanism to start the MiniServer, failure to meet the - * allowed delay aborts the attempt to launch the MiniServer. - * - * Return: int; - * Actual port socket is bound to - On Success: - * A negative number UPNP_E_XXX - On Error - ************************************************************************/ -int StartMiniServer( unsigned short listen_port ); +/*! + * \brief Set GENA Callback. + */ +void SetGenaCallback( + /*! [in] GENA Callback to be invoked. */ + MiniServerCallback callback); -/************************************************************************ - * Function: StopMiniServer + +/*! + * \brief Initialize the sockets functionality for the Miniserver. * - * Parameters: - * void; + * Initialize a thread pool job to run the MiniServer and the job to the + * thread pool. * - * Description: Stop and Shutdown the MiniServer and free socket resources. + * If listen port is 0, port is dynamically picked. * - * Return : int; - * Always returns 0 - ************************************************************************/ + * Use timer mechanism to start the MiniServer, failure to meet the + * allowed delay aborts the attempt to launch the MiniServer. + * + * \return + * \li On success: UPNP_E_SUCCESS. + * \li On error: UPNP_E_XXX. + */ +int StartMiniServer( + /*! [in,out] Port on which the server listens for incoming IPv4 connections. */ + unsigned short *listen_port4, + /*! [in,out] Port on which the server listens for incoming IPv6 connections. */ + unsigned short *listen_port6); + + +/*! + * \brief Stop and Shutdown the MiniServer and free socket resources. + * + * \return Always returns 0. + */ int StopMiniServer(); diff --git a/upnp/src/inc/sock.h b/upnp/src/inc/sock.h index d7ee596..2a71022 100644 --- a/upnp/src/inc/sock.h +++ b/upnp/src/inc/sock.h @@ -1,44 +1,50 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + #ifndef GENLIB_NET_SOCK_H #define GENLIB_NET_SOCK_H + #include "util.h" -#ifndef WIN32 - #include + +#ifdef WIN32 + /* Do not #include */ +#else + #include #endif -//Following variable is not defined under winsock.h + +/* Following variable is not defined under winsock.h */ #ifndef SD_RECEIVE #define SD_RECEIVE 0x00 #define SD_SEND 0x01 @@ -48,24 +54,25 @@ typedef struct { - int socket; // handle/descriptor to a socket + /* handle/descriptor to a socket */ + SOCKET socket; - // the following two fields are filled only in incoming requests; - struct in_addr foreign_ip_addr; - unsigned short foreign_ip_port; - + /* the following two fields are filled only in incoming requests; */ + struct sockaddr_storage foreign_sockaddr; } SOCKINFO; + #ifdef __cplusplus #extern "C" { #endif + /************************************************************************ * Function : sock_init * * Parameters : * OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor +* IN SOCKET sockfd ; Socket Descriptor * * Description : Assign the passed in socket descriptor to socket * descriptor in the SOCKINFO structure. @@ -76,16 +83,15 @@ typedef struct * UPNP_E_SOCKET_ERROR * Note : ************************************************************************/ -int sock_init( OUT SOCKINFO* info, IN int sockfd ); +int sock_init(OUT SOCKINFO* info, IN SOCKET sockfd); /************************************************************************ * Function : sock_init_with_ip * * Parameters : -* OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor -* IN struct in_addr foreign_ip_addr ; Remote IP Address -* IN unsigned short foreign_ip_port ; Remote Port number +* OUT SOCKINFO* info ; Socket Information Object +* IN SOCKET sockfd ; Socket Descriptor +* IN struct sockaddr* foreign_sockaddr; Remote socket address * * Description : Calls the sock_init function and assigns the passed in * IP address and port to the IP address and port in the SOCKINFO @@ -98,8 +104,10 @@ int sock_init( OUT SOCKINFO* info, IN int sockfd ); * * Note : ************************************************************************/ -int sock_init_with_ip( OUT SOCKINFO* info, IN int sockfd, - IN struct in_addr foreign_ip_addr, IN unsigned short foreign_ip_port ); +int sock_init_with_ip( + OUT SOCKINFO* info, + IN SOCKET sockfd, + IN struct sockaddr *foreign_sockaddr); /************************************************************************ * Function : sock_read @@ -162,11 +170,13 @@ int sock_write( IN SOCKINFO *info, IN char* buffer, IN size_t bufsize, * * Note : ************************************************************************/ -int sock_destroy( INOUT SOCKINFO* info,int ); +int sock_destroy(INOUT SOCKINFO* info, int); + #ifdef __cplusplus -} // #extern "C" +} /* #extern "C" */ #endif -#endif // GENLIB_NET_SOCK_H +#endif /* GENLIB_NET_SOCK_H */ + diff --git a/upnp/src/inc/ssdplib.h b/upnp/src/inc/ssdplib.h index f8c7271..a187aef 100644 --- a/upnp/src/inc/ssdplib.h +++ b/upnp/src/inc/ssdplib.h @@ -1,59 +1,64 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + #ifndef SSDPLIB_H #define SSDPLIB_H +#include "httpparser.h" +#include "httpreadwrite.h" +#include "miniserver.h" +#include "UpnpInet.h" + + #include #include #include #include #include -#include "httpparser.h" -#include "httpreadwrite.h" -#include "miniserver.h" -#ifndef WIN32 - #include - #include - #include - #include - #include - #include - #include - #include + + +#ifdef WIN32 #else -#include + #include + #include + #include + #include + #include + #include + #include #endif -//Enumeration to define all different types of ssdp searches + +/* Enumeration to define all different types of ssdp searches */ typedef enum SsdpSearchType{ SSDP_SERROR=-1, SSDP_ALL,SSDP_ROOTDEVICE, @@ -63,8 +68,9 @@ typedef enum SsdpSearchType{ } SType; -//Enumeration to define all different type of ssdp messages -typedef enum SsdpCmdType{SSDP_ERROR=-1, +/* Enumeration to define all different type of ssdp messages */ +typedef enum SsdpCmdType{ + SSDP_ERROR=-1, SSDP_OK, SSDP_ALIVE, SSDP_BYEBYE, @@ -75,16 +81,18 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1, -//Constant +/* Constant */ #define BUFSIZE 2500 #define SSDP_IP "239.255.255.250" +#define SSDP_IPV6_LINKLOCAL "FF02::C" #define SSDP_PORT 1900 #define NUM_TRY 3 #define NUM_COPY 1 #define THREAD_LIMIT 50 #define COMMAND_LEN 300 -#ifndef X_USER_AGENT // can be overwritten by configure CFLAGS argument +/* can be overwritten by configure CFLAGS argument */ +#ifndef X_USER_AGENT /** @name X_USER_AGENT * The {\tt X_USER_AGENT} constant specifies the value of the X-User-Agent: * HTTP header. The value "redsonic" is needed for the DSM-320. See @@ -94,7 +102,7 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1, #define X_USER_AGENT "redsonic" #endif -//Error code +/* Error code */ #define NO_ERROR_FOUND 0 #define E_REQUEST_INVALID -3 #define E_RES_EXPIRED -4 @@ -105,7 +113,7 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1, -//Structure to store the SSDP information +/* Structure to store the SSDP information */ typedef struct SsdpEventStruct { enum SsdpCmdType Cmd; @@ -121,7 +129,7 @@ typedef struct SsdpEventStruct char Os[LINE_SIZE]; char Ext[LINE_SIZE]; char Date[LINE_SIZE]; - struct sockaddr_in * DestAddr; + struct sockaddr *DestAddr; void * Cookie; } Event; @@ -143,7 +151,7 @@ typedef struct TData int Mx; void * Cookie; char * Data; - struct sockaddr_in DestAddr; + struct sockaddr_storage DestAddr; }ThreadData; @@ -151,7 +159,7 @@ typedef struct ssdpsearchreply { int MaxAge; UpnpDevice_Handle handle; - struct sockaddr_in dest_addr; + struct sockaddr_storage dest_addr; SsdpEvent event; }SsdpSearchReply; @@ -168,21 +176,18 @@ typedef struct ssdpsearcharg typedef struct { http_parser_t parser; - struct sockaddr_in dest_addr; + struct sockaddr_storage dest_addr; } ssdp_thread_data; /* globals */ -CLIENTONLY(extern SOCKET gSsdpReqSocket;); +CLIENTONLY(extern SOCKET gSsdpReqSocket4;); +CLIENTONLY(extern SOCKET gSsdpReqSocket6;); typedef int (*ParserFun)(char *, Event *); -//void InitParser(); - -//int AnalyzeCommand(char * szCommand, Event * Evt); - /************************************************************************ * Function : Make_Socket_NoBlocking * @@ -214,11 +219,11 @@ int Make_Socket_NoBlocking (int sock); #ifdef INCLUDE_DEVICE_APIS void ssdp_handle_device_request( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr ); + IN struct sockaddr* dest_addr ); #else static inline void ssdp_handle_device_request( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr ) {} + IN struct sockaddr* dest_addr ) {} #endif /************************************************************************ @@ -226,7 +231,7 @@ static inline void ssdp_handle_device_request( * * Parameters: * IN http_message_t* hmsg: SSDP message from the device -* IN struct sockaddr_in* dest_addr: Address of the device +* IN struct sockaddr* dest_addr: Address of the device * IN xboolean timeout: timeout kept by the control point while sending * search message * IN void* cookie: Cookie stored by the control point application. @@ -243,7 +248,7 @@ static inline void ssdp_handle_device_request( ***************************************************************************/ void ssdp_handle_ctrlpt_msg( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr, + IN struct sockaddr* dest_addr, IN xboolean timeout, IN void* cookie ); @@ -356,6 +361,7 @@ int SearchByTarget(IN int Mx, IN char *St, IN void *Cookie); * IN char *Udn : * IN char *Location: Location URL. * IN int Duration : Service duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates the device advertisement request based on @@ -369,7 +375,8 @@ int DeviceAdvertisement( IN int RootDev, IN char *Udn, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ @@ -382,6 +389,7 @@ int DeviceAdvertisement( * IN char *_Server: * IN char *Location: Location URL * IN int Duration :Device duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates a HTTP device shutdown request packet @@ -396,13 +404,14 @@ int DeviceShutdown( IN char *Udn, IN char *_Server, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ * Function : DeviceReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr: destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char *Udn: Device UDN @@ -417,17 +426,18 @@ int DeviceShutdown( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int DeviceReply( - IN struct sockaddr_in * DestAddr, + IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, - IN char *Location, IN int Duration); + IN char *Location, + IN int Duration); /************************************************************************ * Function : SendReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr: destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -444,7 +454,7 @@ int DeviceReply( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int SendReply( - IN struct sockaddr_in * DestAddr, + IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, @@ -459,7 +469,8 @@ int SendReply( * IN char * Udn: Device UDN * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. -* IN int Duration :Life time of this device. +* IN int Duration: Life time of this device. +* IN int AddressFamily: Device address family * * Description: * This function creates the advertisement packet based @@ -472,13 +483,14 @@ int ServiceAdvertisement( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ * Function : ServiceReply * * Parameters: -* IN struct sockaddr_in *DestAddr: +* IN struct sockaddr *DestAddr: * IN char *Udn: Device UDN * IN char *ServType: Service Type. * IN char *Server: Not used @@ -493,7 +505,7 @@ int ServiceAdvertisement( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int ServiceReply( - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *ServType, IN char *Udn, IN char *Location, @@ -507,6 +519,7 @@ int ServiceReply( * IN char *ServType: Service Type. * IN char *Location: Location of Device description document. * IN int Duration :Service duration in sec. +* IN int AddressFamily: Device address family * * Description: * This function creates a HTTP service shutdown request packet @@ -519,7 +532,8 @@ int ServiceShutdown( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ @@ -546,7 +560,7 @@ void *advertiseAndReplyThread(IN void * data); * 1 = Send Advertisement * IN UpnpDevice_Handle Hnd: Device handle * IN enum SsdpSearchType SearchType:Search type for sending replies -* IN struct sockaddr_in *DestAddr:Destination address +* IN struct sockaddr *DestAddr:Destination address * IN char *DeviceType:Device type * IN char *DeviceUDN:Device UDN * IN char *ServiceType:Service type @@ -562,10 +576,10 @@ int AdvertiseAndReply( IN int AdFlag, IN UpnpDevice_Handle Hnd, IN enum SsdpSearchType SearchType, - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *DeviceType, IN char *DeviceUDN, IN char *ServiceType, int Exp); -#endif +#endif /* SSDPLIB_H */ diff --git a/upnp/src/inc/sysdep.h b/upnp/src/inc/sysdep.h index ac495b1..eb8980a 100644 --- a/upnp/src/inc/sysdep.h +++ b/upnp/src/inc/sysdep.h @@ -1,65 +1,90 @@ - /* - ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. - ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & - ** Digital Equipment Corporation, Maynard, Mass. - ** Copyright (c) 1998 Microsoft. - ** To anyone who acknowledges that this file is provided "AS IS" - ** without any express or implied warranty: permission to use, copy, - ** modify, and distribute this file for any purpose is hereby - ** granted without fee, provided that the above copyright notices and - ** this notice appears in all source code copies, and that none of - ** the names of Open Software Foundation, Inc., Hewlett-Packard - ** Company, or Digital Equipment Corporation be used in advertising - ** or publicity pertaining to distribution of the software without - ** specific, written prior permission. Neither Open Software - ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment - ** Corporation makes any representations about the suitability of - ** this software for any purpose. - */ +/* + * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. + * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & + * Digital Equipment Corporation, Maynard, Mass. + * Copyright (c) 1998 Microsoft. + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: permission to use, copy, + * modify, and distribute this file for any purpose is hereby + * granted without fee, provided that the above copyright notices and + * this notice appears in all source code copies, and that none of + * the names of Open Software Foundation, Inc., Hewlett-Packard + * Company, or Digital Equipment Corporation be used in advertising + * or publicity pertaining to distribution of the software without + * specific, written prior permission. Neither Open Software + * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment + * Corporation makes any representations about the suitability of + * this software for any purpose. + */ + + +#ifndef SYSDEP_H +#define SYSDEP_H + -#include -#ifndef WIN32 - #include -#endif -//#include #include "ithread.h" + /* change to point to where MD5 .h's live */ /* get MD5 sample implementation from RFC 1321 */ #include "global.h" #include "md5.h" + +#include + + +#ifdef WIN32 + /* Do not #include */ +#else + #include +#endif + + /* set the following to the number of 100ns ticks of the actual resolution of your system's clock */ #define UUIDS_PER_TICK 1024 + /* Set the following to a call to acquire a system wide global lock */ extern ithread_mutex_t gUUIDMutex; + #define UUIDLock() ithread_mutex_lock(&gUUIDMutex) #define UUIDUnlock() ithread_mutex_unlock(&gUUIDMutex) + typedef unsigned long unsigned32; typedef unsigned short unsigned16; typedef unsigned char unsigned8; typedef unsigned char byte; + /* Set this to what your compiler uses for 64 bit data type */ -#ifndef WIN32 - #define unsigned64_t unsigned long long +#ifdef WIN32 + #define unsigned64_t __int64 #else - #define unsigned64_t __int64 + #define unsigned64_t unsigned long long #endif + + #define I64(C) C##LL + typedef unsigned64_t uuid_time_t; + + typedef struct { - char nodeID[6]; + char nodeID[6]; } uuid_node_t; + void get_ieee_node_identifier(uuid_node_t *node); void get_system_time(uuid_time_t *uuid_time); void get_random_info(char seed[16]); + +#endif /* SYSDEP_H */ + diff --git a/upnp/src/inc/unixutil.h b/upnp/src/inc/unixutil.h index 6b2566c..c5f6f25 100644 --- a/upnp/src/inc/unixutil.h +++ b/upnp/src/inc/unixutil.h @@ -1,46 +1,56 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/******************************************************************************* + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + + +/* Unix-specific network utilities */ -// Unix-specific network utilities #ifndef GENLIB_NET_UNIXUTIL_H #define GENLIB_NET_UNIXUTIL_H -#include -#ifndef WIN32 - #include -#else + +#include "UpnpInet.h" + + +#ifdef WIN32 typedef int socklen_t; #define EAFNOSUPPORT 97 +#else + #include + #include + #include + #include + #include #endif -#endif // GENLIB_NET_UNIXUTIL_H + +#endif /* GENLIB_NET_UNIXUTIL_H */ diff --git a/upnp/src/inc/upnpapi.h b/upnp/src/inc/upnpapi.h index 6a481eb..9c63b26 100644 --- a/upnp/src/inc/upnpapi.h +++ b/upnp/src/inc/upnpapi.h @@ -1,42 +1,48 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/******************************************************************************* + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ -// File : upnpapi.h -#ifndef UPNPDK_H -#define UPNPDK_H +#ifndef UPNPAPI_H +#define UPNPAPI_H + + +/*! + * \file + */ + -#include "upnp.h" #include "client_table.h" -//#include "../ssdp/ssdplib.h" +#include "upnp.h" +#include "VirtualDir.h" /* for struct VirtualDirCallbacks */ + #define MAX_INTERFACES 256 @@ -55,134 +61,277 @@ extern size_t g_maxContentLength; -// 30-second timeout +/* 30-second timeout */ #define UPNP_TIMEOUT 30 typedef enum {HND_INVALID=-1,HND_CLIENT,HND_DEVICE} Upnp_Handle_Type; -// Data to be stored in handle table for +/* Data to be stored in handle table for */ struct Handle_Info { - Upnp_Handle_Type HType; - Upnp_FunPtr Callback; // Callback function pointer. - char * Cookie; + /*! . */ + Upnp_Handle_Type HType; + /*! Callback function pointer. */ + Upnp_FunPtr Callback; + /*! . */ + char *Cookie; + /*! 0 = not installed; otherwise installed. */ + int aliasInstalled; - // Device Only + /* Device Only */ #ifdef INCLUDE_DEVICE_APIS - char DescURL[LINE_SIZE]; // URL for the use of SSDP - char DescXML[LINE_SIZE]; // XML file path for device - //description + /*! URL for the use of SSDP. */ + char DescURL[LINE_SIZE]; + /*! XML file path for device description. */ + char DescXML[LINE_SIZE]; + /* Advertisement timeout */ + int MaxAge; + /*! Description parsed in terms of DOM document. */ + IXML_Document *DescDocument; + /*! List of devices in the description document. */ + IXML_NodeList *DeviceList; + /*! List of services in the description document. */ + IXML_NodeList *ServiceList; + /*! Table holding subscriptions and URL information. */ + service_table ServiceTable; + /*! . */ + int MaxSubscriptions; + /*! . */ + int MaxSubscriptionTimeOut; + /*! Address family: AF_INET or AF_INET6. */ + int DeviceAf; +#endif - int MaxAge; // Advertisement timeout - IXML_Document *DescDocument;// Description parsed in - //terms of DOM document - IXML_NodeList *DeviceList; // List of devices in the - //description document - IXML_NodeList *ServiceList; // List of services in the - // description document - service_table ServiceTable; //table holding subscriptions and - //URL information - int MaxSubscriptions; - int MaxSubscriptionTimeOut; -#endif - - // Client only + /* Client only */ #ifdef INCLUDE_CLIENT_APIS - client_subscription *ClientSubList; //client subscription list - LinkedList SsdpSearchList; // active ssdp searches + /*! Client subscription list. */ + ClientSubscription *ClientSubList; + /*! Active SSDP searches. */ + LinkedList SsdpSearchList; #endif - int aliasInstalled; // 0 = not installed; otherwise installed }; + extern ithread_rwlock_t GlobalHndRWLock; -Upnp_Handle_Type GetHandleInfo(int Hnd, struct Handle_Info **HndInfo); + + +/*! + * \brief Get handle information. + * + * \return HND_DEVICE, UPNP_E_INVALID_HANDLE + */ +Upnp_Handle_Type GetHandleInfo( + /*! handle pointer (key for the client handle structure). */ + int Hnd, + /*! handle structure passed by this function. */ + struct Handle_Info **HndInfo); + #define HandleLock() HandleWriteLock() + #define HandleWriteLock() \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a write lock"); \ ithread_rwlock_wrlock(&GlobalHndRWLock); \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Write lock acquired"); + #define HandleReadLock() \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a read lock"); \ ithread_rwlock_rdlock(&GlobalHndRWLock); \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Read lock acquired"); + #define HandleUnlock() \ UpnpPrintf(UPNP_INFO, API,__FILE__, __LINE__, "Trying Unlock"); \ ithread_rwlock_unlock(&GlobalHndRWLock); \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Unlocked rwlock"); -Upnp_Handle_Type GetClientHandleInfo(int *client_handle_out, - struct Handle_Info **HndInfo); -Upnp_Handle_Type GetDeviceHandleInfo(int *device_handle_out, - struct Handle_Info **HndInfo); + +/*! + * \brief Get client handle info. + * + * \note The logic around the use of this function should be revised. + * + * \return HND_CLIENT, HND_INVALID + */ +Upnp_Handle_Type GetClientHandleInfo( + /*! [in] client handle pointer (key for the client handle structure). */ + int *client_handle_out, + /*! [out] Client handle structure passed by this function. */ + struct Handle_Info **HndInfo); +/*! + * \brief Retrieves the device handle and information of the first device of + * the address family spcified. + * + * \return HND_DEVICE or HND_INVALID + */ +Upnp_Handle_Type GetDeviceHandleInfo( + /*! [in] Address family. */ + const int AddressFamily, + /*! [out] Device handle pointer. */ + int *device_handle_out, + /*! [out] Device handle structure passed by this function. */ + struct Handle_Info **HndInfo); -extern char LOCAL_HOST[LINE_SIZE]; +extern char gIF_NAME[LINE_SIZE]; +/*! INET_ADDRSTRLEN. */ +extern char gIF_IPV4[22]; +/*! INET6_ADDRSTRLEN. */ +extern char gIF_IPV6[65]; +extern int gIF_INDEX; + + +extern unsigned short LOCAL_PORT_V4; +extern unsigned short LOCAL_PORT_V6; + + +/*! NLS uuid. */ +extern Upnp_SID gUpnpSdkNLSuuid; -extern unsigned short LOCAL_PORT; extern TimerThread gTimerThread; extern ThreadPool gRecvThreadPool; extern ThreadPool gSendThreadPool; extern ThreadPool gMiniServerThreadPool; + typedef enum { - SUBSCRIBE, - UNSUBSCRIBE, - DK_NOTIFY, - QUERY, - ACTION, - STATUS, - DEVDESCRIPTION, - SERVDESCRIPTION, - MINI, - RENEW} UpnpFunName; + SUBSCRIBE, + UNSUBSCRIBE, + DK_NOTIFY, + QUERY, + ACTION, + STATUS, + DEVDESCRIPTION, + SERVDESCRIPTION, + MINI, + RENEW +} UpnpFunName; + struct UpnpNonblockParam -{ - UpnpFunName FunName; - int Handle; - int TimeOut; - char VarName[NAME_SIZE]; - char NewVal[NAME_SIZE]; - char DevType[NAME_SIZE]; - char DevId[NAME_SIZE]; - char ServiceType[NAME_SIZE]; - char ServiceVer[NAME_SIZE]; - char Url[NAME_SIZE]; - Upnp_SID SubsId; - char *Cookie; - Upnp_FunPtr Fun; +{ + UpnpFunName FunName; + int Handle; + int TimeOut; + char VarName[NAME_SIZE]; + char NewVal[NAME_SIZE]; + char DevType[NAME_SIZE]; + char DevId[NAME_SIZE]; + char ServiceType[NAME_SIZE]; + char ServiceVer[NAME_SIZE]; + char Url[NAME_SIZE]; + Upnp_SID SubsId; + char *Cookie; + Upnp_FunPtr Fun; IXML_Document *Header; - IXML_Document *Act; - struct DevDesc *Devdesc; + IXML_Document *Act; + struct DevDesc *Devdesc; }; extern virtualDirList *pVirtualDirList; -extern struct UpnpVirtualDirCallbacks virtualDirCallback; +extern struct VirtualDirCallbacks virtualDirCallback; -typedef enum { WEB_SERVER_DISABLED, WEB_SERVER_ENABLED } WebServerState; +typedef enum { + WEB_SERVER_DISABLED, + WEB_SERVER_ENABLED +} WebServerState; + #define E_HTTP_SYNTAX -6 + +/*! + * \brief Retrieve interface information and keep it in global variables. + * If NULL, we'll find the first suitable interface for operation. + * + * The interface must fulfill these requirements: + * \li Be UP. + * \li Not be LOOPBACK. + * \li Support MULTICAST. + * \li Have a valid IPv4 or IPv6 address. + * + * We'll retrieve the following information from the interface: + * \li gIF_NAME -> Interface name (by input or found). + * \li gIF_IPV4 -> IPv4 address (if any). + * \li gIF_IPV6 -> IPv6 address (if any). + * \li gIF_INDEX -> Interface index number. + * + * \return UPNP_E_SUCCESS on success. + */ +int UpnpGetIfInfo( + /*! [in] Interface name (can be NULL). */ + const char *IfName); + + +/*! + * \brief Initialize handle table. + */ void InitHandleList(); + + +/*! + * \brief Get a free handle. + * + * \return On success, an integer greater than zero or UPNP_E_OUTOF_HANDLE on + * failure. + */ int GetFreeHandle(); -int FreeHandle(int Handle); + + +/*! + * \brief Free handle. + * + * \return UPNP_E_SUCCESS if successful or UPNP_E_INVALID_HANDLE if not + */ +int FreeHandle( + /*! [in] Handle index. */ + int Handle); + + void UpnpThreadDistribution(struct UpnpNonblockParam * Param); -void AutoAdvertise(void *input); -int getlocalhostname(char *out); +/*! + * \brief This function is a timer thread scheduled by UpnpSendAdvertisement + * to the send advetisement again. + */ +void AutoAdvertise( + /*! [in] Information provided to the thread. */ + void *input); + + +/*! + * \brief Get local IP address. + * + * Gets the ip address for the DEFAULT_INTERFACE interface which is up and not + * a loopback. Assumes at most MAX_INTERFACES interfaces + * + * \return UPNP_E_SUCCESS if successful or UPNP_E_INIT. + */ +int getlocalhostname( + /*! [out] IP address of the interface. */ + char *out, + /*! [in] Length of the output buffer. */ + const int out_len); + + +/*! + * \brief Print handle info. + * + * \return UPNP_E_SUCCESS if successful, otherwise returns appropriate error. + */ +int PrintHandleInfo( + /*! [in] Handle index. */ + UpnpClient_Handle Hnd); + extern WebServerState bWebServerState; -#endif +#endif /* UPNPAPI_H */ - -/************************ END OF upnpapi.h **********************/ diff --git a/upnp/src/inc/urlconfig.h b/upnp/src/inc/urlconfig.h index 4683764..39687bc 100644 --- a/upnp/src/inc/urlconfig.h +++ b/upnp/src/inc/urlconfig.h @@ -1,84 +1,90 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + #ifndef URLCONFIG_H #define URLCONFIG_H -#ifndef WIN32 - #include - #include - #include + + +#include "UpnpInet.h" + + +#ifdef WIN32 #else - #include + #include + #include #endif -// functions available only if the web server is included + +/* functions available only if the web server is included */ + #ifdef __cplusplus extern "C" { #endif + /************************************************************************ -* Function : configure_urlbase -* -* Parameters : -* INOUT IXML_Document *doc ; IXML Description document -* IN const struct sockaddr_in* serverAddr ; socket address object -* providing the IP address and port information -* IN const char* alias ; string containing the alias -* IN time_t last_modified ; time when the XML document was -* downloaded -* OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the -* document. -* -* Description : Configure the full URL for the description document. -* Create the URL document and add alias, description information. -* The doc is added to the web server to be served using the given -* alias. -* -* Return : int ; -* UPNP_E_SUCCESS - On Success -* UPNP_E_OUTOF_MEMORY - Default Error -* -* Note : -****************************************************************************/ + * Function: configure_urlbase + * + * Parameters : + * INOUT IXML_Document *doc ; IXML Description document + * IN const struct sockaddr *serverAddr; socket address object + * providing the IP address and port information + * IN const char* alias ; string containing the alias + * IN time_t last_modified ; time when the XML document was + * downloaded + * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the + * document. + * + * Description : Configure the full URL for the description document. + * Create the URL document and add alias, description information. + * The doc is added to the web server to be served using the given + * alias. + * + * Return : int ; + * UPNP_E_SUCCESS - On Success + * UPNP_E_OUTOF_MEMORY - Default Error + ****************************************************************************/ int configure_urlbase( INOUT IXML_Document *doc, - IN const struct sockaddr_in* serverAddr, - IN const char* alias, + IN const struct sockaddr* serverAddr, + IN const char* alias, IN time_t last_modified, - OUT char docURL[LINE_SIZE] ); + OUT char docURL[LINE_SIZE]); #ifdef __cplusplus -} // extern C +} /* extern C */ #endif + #endif /* URLCONFIG_H */ diff --git a/upnp/src/inc/uuid.h b/upnp/src/inc/uuid.h index 54980f8..53a1d47 100644 --- a/upnp/src/inc/uuid.h +++ b/upnp/src/inc/uuid.h @@ -1,50 +1,90 @@ - /* - ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. - ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & - ** Digital Equipment Corporation, Maynard, Mass. - ** Copyright (c) 1998 Microsoft. - ** To anyone who acknowledges that this file is provided "AS IS" - ** without any express or implied warranty: permission to use, copy, - ** modify, and distribute this file for any purpose is hereby - ** granted without fee, provided that the above copyright notices and - ** this notice appears in all source code copies, and that none of - ** the names of Open Software Foundation, Inc., Hewlett-Packard - ** Company, or Digital Equipment Corporation be used in advertising - ** or publicity pertaining to distribution of the software without - ** specific, written prior permission. Neither Open Software - ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment - ** Corporation makes any representations about the suitability of - ** this software for any purpose. - */ +/* + * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. + * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & + * Digital Equipment Corporation, Maynard, Mass. + * Copyright (c) 1998 Microsoft. + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: permission to use, copy, + * modify, and distribute this file for any purpose is hereby + * granted without fee, provided that the above copyright notices and + * this notice appears in all source code copies, and that none of + * the names of Open Software Foundation, Inc., Hewlett-Packard + * Company, or Digital Equipment Corporation be used in advertising + * or publicity pertaining to distribution of the software without + * specific, written prior permission. Neither Open Software + * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment + * Corporation makes any representations about the suitability of + * this software for any purpose. + */ - typedef struct _uuid_upnp { - unsigned32 time_low; - unsigned16 time_mid; - unsigned16 time_hi_and_version; - unsigned8 clock_seq_hi_and_reserved; - unsigned8 clock_seq_low; - byte node[6]; - } uuid_upnp; - /* uuid_create -- generate a UUID */ - int uuid_create(uuid_upnp * id); - void uuid_unpack(uuid_upnp *u, char *out); // out will be xxxx-xx-xx-xx-xxxxxx format +#include "sysdep.h" - /* uuid_create_from_name -- create a UUID using a "name" - from a "name space" */ - void uuid_create_from_name( - uuid_upnp * uid, /* resulting UUID */ - uuid_upnp nsid, /* UUID to serve as context, so identical - names from different name spaces generate - different UUIDs */ - void * name, /* the name from which to generate a UUID */ - int namelen /* the length of the name */ - ); - /* uuid_compare -- Compare two UUID's "lexically" and return - -1 u1 is lexically before u2 - 0 u1 is equal to u2 - 1 u1 is lexically after u2 - Note: lexical ordering is not temporal ordering! - */ - int uuid_compare(uuid_upnp *u1, uuid_upnp *u2); +/*! . */ +typedef struct _uuid_upnp { + /*! . */ + unsigned32 time_low; + /*! . */ + unsigned16 time_mid; + /*! . */ + unsigned16 time_hi_and_version; + /*! . */ + unsigned8 clock_seq_hi_and_reserved; + /*! . */ + unsigned8 clock_seq_low; + /*! . */ + byte node[6]; +} uuid_upnp; + + +/*! + * \brief Generate a UUID. + */ +int uuid_create( + /*! . */ + uuid_upnp * id); + + +/*! + * \brief Out will be xxxx-xx-xx-xx-xxxxxx format. + */ +void uuid_unpack( + /*! . */ + uuid_upnp *u, + /*! . */ + char *out); + + +/*! + * \brief Create a UUID using a "name" from a "name space" + */ +void uuid_create_from_name( + /*! Resulting UUID. */ + uuid_upnp *uid, + /*! UUID to serve as context, so identical names from different name + * spaces generate different UUIDs. */ + uuid_upnp nsid, + /*! The name from which to generate a UUID. */ + void *name, + /*! The length of the name. */ + int namelen +); + + +/*! + * \brief Compare two UUID's "lexically". + * + * \return + * -1 u1 is lexically before u2 + * 0 u1 is equal to u2 + * 1 u1 is lexically after u2 + * + * \note Lexical ordering is not temporal ordering! + */ +int uuid_compare( + /*! . */ + uuid_upnp *u1, + /*! . */ + uuid_upnp *u2); + diff --git a/upnp/src/soap/soap_device.c b/upnp/src/soap/soap_device.c index f24db28..453bad2 100644 --- a/upnp/src/soap/soap_device.c +++ b/upnp/src/soap/soap_device.c @@ -1,57 +1,68 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/******************************************************************************* + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + + +/*! + * \file + */ + #include "config.h" + + #ifdef INCLUDE_DEVICE_APIS #if EXCLUDE_SOAP == 0 + #define SOAP_BODY "Body" #define SOAP_URN "http:/""/schemas.xmlsoap.org/soap/envelope/" #define QUERY_STATE_VAR_URN "urn:schemas-upnp-org:control-1-0" -#include "upnpapi.h" -#include "parsetools.h" -#include "statcodes.h" #include "httpparser.h" #include "httpreadwrite.h" -#include "unixutil.h" +#include "parsetools.h" #include "soaplib.h" #include "ssdplib.h" +#include "statcodes.h" +#include "unixutil.h" +#include "upnpapi.h" + #ifdef WIN32 - #define snprintf _snprintf + #define snprintf _snprintf #endif -// timeout duration in secs for transmission/reception + +/*! timeout duration in secs for transmission/reception */ #define SOAP_TIMEOUT UPNP_TIMEOUT #define SREQ_HDR_NOT_FOUND -1 @@ -65,13 +76,14 @@ static const char *Soap_Invalid_Action = "Invalid Action"; -//static const char* Soap_Invalid_Args = "Invalid Args"; +/*static const char* Soap_Invalid_Args = "Invalid Args"; */ static const char *Soap_Action_Failed = "Action Failed"; static const char *Soap_Invalid_Var = "Invalid Var"; const char *ContentTypeHeader = "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"; + /**************************************************************************** * Function : get_request_type * @@ -572,7 +584,7 @@ check_soap_action_header( IN http_message_t * request, * OUT char device_udn[LINE_SIZE] : Device UDN string * OUT char service_id[LINE_SIZE] : Service ID string * OUT Upnp_FunPtr *callback : callback function of the device -* application +* application * OUT void** cookie : cookie stored by device application * * Description : This function retrives all the information needed to @@ -586,12 +598,13 @@ check_soap_action_header( IN http_message_t * request, * Note : ****************************************************************************/ static int -get_device_info( IN http_message_t * request, +get_device_info( IN http_message_t *request, IN int isQuery, - IN IXML_Document * actionDoc, + IN IXML_Document *actionDoc, + IN int AddressFamily, OUT char device_udn[LINE_SIZE], OUT char service_id[LINE_SIZE], - OUT Upnp_FunPtr * callback, + OUT Upnp_FunPtr *callback, OUT void **cookie ) { struct Handle_Info *device_info; @@ -609,7 +622,8 @@ get_device_info( IN http_message_t * request, HandleLock(); - if( GetDeviceHandleInfo( &device_hnd, &device_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( AddressFamily, + &device_hnd, &device_info ) != HND_DEVICE ) { goto error_handler; } @@ -840,10 +854,10 @@ error_handler: * * Note : ****************************************************************************/ -static UPNP_INLINE void -handle_query_variable( IN SOCKINFO * info, - IN http_message_t * request, - IN IXML_Document * xml_doc ) +static UPNP_INLINE void handle_query_variable( + IN SOCKINFO *info, + IN http_message_t *request, + IN IXML_Document *xml_doc ) { Upnp_FunPtr soap_event_callback; void *cookie; @@ -859,9 +873,14 @@ handle_query_variable( IN SOCKINFO * info, return; } // get info for event - if( get_device_info( request, 1, xml_doc, variable.DevUDN, - variable.ServiceID, - &soap_event_callback, &cookie ) != 0 ) { + err_code = get_device_info( + request, 1, xml_doc, + info->foreign_sockaddr.ss_family, + variable.DevUDN, + variable.ServiceID, + &soap_event_callback, + &cookie); + if( err_code != 0 ) { send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request ); return; @@ -871,7 +890,7 @@ handle_query_variable( IN SOCKINFO * info, variable.ErrCode = UPNP_E_SUCCESS; namecopy( variable.StateVarName, var_name ); variable.CurrentVal = NULL; - variable.CtrlPtIPAddr = info->foreign_ip_addr; + variable.CtrlPtIPAddr = info->foreign_sockaddr; // send event soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie ); @@ -883,8 +902,8 @@ handle_query_variable( IN SOCKINFO * info, if( variable.CurrentVal == NULL ) { err_code = SOAP_ACTION_FAILED; err_str = Soap_Action_Failed; - send_error_response( info, SOAP_INVALID_VAR, - Soap_Invalid_Var, request ); + send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request ); + return; } if( variable.ErrCode != UPNP_E_SUCCESS ) { @@ -951,9 +970,15 @@ handle_invoke_action( IN SOCKINFO * info, goto error_handler; } // get device info for action event - err_code = get_device_info( request, 0, xml_doc, action.DevUDN, - action.ServiceID, &soap_event_callback, - &cookie ); + err_code = get_device_info( + request, + 0, + xml_doc, + info->foreign_sockaddr.ss_family, + action.DevUDN, + action.ServiceID, + &soap_event_callback, + &cookie ); if( err_code != UPNP_E_SUCCESS ) { goto error_handler; @@ -964,10 +989,9 @@ handle_invoke_action( IN SOCKINFO * info, action.ActionRequest = resp_node; action.ActionResult = NULL; action.ErrCode = UPNP_E_SUCCESS; - action.CtrlPtIPAddr = info->foreign_ip_addr; + action.CtrlPtIPAddr = info->foreign_sockaddr; - UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, - "Calling Callback\n" ); + UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Calling Callback\n"); soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie ); @@ -993,7 +1017,7 @@ handle_invoke_action( IN SOCKINFO * info, err_code = 0; // error handling and cleanup - error_handler: +error_handler: ixmlDocument_free( action.ActionResult ); ixmlDocument_free( resp_node ); action_name.buf[action_name.length] = save_char; // restore diff --git a/upnp/src/ssdp/ssdp_ctrlpt.c b/upnp/src/ssdp/ssdp_ctrlpt.c index efe80f3..2f849ed 100644 --- a/upnp/src/ssdp/ssdp_ctrlpt.c +++ b/upnp/src/ssdp/ssdp_ctrlpt.c @@ -1,72 +1,78 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2000-2003 Intel Corporation -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither name of Intel Corporation nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////// +/************************************************************************** + * + * Copyright (c) 2000-2003 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + #include "config.h" + + #include "util.h" + + #ifdef INCLUDE_CLIENT_APIS #if EXCLUDE_SSDP == 0 -#include "ssdplib.h" -#include "upnpapi.h" -#include -#include "ThreadPool.h" #include "httpparser.h" #include "httpreadwrite.h" +/*#include "ssdp_ResultData.h"*/ +#include "ssdplib.h" #include "statcodes.h" - #include "unixutil.h" +#include "upnpapi.h" +#include "UpnpInet.h" +#include "ThreadPool.h" + + +#include + #ifdef WIN32 - #include - #include #include #endif /* WIN32 */ /************************************************************************ -* Function : send_search_result -* -* Parameters: -* IN void *data: Search reply from the device -* -* Description: -* This function sends a callback to the control point application with -* a SEARCH result -* -* Returns: void -* -***************************************************************************/ -void -send_search_result( IN void *data ) + * Function: send_search_result + * + * Parameters: + * IN void *data: Search reply from the device + * + * Description: + * This function sends a callback to the control point application with + * a SEARCH result + * + * Returns: void + * + ***************************************************************************/ +void send_search_result(IN void *data) { ResultData *temp = ( ResultData * ) data; @@ -76,31 +82,34 @@ send_search_result( IN void *data ) } /************************************************************************ -* Function : ssdp_handle_ctrlpt_msg -* -* Parameters: -* IN http_message_t* hmsg: SSDP message from the device -* IN struct sockaddr_in* dest_addr: Address of the device -* IN xboolean timeout: timeout kept by the control point while -* sending search message -* IN void* cookie: Cookie stored by the control point application. -* This cookie will be returned to the control point -* in the callback -* -* Description: -* This function handles the ssdp messages from the devices. These -* messages includes the search replies, advertisement of device coming -* alive and bye byes. -* -* Returns: void -* -***************************************************************************/ -void -ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, - IN struct sockaddr_in *dest_addr, - IN xboolean timeout, // only in search reply - - IN void *cookie ) // only in search reply + * Function: ssdp_handle_ctrlpt_msg + * + * Parameters: + * IN http_message_t *hmsg: + * SSDP message from the device + * IN struct sockaddr *dest_addr: + * Address of the device + * IN xboolean timeout: + * timeout kept by the control point while + * sending search message + * IN void* cookie: + * Cookie stored by the control point application. + * This cookie will be returned to the control point + * in the callback + * + * Description: + * This function handles the ssdp messages from the devices. These + * messages includes the search replies, advertisement of device coming + * alive and bye byes. + * + * Returns: void + * + ***************************************************************************/ +void ssdp_handle_ctrlpt_msg( + IN http_message_t *hmsg, + IN struct sockaddr *dest_addr, + IN xboolean timeout, // only in search reply + IN void *cookie) // only in search reply { int handle; struct Handle_Info *ctrlpt_info = NULL; @@ -108,9 +117,9 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, xboolean is_byebye; // byebye or alive struct Upnp_Discovery param; SsdpEvent event; - xboolean nt_found, - usn_found, - st_found; + xboolean nt_found; + xboolean usn_found; + xboolean st_found; char save_char; Upnp_EventType event_type; Upnp_FunPtr ctrlpt_callback; @@ -125,7 +134,7 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, HandleReadLock(); - if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) { + if ( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) { HandleUnlock(); return; } @@ -135,7 +144,7 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, HandleUnlock(); // search timeout - if( timeout ) { + if ( timeout ) { ctrlpt_callback( UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie ); return; } @@ -188,26 +197,22 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, nt_found = FALSE; - if( httpmsg_find_hdr( hmsg, HDR_NT, &hdr_value ) != NULL ) { + if ( httpmsg_find_hdr( hmsg, HDR_NT, &hdr_value ) != NULL ) { save_char = hdr_value.buf[hdr_value.length]; hdr_value.buf[hdr_value.length] = '\0'; - nt_found = ( ssdp_request_type( hdr_value.buf, &event ) == 0 ); - hdr_value.buf[hdr_value.length] = save_char; } usn_found = FALSE; - if( httpmsg_find_hdr( hmsg, HDR_USN, &hdr_value ) != NULL ) { + if ( httpmsg_find_hdr( hmsg, HDR_USN, &hdr_value ) != NULL ) { save_char = hdr_value.buf[hdr_value.length]; hdr_value.buf[hdr_value.length] = '\0'; - usn_found = ( unique_service_name( hdr_value.buf, &event ) == 0 ); - hdr_value.buf[hdr_value.length] = save_char; } - if( nt_found || usn_found ) { + if ( nt_found || usn_found ) { strcpy( param.DeviceId, event.UDN ); strcpy( param.DeviceType, event.DeviceType ); strcpy( param.ServiceType, event.ServiceType ); @@ -216,11 +221,10 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, // ADVERT. OR BYEBYE if( hmsg->is_request ) { // use NTS hdr to determine advert., or byebye - // - if( httpmsg_find_hdr( hmsg, HDR_NTS, &hdr_value ) == NULL ) { + if ( httpmsg_find_hdr( hmsg, HDR_NTS, &hdr_value ) == NULL ) { return; // error; NTS header not found } - if( memptr_cmp( &hdr_value, "ssdp:alive" ) == 0 ) { + if ( memptr_cmp( &hdr_value, "ssdp:alive" ) == 0 ) { is_byebye = FALSE; } else if( memptr_cmp( &hdr_value, "ssdp:byebye" ) == 0 ) { is_byebye = TRUE; @@ -228,7 +232,7 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, return; // bad value } - if( is_byebye ) { + if ( is_byebye ) { // check device byebye if( !nt_found || !usn_found ) { return; // bad byebye @@ -243,7 +247,6 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, strlen( param.Location ) == 0 || param.Expires <= 0 ) { return; // bad advertisement } - event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE; } @@ -282,61 +285,50 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, matched = 0; // check for match of ST header and search target switch ( searchArg->requestType ) { - case SSDP_ALL: - { + case SSDP_ALL: matched = 1; break; - } - case SSDP_ROOTDEVICE: - { + case SSDP_ROOTDEVICE: matched = ( event.RequestType == SSDP_ROOTDEVICE ); break; - } - case SSDP_DEVICEUDN: - { + case SSDP_DEVICEUDN: matched = !( strncmp( searchArg->searchTarget, hdr_value.buf, hdr_value.length ) ); break; - } - case SSDP_DEVICETYPE: - { + case SSDP_DEVICETYPE: { + int m = min( hdr_value.length, + strlen( searchArg->searchTarget ) ); + matched = !( strncmp( searchArg->searchTarget, + hdr_value.buf, m ) ); + break; + } + case SSDP_SERVICE: { int m = min( hdr_value.length, strlen( searchArg->searchTarget ) ); matched = !( strncmp( searchArg->searchTarget, hdr_value.buf, m ) ); break; - } - case SSDP_SERVICE: - { - int m = min( hdr_value.length, - strlen( searchArg->searchTarget ) ); - - matched = !( strncmp( searchArg->searchTarget, - hdr_value.buf, m ) ); - break; - } - default: - { + } + default: matched = 0; break; - } } - if( matched ) { + if (matched) { // schedule call back threadData = ( ResultData * ) malloc( sizeof( ResultData ) ); - if( threadData != NULL ) { + if (threadData != NULL) { threadData->param = param; threadData->cookie = searchArg->cookie; threadData->ctrlpt_callback = ctrlpt_callback; TPJobInit( &job, ( start_routine ) send_search_result, threadData ); - TPJobSetPriority( &job, MED_PRIORITY ); + TPJobSetPriority(&job, MED_PRIORITY); TPJobSetFreeFunction( &job, ( free_routine ) free ); - ThreadPoolAdd( &gRecvThreadPool, &job, NULL ); + ThreadPoolAdd(&gRecvThreadPool, &job, NULL); } } node = ListNext( &ctrlpt_info->SsdpSearchList, node ); @@ -347,50 +339,6 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, } } -/************************************************************************ -* Function : process_reply -* -* Parameters: -* IN char* request_buf: the response came from the device -* IN int buf_len: The length of the response buffer -* IN struct sockaddr_in* dest_addr: The address of the device -* IN void *cookie : cookie passed by the control point application -* at the time of sending search message -* -* Description: -* This function processes reply recevied from a search -* -* Returns: void -* -***************************************************************************/ -#ifndef WIN32 -#warning There are currently no uses of the function 'process_reply()' in the code. -#warning 'process_reply()' is a candidate for removal. -#else -#pragma message("There are currently no uses of the function 'process_reply()' in the code.") -#pragma message("'process_reply()' is a candidate for removal.") -#endif -static UPNP_INLINE void -process_reply( IN char *request_buf, - IN int buf_len, - IN struct sockaddr_in *dest_addr, - IN void *cookie ) -{ - http_parser_t parser; - - parser_response_init( &parser, HTTPMETHOD_MSEARCH ); - - // parse - if( parser_append( &parser, request_buf, buf_len ) != PARSE_SUCCESS ) { - httpmsg_destroy( &parser.msg ); - return; - } - // handle reply - ssdp_handle_ctrlpt_msg( &parser.msg, dest_addr, FALSE, cookie ); - - // done - httpmsg_destroy( &parser.msg ); -} /************************************************************************ * Function : CreateClientRequestPacket @@ -400,6 +348,7 @@ process_reply( IN char *request_buf, * IN char *SearchTarget:Search Target * IN int Mx dest_addr: Number of seconds to wait to * collect all the responses +* IN int AddressFamily: search address family * * Description: * This function creates a HTTP search request packet @@ -411,13 +360,18 @@ process_reply( IN char *request_buf, static void CreateClientRequestPacket( IN char *RqstBuf, IN int Mx, - IN char *SearchTarget ) + IN char *SearchTarget, + IN int AddressFamily ) { char TempBuf[COMMAND_LEN]; strcpy( RqstBuf, "M-SEARCH * HTTP/1.1\r\n" ); - sprintf( TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT ); + if (AddressFamily == AF_INET) { + sprintf( TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT ); + } else if (AddressFamily == AF_INET6) { + sprintf( TempBuf, "HOST: [%s]:%d\r\n", SSDP_IPV6_LINKLOCAL, SSDP_PORT ); + } strcat( RqstBuf, TempBuf ); strcat( RqstBuf, "MAN: \"ssdp:discover\"\r\n" ); @@ -431,7 +385,6 @@ CreateClientRequestPacket( IN char *RqstBuf, strcat( RqstBuf, TempBuf ); } strcat( RqstBuf, "\r\n" ); - } /************************************************************************ @@ -507,7 +460,17 @@ searchExpired( void *arg ) * This cokie will be returned to application in the callback. * * Description: -* This function creates and send the search request for a specific URL. +* This function implements the search request of the discovery phase. +* A M-SEARCH request is sent on the SSDP channel for both IPv4 and +* IPv6 addresses. The search target(ST) is required and must be one of +* the following: +* - "ssdp:all" : Search for all devices and services. +* - "ssdp:rootdevice" : Search for root devices only. +* - "uuid:" : Search for a particular device. +* - "urn:schemas-upnp-org:device:" +* - "urn:schemas-upnp-org:service:" +* - "urn::device:" +* - "urn::service:" * * Returns: int * 1 if successful else appropriate error @@ -518,18 +481,23 @@ SearchByTarget( IN int Mx, IN void *Cookie ) { char errorBuffer[ERROR_BUFFER_LEN]; - int socklen = sizeof( struct sockaddr_in ); + int socklen = sizeof( struct sockaddr_storage ); int *id = NULL; int ret = 0; - char *ReqBuf; - struct sockaddr_in destAddr; + char ReqBufv4[BUFSIZE]; + char ReqBufv6[BUFSIZE]; + struct sockaddr_storage __ss_v4; + struct sockaddr_storage __ss_v6; + struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4; + struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6; fd_set wrSet; SsdpSearchArg *newArg = NULL; int timeTillRead = 0; int handle; struct Handle_Info *ctrlpt_info = NULL; enum SsdpSearchType requestType; - unsigned long addr = inet_addr( LOCAL_HOST ); + unsigned long addrv4 = inet_addr( gIF_IPV4 ); + int max_fd = 0; //ThreadData *ThData; ThreadPoolJob job; @@ -539,12 +507,7 @@ SearchByTarget( IN int Mx, return UPNP_E_INVALID_PARAM; } - ReqBuf = (char *)malloc( BUFSIZE ); - if( ReqBuf == NULL ) { - return UPNP_E_OUTOF_MEMORY; - } - - UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND >>>\n"); + UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n"); timeTillRead = Mx; @@ -554,21 +517,24 @@ SearchByTarget( IN int Mx, timeTillRead = MAX_SEARCH_TIME; } - CreateClientRequestPacket( ReqBuf, timeTillRead, St ); - memset( ( char * )&destAddr, 0, sizeof( struct sockaddr_in ) ); + CreateClientRequestPacket( ReqBufv4, timeTillRead, St, AF_INET ); + CreateClientRequestPacket( ReqBufv6, timeTillRead, St, AF_INET6 ); - destAddr.sin_family = AF_INET; - destAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - destAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss_v4, 0, sizeof( __ss_v4 ) ); + destAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &destAddr4->sin_addr ); + destAddr4->sin_port = htons( SSDP_PORT ); - FD_ZERO( &wrSet ); - FD_SET( gSsdpReqSocket, &wrSet ); + memset( &__ss_v6, 0, sizeof( __ss_v6 ) ); + destAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr ); + destAddr6->sin6_port = htons( SSDP_PORT ); + destAddr6->sin6_scope_id = gIF_INDEX; // add search criteria to list HandleLock(); if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) { HandleUnlock(); - free( ReqBuf ); return UPNP_E_INTERNAL_ERROR; } @@ -590,34 +556,56 @@ SearchByTarget( IN int Mx, ListAddTail( &ctrlpt_info->SsdpSearchList, newArg ); HandleUnlock(); - ret = setsockopt( gSsdpReqSocket, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&addr, sizeof (addr) ); + FD_ZERO( &wrSet ); + if( gSsdpReqSocket4 != INVALID_SOCKET ) { + setsockopt( gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&addrv4, sizeof (addrv4) ); + FD_SET( gSsdpReqSocket4, &wrSet ); + max_fd = max(max_fd, gSsdpReqSocket4); + } + if( gSsdpReqSocket6 != INVALID_SOCKET ) { + setsockopt( gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *)&gIF_INDEX, sizeof(gIF_INDEX) ); + FD_SET( gSsdpReqSocket6, &wrSet ); + max_fd = max(max_fd, gSsdpReqSocket6); + } - ret = select( gSsdpReqSocket + 1, NULL, &wrSet, NULL, NULL ); + ret = select( max_fd + 1, NULL, &wrSet, NULL, NULL ); if( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: Error in select(): %s\n", errorBuffer ); - shutdown( gSsdpReqSocket, SD_BOTH ); - UpnpCloseSocket( gSsdpReqSocket ); - free( ReqBuf ); + shutdown( gSsdpReqSocket4, SD_BOTH ); + UpnpCloseSocket( gSsdpReqSocket4 ); + shutdown( gSsdpReqSocket6, SD_BOTH ); + UpnpCloseSocket( gSsdpReqSocket6 ); return UPNP_E_INTERNAL_ERROR; - } else if( FD_ISSET( gSsdpReqSocket, &wrSet ) ) { + } + if( gSsdpReqSocket6 != INVALID_SOCKET && + FD_ISSET( gSsdpReqSocket6, &wrSet ) ) { int NumCopy = 0; while( NumCopy < NUM_SSDP_COPY ) { - sendto( gSsdpReqSocket, ReqBuf, strlen( ReqBuf ), 0, - (struct sockaddr *)&destAddr, socklen ); + sendto( gSsdpReqSocket6, ReqBufv6, strlen( ReqBufv6 ), 0, + (struct sockaddr *)&__ss_v6, socklen ); NumCopy++; imillisleep( SSDP_PAUSE ); } } + if( gSsdpReqSocket4 != INVALID_SOCKET && + FD_ISSET( gSsdpReqSocket4, &wrSet ) ) { + int NumCopy = 0; + while( NumCopy < NUM_SSDP_COPY ) { + sendto( gSsdpReqSocket4, ReqBufv4, strlen( ReqBufv4 ), 0, + (struct sockaddr *)&__ss_v4, socklen ); + NumCopy++; + imillisleep( SSDP_PAUSE ); + } + } - free( ReqBuf ); return 1; } #endif // EXCLUDE_SSDP #endif // INCLUDE_CLIENT_APIS - diff --git a/upnp/src/ssdp/ssdp_device.c b/upnp/src/ssdp/ssdp_device.c index 27a2c30..f64e7e8 100644 --- a/upnp/src/ssdp/ssdp_device.c +++ b/upnp/src/ssdp/ssdp_device.c @@ -77,7 +77,7 @@ advertiseAndReplyThread( IN void *data ) AdvertiseAndReply( 0, arg->handle, arg->event.RequestType, - &arg->dest_addr, + (struct sockaddr*)&arg->dest_addr, arg->event.DeviceType, arg->event.UDN, arg->event.ServiceType, arg->MaxAge ); @@ -91,7 +91,7 @@ advertiseAndReplyThread( IN void *data ) * * Parameters: * IN http_message_t *hmsg: SSDP search request from the control point -* IN struct sockaddr_in* dest_addr: The address info of control point +* IN struct sockaddr *dest_addr: The address info of control point * * Description: * This function handles the search request. It do the sanity checks of @@ -104,7 +104,7 @@ advertiseAndReplyThread( IN void *data ) #ifdef INCLUDE_DEVICE_APIS void ssdp_handle_device_request( IN http_message_t *hmsg, - IN struct sockaddr_in *dest_addr ) + IN struct sockaddr *dest_addr ) { #define MX_FUDGE_FACTOR 10 @@ -144,7 +144,8 @@ ssdp_handle_device_request( IN http_message_t *hmsg, HandleLock(); // device info - if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( dest_addr->sa_family, + &handle, &dev_info ) != HND_DEVICE ) { HandleUnlock(); return; // no info found } @@ -172,7 +173,7 @@ ssdp_handle_device_request( IN http_message_t *hmsg, return; } threadArg->handle = handle; - threadArg->dest_addr = ( *dest_addr ); + memcpy( &threadArg->dest_addr, dest_addr, sizeof(threadArg->dest_addr) ); threadArg->event = event; threadArg->MaxAge = maxAge; @@ -203,7 +204,7 @@ ssdp_handle_device_request( IN http_message_t *hmsg, * Function : NewRequestHandler * * Parameters: -* IN struct sockaddr_in * DestAddr: Ip address, to send the reply. +* IN struct sockaddr *DestAddr: Ip address, to send the reply. * IN int NumPacket: Number of packet to be sent. * IN char **RqPacket:Number of packet to be sent. * @@ -215,19 +216,21 @@ ssdp_handle_device_request( IN http_message_t *hmsg, * 1 if successful else appropriate error ***************************************************************************/ static int -NewRequestHandler( IN struct sockaddr_in *DestAddr, +NewRequestHandler( IN struct sockaddr *DestAddr, IN int NumPacket, IN char **RqPacket ) { char errorBuffer[ERROR_BUFFER_LEN]; - int ReplySock; - int socklen = sizeof( struct sockaddr_in ); + SOCKET ReplySock; + int socklen = sizeof( struct sockaddr_storage ); int NumCopy; int Index; - unsigned long replyAddr = inet_addr( LOCAL_HOST ); + unsigned long replyAddr = inet_addr( gIF_IPV4 ); int ttl = 4; // a/c to UPNP Spec + int hops = 1; + char buf_ntop[64]; - ReplySock = socket( AF_INET, SOCK_DGRAM, 0 ); + ReplySock = socket( DestAddr->sa_family, SOCK_DGRAM, 0 ); if ( ReplySock == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, @@ -236,11 +239,25 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, return UPNP_E_OUTOF_SOCKET; } - - setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&replyAddr, sizeof (replyAddr) ); - setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, - (char *)&ttl, sizeof (int) ); + + if( DestAddr->sa_family == AF_INET ) { + inet_ntop(AF_INET, &((struct sockaddr_in*)DestAddr)->sin_addr, + buf_ntop, sizeof(buf_ntop)); + setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&replyAddr, sizeof (replyAddr) ); + setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, + (char *)&ttl, sizeof (int) ); + } else if( DestAddr->sa_family == AF_INET6 ) { + inet_ntop(AF_INET6, &((struct sockaddr_in6*)DestAddr)->sin6_addr, + buf_ntop, sizeof(buf_ntop)); + setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *)&gIF_INDEX, sizeof(gIF_INDEX) ); + setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + (char *)&hops, sizeof(hops) ); + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid destination address specified." ); + } for( Index = 0; Index < NumPacket; Index++ ) { int rc; @@ -258,11 +275,11 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, NumCopy = 0; while( NumCopy < NUM_COPY ) { UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, - ">>> SSDP SEND >>>\n%s\n", - *( RqPacket + Index ) ); + ">>> SSDP SEND to %s >>>\n%s\n", + buf_ntop, *( RqPacket + Index ) ); rc = sendto( ReplySock, *( RqPacket + Index ), strlen( *( RqPacket + Index ) ), - 0, ( struct sockaddr * )DestAddr, socklen ); + 0, DestAddr, socklen ); imillisleep( SSDP_PAUSE ); ++NumCopy; } @@ -285,6 +302,7 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, * IN char * location :Location URL. * IN int duration :Service duration in sec. * OUT char** packet :Output buffer filled with HTTP statement. +* IN int AddressFamily: Address family of the HTTP request. * * Description: * This function creates a HTTP request packet. Depending @@ -300,7 +318,8 @@ CreateServicePacket( IN int msg_type, IN char *usn, IN char *location, IN int duration, - OUT char **packet ) + OUT char **packet, + IN int AddressFamily) { int ret_code; char *nts; @@ -317,11 +336,13 @@ CreateServicePacket( IN int msg_type, if( msg_type == MSGTYPE_REPLY ) { ret_code = http_MakeMessage( &buf, 1, 1, - "R" "sdc" "D" "sc" "ssc" "S" "Xc" "ssc" "sscc", + "R" "sdc" "D" "sc" "ssc" "ssc" "ssc" "S" "Xc" "ssc" "sscc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, + "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", + "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt, "USN: ", usn); @@ -342,11 +363,15 @@ CreateServicePacket( IN int msg_type, ret_code = http_MakeMessage( &buf, 1, 1, - "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", + "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", HTTPMETHOD_NOTIFY, "*", (size_t)1, - "HOST: ", SSDP_IP, ":", SSDP_PORT, + "HOST: ", + (AddressFamily==AF_INET) ? SSDP_IP : "[" SSDP_IPV6_LINKLOCAL "]", + ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, + "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", + "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts, X_USER_AGENT, @@ -389,9 +414,12 @@ DeviceAdvertisement( IN char *DevType, int RootDev, char *Udn, IN char *Location, - IN int Duration ) + IN int Duration, + IN int AddressFamily) { - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; //char Mil_Nt[LINE_SIZE] char Mil_Usn[LINE_SIZE]; @@ -401,9 +429,20 @@ DeviceAdvertisement( IN char *DevType, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "In function DeviceAdvertisement\n" ); - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } msgs[0] = NULL; msgs[1] = NULL; @@ -414,17 +453,17 @@ DeviceAdvertisement( IN char *DevType, if( RootDev ) { sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], AddressFamily ); } // both root and sub-devices need to send these two messages // CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn, - Location, Duration, &msgs[1] ); + Location, Duration, &msgs[1], AddressFamily ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn, - Location, Duration, &msgs[2] ); + Location, Duration, &msgs[2], AddressFamily ); // check error if( ( RootDev && msgs[0] == NULL ) || @@ -437,11 +476,11 @@ DeviceAdvertisement( IN char *DevType, // send packets if( RootDev ) { // send 3 msg types - ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] ); } else // sub-device { // send 2 msg types - ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] ); } // free msgs @@ -456,7 +495,7 @@ DeviceAdvertisement( IN char *DevType, * Function : SendReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr * DestAddr:destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -472,7 +511,7 @@ DeviceAdvertisement( IN char *DevType, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -SendReply( IN struct sockaddr_in *DestAddr, +SendReply( IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, @@ -495,7 +534,7 @@ SendReply( IN struct sockaddr_in *DestAddr, sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], DestAddr->sa_family ); } else { // two msgs for embedded devices num_msgs = 1; @@ -503,11 +542,11 @@ SendReply( IN struct sockaddr_in *DestAddr, //NK: FIX for extra response when someone searches by udn if( !ByType ) { CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location, - Duration, &msgs[0] ); + Duration, &msgs[0], DestAddr->sa_family ); } else { sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_REPLY, DevType, Mil_Usn, - Location, Duration, &msgs[0] ); + Location, Duration, &msgs[0], DestAddr->sa_family ); } } @@ -533,7 +572,7 @@ SendReply( IN struct sockaddr_in *DestAddr, * Function : DeviceReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr:destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -547,7 +586,7 @@ SendReply( IN struct sockaddr_in *DestAddr, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -DeviceReply( IN struct sockaddr_in *DestAddr, +DeviceReply( IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, @@ -570,18 +609,18 @@ DeviceReply( IN struct sockaddr_in *DestAddr, strcpy( Mil_Nt, "upnp:rootdevice" ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], DestAddr->sa_family ); } sprintf( Mil_Nt, "%s", Udn ); sprintf( Mil_Usn, "%s", Udn ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[1] ); + Location, Duration, &szReq[1], DestAddr->sa_family ); sprintf( Mil_Nt, "%s", DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[2] ); + Location, Duration, &szReq[2], DestAddr->sa_family ); // check error @@ -615,6 +654,7 @@ DeviceReply( IN struct sockaddr_in *DestAddr, * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. * IN int Duration :Life time of this device. +* IN int AddressFamily: Device address family * Description: * This function creates the advertisement packet based * on the input parameter, and send it to the multicast channel. @@ -626,28 +666,42 @@ int ServiceAdvertisement( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration) + IN int Duration, + IN int AddressFamily) { char Mil_Usn[LINE_SIZE]; char *szReq[1]; - struct sockaddr_in DestAddr; int RetVal; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } sprintf( Mil_Usn, "%s::%s", Udn, ServType ); //CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn, //Server,Location,Duration); CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], AddressFamily ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } - RetVal = NewRequestHandler( &DestAddr, 1, szReq ); + RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq ); free( szReq[0] ); return RetVal; @@ -657,7 +711,7 @@ ServiceAdvertisement( IN char *Udn, * Function : ServiceReply * * Parameters: -* IN struct sockaddr_in *DestAddr: +* IN struct sockaddr *DestAddr: * IN char * Udn: Device UDN * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. @@ -670,7 +724,7 @@ ServiceAdvertisement( IN char *Udn, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -ServiceReply( IN struct sockaddr_in *DestAddr, +ServiceReply( IN struct sockaddr *DestAddr, IN char *ServType, IN char *Udn, IN char *Location, @@ -685,7 +739,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr, sprintf( Mil_Usn, "%s::%s", Udn, ServType ); CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], DestAddr->sa_family ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } @@ -704,6 +758,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr, * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. * IN int Duration :Service duration in sec. +* IN int AddressFamily: Device address family * Description: * This function creates a HTTP service shutdown request packet * and sent it to the multicast channel through RequestHandler. @@ -715,27 +770,41 @@ int ServiceShutdown( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration) + IN int Duration, + IN int AddressFamily) { char Mil_Usn[LINE_SIZE]; char *szReq[1]; - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; int RetVal; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } //sprintf(Mil_Nt,"%s",ServType); sprintf( Mil_Usn, "%s::%s", Udn, ServType ); //CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn, //Server,Location,Duration); CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], AddressFamily ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } - RetVal = NewRequestHandler( &DestAddr, 1, szReq ); + RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq ); free( szReq[0] ); return RetVal; @@ -750,6 +819,7 @@ ServiceShutdown( IN char *Udn, * IN char * Udn: Device UDN * IN char * Location: Location URL * IN int Duration :Device duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates a HTTP device shutdown request packet @@ -764,9 +834,12 @@ DeviceShutdown( IN char *DevType, IN char *Udn, IN char *_Server, IN char *Location, - IN int Duration) + IN int Duration, + IN int AddressFamily) { - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; char *msgs[3]; char Mil_Usn[LINE_SIZE]; int ret_code; @@ -775,26 +848,37 @@ DeviceShutdown( IN char *DevType, msgs[1] = NULL; msgs[2] = NULL; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } // root device has one extra msg if( RootDev ) { sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], AddressFamily ); } UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "In function DeviceShutdown\n" ); // both root and sub-devices need to send these two messages CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn, - Location, Duration, &msgs[1] ); + Location, Duration, &msgs[1], AddressFamily ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn, - Location, Duration, &msgs[2] ); + Location, Duration, &msgs[2], AddressFamily ); // check error if( ( RootDev && msgs[0] == NULL ) || @@ -807,11 +891,11 @@ DeviceShutdown( IN char *DevType, // send packets if( RootDev ) { // send 3 msg types - ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] ); } else // sub-device { // send 2 msg types - ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] ); } // free msgs diff --git a/upnp/src/ssdp/ssdp_server.c b/upnp/src/ssdp/ssdp_server.c index 2e78e74..b7e302a 100644 --- a/upnp/src/ssdp/ssdp_server.c +++ b/upnp/src/ssdp/ssdp_server.c @@ -50,18 +50,23 @@ #define MAX_TIME_TOREAD 45 -CLIENTONLY( SOCKET gSsdpReqSocket = 0; ) +CLIENTONLY( SOCKET gSsdpReqSocket4 = INVALID_SOCKET; ) +CLIENTONLY( SOCKET gSsdpReqSocket6 = INVALID_SOCKET; ) void RequestHandler(); +int create_ssdp_sock_v4( SOCKET* ssdpSock ); +int create_ssdp_sock_v6( SOCKET* ssdpSock ); +#if INCLUDE_CLIENT_APIS +int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock ); +int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock ); +#endif Event ErrotEvt; enum Listener { Idle, Stopping, Running }; -unsigned short ssdpStopPort; - struct SSDPSockArray { // socket for incoming advertisments and search requests - int ssdpSock; + SOCKET ssdpSock; // socket for sending search requests and receiving search replies CLIENTONLY( int ssdpReqSock; ) }; @@ -79,10 +84,10 @@ struct SSDPSockArray { * 1 = Send Advertisement * IN UpnpDevice_Handle Hnd: Device handle * IN enum SsdpSearchType SearchType:Search type for sending replies - * IN struct sockaddr_in *DestAddr:Destination address - * IN char *DeviceType:Device type + * IN struct sockaddr *DestAddr:Destination address + * IN char *DeviceType:Device type * IN char *DeviceUDN:Device UDN - * IN char *ServiceType:Service type + * IN char *ServiceType:Service type * IN int Exp:Advertisement age * * Description: @@ -95,7 +100,7 @@ int AdvertiseAndReply( IN int AdFlag, IN UpnpDevice_Handle Hnd, IN enum SsdpSearchType SearchType, - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *DeviceType, IN char *DeviceUDN, IN char *ServiceType, @@ -213,11 +218,11 @@ int AdvertiseAndReply( /* send the device advertisement */ if (AdFlag == 1) { DeviceAdvertisement(devType, i == 0, - UDNstr, SInfo->DescURL, Exp); + UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf ); } else { /* AdFlag == -1 */ DeviceShutdown(devType, i == 0, UDNstr, - SERVER, SInfo->DescURL, Exp); + SERVER, SInfo->DescURL, Exp, SInfo->DeviceAf ); } } else { switch (SearchType) { @@ -311,11 +316,11 @@ int AdvertiseAndReply( if (AdFlag) { if (AdFlag == 1) { ServiceAdvertisement(UDNstr, servType, - SInfo->DescURL, Exp); + SInfo->DescURL, Exp, SInfo->DeviceAf ); } else { /* AdFlag == -1 */ ServiceShutdown(UDNstr, servType, - SInfo->DescURL, Exp); + SInfo->DescURL, Exp, SInfo->DeviceAf ); } } else { switch (SearchType) { @@ -362,7 +367,7 @@ end_function: * Function : Make_Socket_NoBlocking * * Parameters: - * IN int sock: socket + * IN SOCKET sock: socket * * Description: * This function makes socket non-blocking. @@ -371,7 +376,7 @@ end_function: * 0 if successful else -1 ***************************************************************************/ int -Make_Socket_NoBlocking( int sock ) +Make_Socket_NoBlocking( SOCKET sock ) { #ifdef WIN32 u_long val=1; @@ -614,8 +619,11 @@ valid_ssdp_msg( IN http_message_t * hmsg ) } // check HOST header if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) || - ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 ) + ( ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 ) && + ( memptr_cmp( &hdr_value, "[FF02::C]:1900" ) != 0 ) ) ) { + UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, + "Invalid HOST header from SSDP message\n" ); return FALSE; } } @@ -664,7 +672,7 @@ start_event_handler( void *Data ) goto error_handler; } // check msg - if( !valid_ssdp_msg( &parser->msg ) ) { + if( valid_ssdp_msg( &parser->msg ) != TRUE ) { goto error_handler; } return 0; //////// done; thread will free 'data' @@ -699,9 +707,10 @@ ssdp_event_handler_thread( void *the_data ) // send msg to device or ctrlpt if( ( hmsg->method == HTTPMETHOD_NOTIFY ) || ( hmsg->request_method == HTTPMETHOD_MSEARCH ) ) { - CLIENTONLY( ssdp_handle_ctrlpt_msg( hmsg, &data->dest_addr, FALSE, NULL );) + CLIENTONLY( ssdp_handle_ctrlpt_msg( hmsg, + (struct sockaddr*)&data->dest_addr, FALSE, NULL );) } else { - ssdp_handle_device_request( hmsg, &data->dest_addr ); + ssdp_handle_device_request( hmsg, (struct sockaddr*)&data->dest_addr ); } // free data @@ -725,11 +734,12 @@ readFromSSDPSocket( SOCKET socket ) { char *requestBuf = NULL; char staticBuf[BUFSIZE]; - struct sockaddr_in clientAddr; + struct sockaddr_storage __ss; ThreadPoolJob job; ssdp_thread_data *data = NULL; - socklen_t socklen = 0; + socklen_t socklen = sizeof( __ss ); int byteReceived = 0; + char ntop_buf[64]; requestBuf = staticBuf; @@ -737,8 +747,6 @@ readFromSSDPSocket( SOCKET socket ) //can't be allocated, still drain the //socket using a static buffer - socklen = sizeof( struct sockaddr_in ); - data = ( ssdp_thread_data * ) malloc( sizeof( ssdp_thread_data ) ); @@ -746,7 +754,7 @@ readFromSSDPSocket( SOCKET socket ) //initialize parser #ifdef INCLUDE_CLIENT_APIS - if( socket == gSsdpReqSocket ) { + if( socket == gSsdpReqSocket4 || socket == gSsdpReqSocket6 ) { parser_response_init( &data->parser, HTTPMETHOD_MSEARCH ); } else { parser_request_init( &data->parser ); @@ -768,10 +776,18 @@ readFromSSDPSocket( SOCKET socket ) } byteReceived = recvfrom( socket, requestBuf, BUFSIZE - 1, 0, - ( struct sockaddr * )&clientAddr, &socklen ); + (struct sockaddr *)&__ss, &socklen ); if( byteReceived > 0 ) { requestBuf[byteReceived] = '\0'; + + if( __ss.ss_family == AF_INET ) + inet_ntop( AF_INET, &((struct sockaddr_in*)&__ss)->sin_addr, ntop_buf, sizeof(ntop_buf) ); + else if( __ss.ss_family == AF_INET6 ) + inet_ntop( AF_INET6, &((struct sockaddr_in6*)&__ss)->sin6_addr, ntop_buf, sizeof(ntop_buf) ); + else + strncpy( ntop_buf, "", sizeof(ntop_buf) ); + UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "Start of received response ----------------------------------------------------\n" @@ -779,7 +795,7 @@ readFromSSDPSocket( SOCKET socket ) "End of received response ------------------------------------------------------\n" "From host %s\n", requestBuf, - inet_ntoa( clientAddr.sin_addr ) ); + ntop_buf ); UpnpPrintf( UPNP_PACKET, SSDP, __FILE__, __LINE__, "Start of received multicast packet --------------------------------------------\n" "%s\n" @@ -790,7 +806,7 @@ readFromSSDPSocket( SOCKET socket ) data->parser.msg.msg.length += byteReceived; // null-terminate data->parser.msg.msg.buf[byteReceived] = 0; - data->dest_addr = clientAddr; + memcpy( &data->dest_addr, &__ss, sizeof(__ss) ); TPJobInit( &job, ( start_routine ) ssdp_event_handler_thread, data ); TPJobSetFreeFunction( &job, free_ssdp_event_handler_data ); @@ -805,6 +821,7 @@ readFromSSDPSocket( SOCKET socket ) } } + /************************************************************************ * Function : get_ssdp_sockets * @@ -812,125 +829,252 @@ readFromSSDPSocket( SOCKET socket ) * OUT MiniServerSockArray *out: Array of SSDP sockets * * Description: - * This function creates the ssdp sockets. It set their option to listen - * for multicast traffic. + * This function creates the IPv4 and IPv6 ssdp sockets required by the + * control point and device operation. * * Returns: int * return UPNP_E_SUCCESS if successful else returns appropriate error ***************************************************************************/ -int -get_ssdp_sockets( MiniServerSockArray * out ) +int get_ssdp_sockets( MiniServerSockArray * out ) { - char errorBuffer[ERROR_BUFFER_LEN]; - int onOff = 1; - u_char ttl = 4; - struct ip_mreq ssdpMcastAddr; - struct sockaddr_in ssdpAddr; - int option = 1; - int ret = 0; - struct in_addr addr; - SOCKET ssdpSock; + int retVal; + #if INCLUDE_CLIENT_APIS - SOCKET ssdpReqSock; - - ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( ssdpReqSock == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, - "Error in socket(): %s\n", errorBuffer ); - - return UPNP_E_OUTOF_SOCKET; + // Create the IPv4 socket for SSDP REQUESTS + if( strlen( gIF_IPV4 ) > 0 ) { + retVal = create_ssdp_sock_reqv4( &out->ssdpReqSock4 ); + if( retVal != UPNP_E_SUCCESS ) { + return retVal; + } + // For use by ssdp control point. + gSsdpReqSocket4 = out->ssdpReqSock4; + } else { + out->ssdpReqSock4 = INVALID_SOCKET; + } + + // Create the IPv6 socket for SSDP REQUESTS + if( strlen( gIF_IPV6 ) > 0 ) { + retVal = create_ssdp_sock_reqv6( &out->ssdpReqSock6 ); + if( retVal != UPNP_E_SUCCESS ) { + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + return retVal; + } + // For use by ssdp control point. + gSsdpReqSocket6 = out->ssdpReqSock6; + } else { + out->ssdpReqSock6 = INVALID_SOCKET; } - ret = setsockopt( ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL, - &ttl, sizeof (ttl) ); - // just do it, regardless if fails or not. - Make_Socket_NoBlocking( ssdpReqSock ); - gSsdpReqSocket = ssdpReqSock; #endif /* INCLUDE_CLIENT_APIS */ - ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( ssdpSock == -1 ) { + // Create the IPv4 socket for SSDP + if( strlen( gIF_IPV4 ) > 0 ) { + retVal = create_ssdp_sock_v4( &out->ssdpSock4 ); + if( retVal != UPNP_E_SUCCESS ) { + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) + return retVal; + } + } else { + out->ssdpSock4 = INVALID_SOCKET; + } + + // Create the IPv6 socket for SSDP + if( strlen( gIF_IPV6 ) > 0 ) { + retVal = create_ssdp_sock_v6( &out->ssdpSock6 ); + if( retVal != UPNP_E_SUCCESS ) { + shutdown( out->ssdpSock4, SD_BOTH ); + UpnpCloseSocket( out->ssdpSock4 ); + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) + return retVal; + } + } else { + out->ssdpSock6 = INVALID_SOCKET; + } + + return UPNP_E_SUCCESS; +} + + +#if INCLUDE_CLIENT_APIS +/************************************************************************ + * Function : create_ssdp_sock_reqv4 + * + * Parameters: + * IN SOCKET* ssdpReqSock: SSDP IPv4 request socket to be created + * + * Description: + * This function creates the SSDP IPv4 socket to be used by the control + * point. + * + * Returns: + * UPNP_E_SUCCESS on successful socket creation. + ***************************************************************************/ +int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + u_char ttl = 4; + + *ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ); + if ( *ssdpReqSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + return UPNP_E_OUTOF_SOCKET; + } + + setsockopt( *ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL, + &ttl, sizeof (ttl) ); + + // just do it, regardless if fails or not. + Make_Socket_NoBlocking( *ssdpReqSock ); + + return UPNP_E_SUCCESS; +} + + +/************************************************************************ + * Function : create_ssdp_sock_reqv6 + * + * Parameters: + * IN SOCKET* ssdpReqSock: SSDP IPv6 request socket to be created + * + * Description: + * This function creates the SSDP IPv6 socket to be used by the control + * point. + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + char hops = 1; + + *ssdpReqSock = socket( AF_INET6, SOCK_DGRAM, 0 ); + if ( *ssdpReqSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + return UPNP_E_OUTOF_SOCKET; + } + + // MUST use scoping of IPv6 addresses to control the propagation os SSDP + // messages instead of relying on the Hop Limit (Equivalent to the TTL + // limit in IPv4). + setsockopt( *ssdpReqSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hops, sizeof(hops) ); + + // just do it, regardless if fails or not. + Make_Socket_NoBlocking( *ssdpReqSock ); + + return UPNP_E_SUCCESS; +} +#endif /* INCLUDE_CLIENT_APIS */ + + +/************************************************************************ + * Function : create_ssdp_sock_v4 + * + * Parameters: + * IN SOCKET* ssdpSock: SSDP IPv4 socket to be created + * + * Description: + * This function ... + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_v4( SOCKET* ssdpSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + int onOff; + u_char ttl = 4; + struct ip_mreq ssdpMcastAddr; + struct sockaddr_storage __ss; + struct sockaddr_in *ssdpAddr4 = (struct sockaddr_in *)&__ss; + int ret = 0; + struct in_addr addr; + + + *ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ); + if ( *ssdpSock == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in socket(): %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) return UPNP_E_OUTOF_SOCKET; } onOff = 1; - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEADDR, - (char *)&onOff, sizeof(onOff) ); + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEADDR, + (char*)&onOff, sizeof(onOff) ); if ( ret == -1) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } #if defined(BSD) || defined(__OSX__) || defined(__APPLE__) - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEPORT, - (char *)&onOff, sizeof (onOff) ); + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT, + (char *)&onOff, sizeof(onOff) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } #endif /* BSD */ - memset( (void *)&ssdpAddr, 0, sizeof( struct sockaddr_in ) ); - ssdpAddr.sin_family = AF_INET; - // ssdpAddr.sin_addr.s_addr = inet_addr(LOCAL_HOST); - ssdpAddr.sin_addr.s_addr = htonl( INADDR_ANY ); - ssdpAddr.sin_port = htons( SSDP_PORT ); - ret = bind( ssdpSock, (struct sockaddr *)&ssdpAddr, sizeof (ssdpAddr) ); + memset( &__ss, 0, sizeof( __ss ) ); + ssdpAddr4->sin_family = AF_INET; + ssdpAddr4->sin_addr.s_addr = htonl( INADDR_ANY ); + ssdpAddr4->sin_port = htons( SSDP_PORT ); + ret = bind( *ssdpSock, (struct sockaddr *)ssdpAddr4, sizeof(*ssdpAddr4) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in bind(), addr=0x%08X, port=%d: %s\n", INADDR_ANY, SSDP_PORT, errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_BIND; } memset( (void *)&ssdpMcastAddr, 0, sizeof (struct ip_mreq) ); - ssdpMcastAddr.imr_interface.s_addr = inet_addr( LOCAL_HOST ); + ssdpMcastAddr.imr_interface.s_addr = inet_addr( gIF_IPV4 ); ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr( SSDP_IP ); - ret = setsockopt( ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&ssdpMcastAddr, sizeof (struct ip_mreq) ); + ret = setsockopt( *ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&ssdpMcastAddr, sizeof(struct ip_mreq) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() IP_ADD_MEMBERSHIP (join multicast group): %s\n", errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } /* Set multicast interface. */ memset( (void *)&addr, 0, sizeof (struct in_addr) ); - addr.s_addr = inet_addr(LOCAL_HOST); - ret = setsockopt(ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, + addr.s_addr = inet_addr(gIF_IPV4); + ret = setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof addr); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); @@ -941,26 +1085,131 @@ get_ssdp_sockets( MiniServerSockArray * out ) } /* result is not checked becuase it will fail in WinMe and Win9x. */ - ret = setsockopt( ssdpSock, IPPROTO_IP, + ret = setsockopt( *ssdpSock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof (ttl) ); - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_BROADCAST, - (char *)&option, sizeof (option) ); + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST, + (char*)&onOff, sizeof(onOff) ); if( ret == -1) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n", errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_NETWORK_ERROR; } - CLIENTONLY( out->ssdpReqSock = ssdpReqSock; ) - out->ssdpSock = ssdpSock; + return UPNP_E_SUCCESS; +} + + +/************************************************************************ + * Function : create_ssdp_sock_v6 + * + * Parameters: + * IN SOCKET* ssdpSock: SSDP IPv6 socket to be created + * + * Description: + * This function ... + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_v6( SOCKET* ssdpSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + struct ipv6_mreq ssdpMcastAddr; + struct sockaddr_storage __ss; + struct sockaddr_in6 *ssdpAddr6 = (struct sockaddr_in6 *)&__ss; + int onOff; + int ret = 0; + + *ssdpSock = socket( AF_INET6, SOCK_DGRAM, 0 ); + if ( *ssdpSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + + return UPNP_E_OUTOF_SOCKET; + } + + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEADDR, + (char*)&onOff, sizeof(onOff) ); + if ( ret == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } + +#if defined(BSD) || defined(__OSX__) || defined(__APPLE__) + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT, + (char*)&onOff, sizeof (onOff) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } +#endif /* BSD */ + + memset( &__ss, 0, sizeof( __ss ) ); + ssdpAddr6->sin6_family = AF_INET6; + ssdpAddr6->sin6_addr = in6addr_any; + ssdpAddr6->sin6_scope_id = gIF_INDEX; + ssdpAddr6->sin6_port = htons( SSDP_PORT ); + ret = bind( *ssdpSock, (struct sockaddr *)ssdpAddr6, sizeof(*ssdpAddr6) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in bind(), addr=0x%032lX, port=%d: %s\n", + 0lu, SSDP_PORT, errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_BIND; + } + + memset( (void *)&ssdpMcastAddr, 0, sizeof(ssdpMcastAddr) ); + ssdpMcastAddr.ipv6mr_interface = gIF_INDEX; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &ssdpMcastAddr.ipv6mr_multiaddr ); + ret = setsockopt( *ssdpSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *)&ssdpMcastAddr, sizeof(ssdpMcastAddr) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() IPV6_JOIN_GROUP (join multicast group): %s\n", + errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } + + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST, + (char*)&onOff, sizeof(onOff) ); + if( ret == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n", + errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_NETWORK_ERROR; + } return UPNP_E_SUCCESS; } diff --git a/upnp/src/urlconfig/urlconfig.c b/upnp/src/urlconfig/urlconfig.c index 8b10575..50d8d24 100644 --- a/upnp/src/urlconfig/urlconfig.c +++ b/upnp/src/urlconfig/urlconfig.c @@ -60,7 +60,7 @@ * Function : addrToString * * Parameters : -* IN const struct sockaddr_in* addr ; socket address object with +* IN const struct sockaddr* addr ; socket address object with * the IP Address and port information * OUT char ipaddr_port[] ; character array which will hold the * IP Address in a string format. @@ -73,11 +73,20 @@ * Note : ************************************************************************/ static UPNP_INLINE void -addrToString( IN const struct sockaddr_in *addr, +addrToString( IN const struct sockaddr *addr, OUT char ipaddr_port[] ) { - sprintf( ipaddr_port, "%s:%d", inet_ntoa( addr->sin_addr ), - ntohs( addr->sin_port ) ); + char buf_ntop[64]; + + if( addr->sa_family == AF_INET ) { + struct sockaddr_in* sa4 = (struct sockaddr_in*)addr; + inet_ntop(AF_INET, &sa4->sin_addr, buf_ntop, sizeof(buf_ntop) ); + sprintf( ipaddr_port, "%s:%d", buf_ntop, ntohs( sa4->sin_port ) ); + } else if( addr->sa_family == AF_INET6 ) { + struct sockaddr_in6* sa6 = (struct sockaddr_in6*)addr; + inet_ntop(AF_INET6, &sa6->sin6_addr, buf_ntop, sizeof(buf_ntop) ); + sprintf( ipaddr_port, "[%s]:%d", buf_ntop, ntohs( sa6->sin6_port ) ); + } } /************************************************************************ @@ -353,7 +362,7 @@ config_description_doc( INOUT IXML_Document * doc, * * Parameters : * INOUT IXML_Document *doc ; IXML Description document -* IN const struct sockaddr_in* serverAddr ; socket address object +* IN const struct sockaddr* serverAddr ; socket address object * providing the IP address and port information * IN const char* alias ; string containing the alias * IN time_t last_modified ; time when the XML document was @@ -361,7 +370,7 @@ config_description_doc( INOUT IXML_Document * doc, * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the * document. * INOUT IXML_Document *doc:dom document whose urlbase is to be modified -* IN const struct sockaddr_in* serverAddr : ip address and port of +* IN const struct sockaddr* serverAddr : ip address and port of * the miniserver * IN const char* alias : a name to be used for the temp; e.g.:"foo.xml" * IN time_t last_modified : time @@ -380,7 +389,7 @@ config_description_doc( INOUT IXML_Document * doc, ************************************************************************/ int configure_urlbase( INOUT IXML_Document * doc, - IN const struct sockaddr_in *serverAddr, + IN const struct sockaddr *serverAddr, IN const char *alias, IN time_t last_modified, OUT char docURL[LINE_SIZE] ) diff --git a/upnp/src/uuid/uuid.c b/upnp/src/uuid/uuid.c index 9aa6333..06bae39 100644 --- a/upnp/src/uuid/uuid.c +++ b/upnp/src/uuid/uuid.c @@ -1,34 +1,39 @@ - /* - ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. - ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & - ** Digital Equipment Corporation, Maynard, Mass. - ** Copyright (c) 1998 Microsoft. - ** To anyone who acknowledges that this file is provided "AS IS" - ** without any express or implied warranty: permission to use, copy, - ** modify, and distribute this file for any purpose is hereby - ** granted without fee, provided that the above copyright notices and - ** this notice appears in all source code copies, and that none of - ** the names of Open Software Foundation, Inc., Hewlett-Packard - ** Company, or Digital Equipment Corporation be used in advertising - ** or publicity pertaining to distribution of the software without - ** specific, written prior permission. Neither Open Software - ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment - ** Corporation makes any representations about the suitability of - ** this software for any purpose. - */ +/************************************************************************** + * + * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. + * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & + * Digital Equipment Corporation, Maynard, Mass. + * Copyright (c) 1998 Microsoft. + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: permission to use, copy, + * modify, and distribute this file for any purpose is hereby + * granted without fee, provided that the above copyright notices and + * this notice appears in all source code copies, and that none of + * the names of Open Software Foundation, Inc., Hewlett-Packard + * Company, or Digital Equipment Corporation be used in advertising + * or publicity pertaining to distribution of the software without + * specific, written prior permission. Neither Open Software + * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment + * Corporation makes any representations about the suitability of + * this software for any purpose. + * + **************************************************************************/ + #include "config.h" + + +#include "uuid.h" + + +#include "UpnpInet.h" + + #include #include #include #include -#ifndef WIN32 - #include -#else - #include -#endif -#include "sysdep.h" -#include "uuid.h" + /* various forward declarations @@ -386,3 +391,4 @@ uuid_compare( uuid_upnp * u1, return 0; }; +