1 - Ported some of IPV6 code to 1.6.7.

2 - 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



git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/branches/branch-1.6.x@529 119443c7-1b9e-41f8-b6fc-b9c35fce742c
This commit is contained in:
Marcelo Roberto Jimenez 2010-03-31 17:53:16 +00:00
parent 6c8a4dd361
commit 2bcbdffd89
32 changed files with 6648 additions and 5860 deletions

View File

@ -2,6 +2,48 @@
Version 1.6.7 Version 1.6.7
******************************************************************************* *******************************************************************************
2010-03-27 Marcelo Jimenez <mroberto(at)users.sourceforge.net>
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 <mroberto(at)users.sourceforge.net> 2010-03-27 Marcelo Jimenez <mroberto(at)users.sourceforge.net>
* SF Patch Tracker [ 2836704 ] Patch for Solaris10 compilation and usage. * SF Patch Tracker [ 2836704 ] Patch for Solaris10 compilation and usage.
Submitted By: zephyrus ( zephyrus00jp ) Submitted By: zephyrus ( zephyrus00jp )

View File

@ -4,7 +4,7 @@
# #
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
# #
# (C) Copyright 2005-2007 Rémi Turboult <r3mi@users.sourceforge.net> # (C) Copyright 2005-2007 Rémi Turboult <r3mi@users.sourceforge.net>
# #
AC_PREREQ(2.60) AC_PREREQ(2.60)
@ -147,13 +147,21 @@ dnl ############################################################################
dnl # Release 1.6.7: dnl # Release 1.6.7:
dnl # "current:revision:age" dnl # "current:revision:age"
dnl # 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_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 #AC_SUBST([LT_VERSION_UPNP], [3:5:0])
dnl # dnl #
dnl ############################################################################ dnl ############################################################################
AC_SUBST([LT_VERSION_IXML], [2:4:0]) 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]) AC_SUBST([LT_VERSION_UPNP], [3:5:0])
dnl ############################################################################ dnl ############################################################################
dnl # Repeating the algorithm to place it closer to the modificatin place: 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 AC_HEADER_STDC
if test "$ac_cv_win32" = "no"; then
# libupnp code doesn't use autoconf variables yet, # libupnp code doesn't use autoconf variables yet,
# so just abort if a header file is not found. # so just abort if a header file is not found.
AC_CHECK_HEADERS( AC_CHECK_HEADERS(
@ -356,13 +381,38 @@ AC_CHECK_HEADERS(
], ],
[], [],
[AC_MSG_ERROR([required header file missing])]) [AC_MSG_ERROR([required header file missing])])
fi
# #
# Checks for typedefs, structures, and compiler characteristics # Checks for typedefs, structures, and compiler characteristics
# #
AC_C_CONST 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 <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#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
# #

View File

@ -30,19 +30,21 @@
******************************************************************************/ ******************************************************************************/
#ifndef ITHREADH #ifndef ITHREAD_H
#define ITHREADH #define ITHREAD_H
/*! /*!
* \file * \file
*/ */
#if !defined(WIN32) #if !defined(WIN32)
#include <sys/param.h> #include <sys/param.h>
#endif #endif
#include "UpnpGlobal.h" /* For EXPORT_SPEC */
#include "UpnpGlobal.h" /* For UPNP_INLINE, EXPORT_SPEC */
#ifdef __cplusplus #ifdef __cplusplus
@ -94,6 +96,7 @@ extern "C" {
***************************************************************************/ ***************************************************************************/
typedef pthread_t ithread_t; typedef pthread_t ithread_t;
/**************************************************************************** /****************************************************************************
* Name: ithread_attr_t * Name: ithread_attr_t
* *
@ -181,6 +184,95 @@ typedef pthread_rwlockattr_t ithread_rwlockattr_t;
***************************************************************************/ ***************************************************************************/
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 * Function: ithread_mutexattr_init
* *
@ -517,7 +609,6 @@ typedef pthread_rwlock_t ithread_rwlock_t;
#define ithread_cond_init pthread_cond_init #define ithread_cond_init pthread_cond_init
/**************************************************************************** /****************************************************************************
* Function: ithread_cond_signal * Function: ithread_cond_signal
* *
@ -577,22 +668,18 @@ typedef pthread_rwlock_t ithread_rwlock_t;
* Function: pthread_cond_timedwait * Function: pthread_cond_timedwait
* *
* Description: * Description:
* Atomically releases the associated mutex and waits on the condition. * Atomically releases the associated mutex and waits on the
* If the condition is not signaled in the specified time * condition.
* than the * If the condition is not signaled in the specified time than the
* call times out and returns. * call times out and returns.
* Associated mutex MUST be locked by thread before entering * Associated mutex MUST be locked by thread before entering this call.
* this call.
* Mutex is reacquired when call returns. * Mutex is reacquired when call returns.
* Parameters: * 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)
* ithread_cond_t)
* cond must be initialized * cond must be initialized
* ithread_mutex_t *mutex (must be valid non NULL pointer to * ithread_mutex_t *mutex (must be valid non NULL pointer to ithread_mutex_t)
* ithread_mutex_t)
* Mutex must be locked. * Mutex must be locked.
* const struct timespec *abstime (absolute time, measured * const struct timespec *abstime (absolute time, measured from Jan 1, 1970)
* from Jan 1, 1970)
* Returns: * Returns:
* 0 on success. ETIMEDOUT on timeout. Nonzero on failure. * 0 on success. ETIMEDOUT on timeout. Nonzero on failure.
* See man page for pthread_cond_timedwait * See man page for pthread_cond_timedwait
@ -664,6 +751,7 @@ typedef pthread_rwlock_t ithread_rwlock_t;
***************************************************************************/ ***************************************************************************/
#define ithread_exit pthread_exit #define ithread_exit pthread_exit
/**************************************************************************** /****************************************************************************
* Function: ithread_get_current_thread_id * Function: ithread_get_current_thread_id
* *
@ -687,6 +775,7 @@ typedef pthread_rwlock_t ithread_rwlock_t;
***************************************************************************/ ***************************************************************************/
#define ithread_self pthread_self #define ithread_self pthread_self
/**************************************************************************** /****************************************************************************
* Function: ithread_detach * Function: ithread_detach
* *
@ -700,6 +789,7 @@ typedef pthread_rwlock_t ithread_rwlock_t;
***************************************************************************/ ***************************************************************************/
#define ithread_detach pthread_detach #define ithread_detach pthread_detach
/**************************************************************************** /****************************************************************************
* Function: ithread_join * Function: ithread_join
* *
@ -719,7 +809,6 @@ typedef pthread_rwlock_t ithread_rwlock_t;
#define ithread_join pthread_join #define ithread_join pthread_join
/**************************************************************************** /****************************************************************************
* Function: isleep * Function: isleep
* *
@ -739,6 +828,7 @@ typedef pthread_rwlock_t ithread_rwlock_t;
#define isleep sleep #define isleep sleep
#endif #endif
/**************************************************************************** /****************************************************************************
* Function: isleep * 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); EXPORT_SPEC int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* ITHREADH */
#endif /* ITHREAD_H */

View File

@ -68,9 +68,6 @@ static unsigned long DiffMillis(struct timeval *time1, struct timeval *time2)
{ {
double temp = 0; double temp = 0;
assert(time1 != NULL);
assert(time2 != NULL);
temp = time1->tv_sec - time2->tv_sec; temp = time1->tv_sec - time2->tv_sec;
/* convert to milliseconds */ /* convert to milliseconds */
temp *= 1000; temp *= 1000;
@ -94,8 +91,6 @@ static unsigned long DiffMillis(struct timeval *time1, struct timeval *time2)
*****************************************************************************/ *****************************************************************************/
static void StatsInit(ThreadPoolStats *stats) static void StatsInit(ThreadPoolStats *stats)
{ {
assert(stats != NULL);
stats->totalIdleTime = 0; stats->totalIdleTime = 0;
stats->totalJobsHQ = 0; stats->totalJobsHQ = 0;
stats->totalJobsLQ = 0; stats->totalJobsLQ = 0;
@ -205,9 +200,6 @@ static int CmpThreadPoolJob(void *jobA, void *jobB)
ThreadPoolJob *a = (ThreadPoolJob *)jobA; ThreadPoolJob *a = (ThreadPoolJob *)jobA;
ThreadPoolJob *b = (ThreadPoolJob *)jobB; ThreadPoolJob *b = (ThreadPoolJob *)jobB;
assert(jobA != NULL);
assert(jobB != NULL);
return a->jobId == b->jobId; return a->jobId == b->jobId;
} }
@ -221,8 +213,6 @@ static int CmpThreadPoolJob(void *jobA, void *jobB)
*****************************************************************************/ *****************************************************************************/
static void FreeThreadPoolJob(ThreadPool *tp, ThreadPoolJob *tpj) static void FreeThreadPoolJob(ThreadPool *tp, ThreadPoolJob *tpj)
{ {
assert(tp != NULL);
FreeListFree(&tp->jobFreeList, tpj); FreeListFree(&tp->jobFreeList, tpj);
} }
@ -340,8 +330,6 @@ static void BumpPriority(ThreadPool *tp)
unsigned long diffTime = 0; unsigned long diffTime = 0;
ThreadPoolJob *tempJob = NULL; ThreadPoolJob *tempJob = NULL;
assert(tp != NULL);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
while (!done) { while (!done) {
if (tp->medJobQ.size) { if (tp->medJobQ.size) {
@ -389,12 +377,9 @@ static void SetRelTimeout( struct timespec *time, int relMillis )
int sec = relMillis / 1000; int sec = relMillis / 1000;
int milliSeconds = relMillis % 1000; int milliSeconds = relMillis % 1000;
assert( time != NULL );
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
time->tv_sec = now.tv_sec + sec; 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;
} }
/**************************************************************************** /****************************************************************************
@ -420,7 +405,10 @@ static void SetSeed()
srand((unsigned int)t.tv_usec + ithread_get_current_thread_id()); srand((unsigned int)t.tv_usec + ithread_get_current_thread_id());
#else #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(); idu.tid = ithread_get_current_thread_id();
srand((unsigned int)t.millitm + idu.i); srand((unsigned int)t.millitm + idu.i);
@ -453,15 +441,10 @@ static void *WorkerThread( void *arg )
int retCode = 0; int retCode = 0;
int persistent = -1; int persistent = -1;
ThreadPool *tp = (ThreadPool *) arg; ThreadPool *tp = (ThreadPool *) arg;
// allow static linking
#ifdef WIN32
#ifdef PTW32_STATIC_LIB
pthread_win32_thread_attach_np();
#endif
#endif
assert( tp != NULL );
// Increment total thread count ithread_initialize_thread();
/* Increment total thread count */
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
tp->totalThreads++; tp->totalThreads++;
ithread_cond_broadcast(&tp->start_and_shutdown); ithread_cond_broadcast(&tp->start_and_shutdown);
@ -482,71 +465,47 @@ static void *WorkerThread( void *arg )
tp->stats.totalWorkTime += ( StatsTime( NULL ) - start ); // work time tp->stats.totalWorkTime += ( StatsTime( NULL ) - start ); // work time
StatsTime( &start ); // idle time StatsTime( &start ); // idle time
if( persistent == 1 ) { if (persistent == 0) {
// Persistent thread tp->stats.workerThreads--;
// becomes a regular thread } else if (persistent == 1) {
/* Persistent thread becomes a regular thread */
tp->persistentThreads--; tp->persistentThreads--;
} }
if( persistent == 0 ) { /* Check for a job or shutdown */
tp->stats.workerThreads--;
}
// Check for a job or shutdown
while (tp->lowJobQ.size == 0 && while (tp->lowJobQ.size == 0 &&
tp->medJobQ.size == 0 && tp->medJobQ.size == 0 &&
tp->highJobQ.size == 0 && tp->highJobQ.size == 0 &&
!tp->persistentJob && !tp->persistentJob && !tp->shutdown) {
!tp->shutdown ) { /* If wait timed out and we currently have more than the
// If wait timed out * min threads, or if we have more than the max threads
// and we currently have more than the * (only possible if the attributes have been reset)
// min threads, or if we have more than the max threads * let this thread die. */
// (only possible if the attributes have been reset)
// let this thread die.
if ((retCode == ETIMEDOUT && if ((retCode == ETIMEDOUT &&
tp->totalThreads > tp->attr.minThreads) || tp->totalThreads > tp->attr.minThreads) ||
(tp->attr.maxThreads != -1 && (tp->attr.maxThreads != -1 &&
tp->totalThreads > tp->attr.maxThreads)) { tp->totalThreads > tp->attr.maxThreads)) {
tp->stats.idleThreads--; tp->stats.idleThreads--;
tp->totalThreads--; goto exit_function;
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;
} }
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( retCode = ithread_cond_timedwait(
&tp->condition, &tp->mutex, &timeout); &tp->condition, &tp->mutex, &timeout);
} }
tp->stats.idleThreads--; tp->stats.idleThreads--;
tp->stats.totalIdleTime += ( StatsTime( NULL ) - start ); // idle time /* idle time */
StatsTime( &start ); // work time tp->stats.totalIdleTime += StatsTime(NULL) - start;
/* work time */
// bump priority of starved jobs StatsTime(&start);
/* bump priority of starved jobs */
BumpPriority(tp); BumpPriority(tp);
/* if shutdown then stop */
// if shutdown then stop
if (tp->shutdown) { if (tp->shutdown) {
tp->totalThreads--; goto exit_function;
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;
} else { } else {
// Pick up persistent job if available /* Pick up persistent job if available */
if (tp->persistentJob) { if (tp->persistentJob) {
job = tp->persistentJob; job = tp->persistentJob;
tp->persistentJob = NULL; tp->persistentJob = NULL;
@ -556,7 +515,7 @@ static void *WorkerThread( void *arg )
} else { } else {
tp->stats.workerThreads++; tp->stats.workerThreads++;
persistent = 0; persistent = 0;
// Pick the highest priority job /* Pick the highest priority job */
if (tp->highJobQ.size > 0) { if (tp->highJobQ.size > 0) {
head = ListHead(&tp->highJobQ); head = ListHead(&tp->highJobQ);
job = (ThreadPoolJob *) head->item; job = (ThreadPoolJob *) head->item;
@ -573,14 +532,9 @@ static void *WorkerThread( void *arg )
CalcWaitTime(tp, LOW_PRIORITY, job); CalcWaitTime(tp, LOW_PRIORITY, job);
ListDelNode(&tp->lowJobQ, head, 0); ListDelNode(&tp->lowJobQ, head, 0);
} else { } else {
// Should never get here /* Should never get here */
assert( 0 );
tp->stats.workerThreads--; tp->stats.workerThreads--;
tp->totalThreads--; goto exit_function;
ithread_cond_broadcast( &tp->start_and_shutdown );
ithread_mutex_unlock( &tp->mutex );
return NULL;
} }
} }
} }
@ -588,20 +542,23 @@ static void *WorkerThread( void *arg )
tp->busyThreads++; tp->busyThreads++;
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
/* In the future can log info */
if (SetPriority(job->priority) != 0) { if (SetPriority(job->priority) != 0) {
// In the future can log
// info
} else { } else {
// In the future can log
// info
} }
/* run the job */
// run the job
job->func(job->arg); job->func(job->arg);
/* return to Normal */
// return to Normal
SetPriority(DEFAULT_PRIORITY); SetPriority(DEFAULT_PRIORITY);
} }
exit_function:
tp->totalThreads--;
ithread_cond_broadcast(&tp->start_and_shutdown);
ithread_mutex_unlock(&tp->mutex);
ithread_cleanup_thread();
return NULL;
} }
/**************************************************************************** /****************************************************************************
@ -621,9 +578,6 @@ static ThreadPoolJob *CreateThreadPoolJob( ThreadPoolJob *job, int id, ThreadPoo
{ {
ThreadPoolJob *newJob = NULL; ThreadPoolJob *newJob = NULL;
assert( job != NULL );
assert( tp != NULL );
newJob = (ThreadPoolJob *)FreeListAlloc(&tp->jobFreeList); newJob = (ThreadPoolJob *)FreeListAlloc(&tp->jobFreeList);
if (newJob) { if (newJob) {
*newJob = *job; *newJob = *job;
@ -656,13 +610,10 @@ static int CreateWorker( ThreadPool *tp )
int rc = 0; int rc = 0;
int currentThreads = tp->totalThreads + 1; int currentThreads = tp->totalThreads + 1;
assert( tp != NULL );
if (tp->attr.maxThreads != INFINITE_THREADS && if (tp->attr.maxThreads != INFINITE_THREADS &&
currentThreads > tp->attr.maxThreads) { currentThreads > tp->attr.maxThreads) {
return EMAXTHREADS; return EMAXTHREADS;
} }
rc = ithread_create(&temp, NULL, WorkerThread, tp); rc = ithread_create(&temp, NULL, WorkerThread, tp);
if (rc == 0) { if (rc == 0) {
rc = ithread_detach(temp); rc = ithread_detach(temp);
@ -670,7 +621,6 @@ static int CreateWorker( ThreadPool *tp )
ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); 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; tp->stats.maxThreads = tp->totalThreads;
} }
@ -695,8 +645,6 @@ static void AddWorker(ThreadPool *tp)
int jobs = 0; int jobs = 0;
int threads = 0; int threads = 0;
assert( tp != NULL );
jobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size; jobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size;
threads = tp->totalThreads - tp->persistentThreads; threads = tp->totalThreads - tp->persistentThreads;
while (threads == 0 || while (threads == 0 ||
@ -746,62 +694,38 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr )
int retCode = 0; int retCode = 0;
int i = 0; int i = 0;
assert( tp != NULL ); if (!tp) {
if( tp == NULL ) {
return EINVAL; return EINVAL;
} }
#ifdef WIN32
#ifdef PTW32_STATIC_LIB
pthread_win32_process_attach_np();
#endif
#endif
retCode += ithread_mutex_init(&tp->mutex, NULL); retCode += ithread_mutex_init(&tp->mutex, NULL);
assert( retCode == 0 );
retCode += ithread_mutex_lock(&tp->mutex); retCode += ithread_mutex_lock(&tp->mutex);
assert( retCode == 0 );
retCode += ithread_cond_init(&tp->condition, NULL); retCode += ithread_cond_init(&tp->condition, NULL);
assert( retCode == 0 );
retCode += ithread_cond_init(&tp->start_and_shutdown, NULL); retCode += ithread_cond_init(&tp->start_and_shutdown, NULL);
assert( retCode == 0 ); if (retCode) {
if( retCode != 0 ) {
return EAGAIN; return EAGAIN;
} }
if (attr) { if (attr) {
tp->attr = ( *attr ); tp->attr = *attr;
} else { } else {
TPAttrInit(&tp->attr); TPAttrInit(&tp->attr);
} }
if (SetPolicyType(tp->attr.schedPolicy) != 0) { if (SetPolicyType(tp->attr.schedPolicy) != 0) {
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
ithread_mutex_destroy(&tp->mutex); ithread_mutex_destroy(&tp->mutex);
ithread_cond_destroy(&tp->condition); ithread_cond_destroy(&tp->condition);
ithread_cond_destroy(&tp->start_and_shutdown); ithread_cond_destroy(&tp->start_and_shutdown);
return INVALID_POLICY; return INVALID_POLICY;
} }
retCode += FreeListInit( retCode += FreeListInit(
&tp->jobFreeList, sizeof(ThreadPoolJob), JOBFREELISTSIZE); &tp->jobFreeList, sizeof(ThreadPoolJob), JOBFREELISTSIZE);
assert( retCode == 0 );
StatsInit(&tp->stats); StatsInit(&tp->stats);
retCode += ListInit(&tp->highJobQ, CmpThreadPoolJob, NULL); retCode += ListInit(&tp->highJobQ, CmpThreadPoolJob, NULL);
assert( retCode == 0 );
retCode += ListInit(&tp->medJobQ, CmpThreadPoolJob, NULL); retCode += ListInit(&tp->medJobQ, CmpThreadPoolJob, NULL);
assert( retCode == 0 );
retCode += ListInit(&tp->lowJobQ, CmpThreadPoolJob, NULL); retCode += ListInit(&tp->lowJobQ, CmpThreadPoolJob, NULL);
assert( retCode == 0 ); if (retCode) {
if( retCode != 0 ) {
retCode = EAGAIN; retCode = EAGAIN;
} else { } else {
tp->persistentJob = NULL; tp->persistentJob = NULL;
@ -811,7 +735,8 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr )
tp->busyThreads = 0; tp->busyThreads = 0;
tp->persistentThreads = 0; tp->persistentThreads = 0;
for (i = 0; i < tp->attr.minThreads; ++i) { for (i = 0; i < tp->attr.minThreads; ++i) {
if( ( retCode = CreateWorker( tp ) ) != 0 ) { retCode = CreateWorker(tp);
if (retCode) {
break; break;
} }
} }
@ -819,8 +744,8 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr )
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
if( retCode != 0 ) { if (retCode) {
// clean up if the min threads could not be created /* clean up if the min threads could not be created */
ThreadPoolShutdown(tp); ThreadPoolShutdown(tp);
} }
@ -848,59 +773,51 @@ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr )
*****************************************************************************/ *****************************************************************************/
int ThreadPoolAddPersistent(ThreadPool *tp, ThreadPoolJob *job, int *jobId) int ThreadPoolAddPersistent(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
{ {
int ret = 0;
int tempId = -1; int tempId = -1;
ThreadPoolJob *temp = NULL; ThreadPoolJob *temp = NULL;
assert( tp != NULL ); if (!tp || !job) {
assert( job != NULL );
if( ( tp == NULL ) || ( job == NULL ) ) {
return EINVAL; return EINVAL;
} }
if (!jobId) {
if( jobId == NULL ) {
jobId = &tempId; jobId = &tempId;
} }
*jobId = INVALID_JOB_ID; *jobId = INVALID_JOB_ID;
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
assert( job->priority == LOW_PRIORITY || /* Create A worker if less than max threads running */
job->priority == MED_PRIORITY ||
job->priority == HIGH_PRIORITY );
// Create A worker if less than max threads running
if (tp->totalThreads < tp->attr.maxThreads) { if (tp->totalThreads < tp->attr.maxThreads) {
CreateWorker(tp); CreateWorker(tp);
} else { } else {
// if there is more than one worker thread /* if there is more than one worker thread
// available then schedule job, otherwise fail * available then schedule job, otherwise fail */
if (tp->totalThreads - tp->persistentThreads - 1 == 0) { if (tp->totalThreads - tp->persistentThreads - 1 == 0) {
ithread_mutex_unlock( &tp->mutex ); ret = EMAXTHREADS;
return EMAXTHREADS; goto exit_function;
} }
} }
temp = CreateThreadPoolJob(job, tp->lastJobId, tp); temp = CreateThreadPoolJob(job, tp->lastJobId, tp);
if( temp == NULL ) { if (!temp) {
ithread_mutex_unlock( &tp->mutex ); ret = EOUTOFMEM;
return EOUTOFMEM; goto exit_function;
} }
tp->persistentJob = temp; tp->persistentJob = temp;
// Notify a waiting thread /* Notify a waiting thread */
ithread_cond_signal(&tp->condition); ithread_cond_signal(&tp->condition);
// wait until long job has been picked up /* wait until long job has been picked up */
while( tp->persistentJob != NULL ) { while (tp->persistentJob) {
ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex);
} }
*jobId = tp->lastJobId++; *jobId = tp->lastJobId++;
exit_function:
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
return 0; return ret;
} }
/**************************************************************************** /****************************************************************************
@ -924,42 +841,29 @@ int ThreadPoolAddPersistent( ThreadPool *tp, ThreadPoolJob *job, int *jobId )
int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId) int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
{ {
int rc = EOUTOFMEM; int rc = EOUTOFMEM;
int tempId = -1; int tempId = -1;
int totalJobs; int totalJobs;
ThreadPoolJob *temp = NULL; ThreadPoolJob *temp = NULL;
assert( tp != NULL ); if (!tp || !job) {
assert( job != NULL );
if( ( tp == NULL ) || ( job == NULL ) ) {
return EINVAL; return EINVAL;
} }
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
assert( job->priority == LOW_PRIORITY ||
job->priority == MED_PRIORITY ||
job->priority == HIGH_PRIORITY );
totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size; totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size;
if (totalJobs >= tp->attr.maxJobsTotal) { if (totalJobs >= tp->attr.maxJobsTotal) {
fprintf(stderr, "total jobs = %d, too many jobs", totalJobs); fprintf(stderr, "total jobs = %d, too many jobs", totalJobs);
ithread_mutex_unlock( &tp->mutex ); goto exit_function;
return rc;
} }
if (!jobId) {
if( jobId == NULL ) {
jobId = &tempId; jobId = &tempId;
} }
*jobId = INVALID_JOB_ID; *jobId = INVALID_JOB_ID;
temp = CreateThreadPoolJob(job, tp->lastJobId, tp); temp = CreateThreadPoolJob(job, tp->lastJobId, tp);
if( temp == NULL ) { if (!temp) {
ithread_mutex_unlock( &tp->mutex ); goto exit_function;
return rc;
} }
if (job->priority == HIGH_PRIORITY) { if (job->priority == HIGH_PRIORITY) {
if (ListAddTail(&tp->highJobQ, temp)) { if (ListAddTail(&tp->highJobQ, temp)) {
rc = 0; rc = 0;
@ -974,10 +878,10 @@ int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId )
} }
} }
// AddWorker if appropriate /* AddWorker if appropriate */
AddWorker(tp); AddWorker(tp);
// Notify a waiting thread /* Notify a waiting thread */
if (rc == 0) { if (rc == 0) {
ithread_cond_signal(&tp->condition); ithread_cond_signal(&tp->condition);
} else { } else {
@ -986,6 +890,7 @@ int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId )
*jobId = tp->lastJobId++; *jobId = tp->lastJobId++;
exit_function:
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
return rc; return rc;
@ -1009,20 +914,17 @@ int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId )
*****************************************************************************/ *****************************************************************************/
int ThreadPoolRemove(ThreadPool *tp, int jobId, ThreadPoolJob *out) int ThreadPoolRemove(ThreadPool *tp, int jobId, ThreadPoolJob *out)
{ {
ThreadPoolJob *temp = NULL;
int ret = INVALID_JOB_ID; int ret = INVALID_JOB_ID;
ThreadPoolJob *temp = NULL;
ListNode *tempNode = NULL; ListNode *tempNode = NULL;
ThreadPoolJob dummy; ThreadPoolJob dummy;
assert( tp != NULL ); if (!tp) {
if( tp == NULL ) {
return EINVAL; return EINVAL;
} }
if (!out) {
if( out == NULL ) {
out = &dummy; out = &dummy;
} }
dummy.jobId = jobId; dummy.jobId = jobId;
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
@ -1033,9 +935,8 @@ int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out )
*out = *temp; *out = *temp;
ListDelNode(&tp->highJobQ, tempNode, 0); ListDelNode(&tp->highJobQ, tempNode, 0);
FreeThreadPoolJob(tp, temp); FreeThreadPoolJob(tp, temp);
ithread_mutex_unlock( &tp->mutex ); ret = 0;
goto exit_function;
return 0;
} }
tempNode = ListFind(&tp->medJobQ, NULL, &dummy); tempNode = ListFind(&tp->medJobQ, NULL, &dummy);
@ -1044,31 +945,27 @@ int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out )
*out = *temp; *out = *temp;
ListDelNode(&tp->medJobQ, tempNode, 0); ListDelNode(&tp->medJobQ, tempNode, 0);
FreeThreadPoolJob(tp, temp); FreeThreadPoolJob(tp, temp);
ithread_mutex_unlock( &tp->mutex ); ret = 0;
goto exit_function;
return 0;
} }
tempNode = ListFind(&tp->lowJobQ, NULL, &dummy); tempNode = ListFind(&tp->lowJobQ, NULL, &dummy);
if (tempNode) { if (tempNode) {
temp = (ThreadPoolJob *)tempNode->item; temp = (ThreadPoolJob *)tempNode->item;
*out = *temp; *out = *temp;
ListDelNode(&tp->lowJobQ, tempNode, 0); ListDelNode(&tp->lowJobQ, tempNode, 0);
FreeThreadPoolJob(tp, temp); FreeThreadPoolJob(tp, temp);
ithread_mutex_unlock( &tp->mutex ); ret = 0;
goto exit_function;
return 0;
} }
if (tp->persistentJob && tp->persistentJob->jobId == jobId) { if (tp->persistentJob && tp->persistentJob->jobId == jobId) {
*out = *tp->persistentJob; *out = *tp->persistentJob;
FreeThreadPoolJob(tp, tp->persistentJob); FreeThreadPoolJob(tp, tp->persistentJob);
tp->persistentJob = NULL; tp->persistentJob = NULL;
ithread_mutex_unlock( &tp->mutex ); ret = 0;
goto exit_function;
return 0;
} }
exit_function:
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
return ret; return ret;
@ -1089,18 +986,13 @@ int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out )
*****************************************************************************/ *****************************************************************************/
int ThreadPoolGetAttr(ThreadPool *tp, ThreadPoolAttr *out) int ThreadPoolGetAttr(ThreadPool *tp, ThreadPoolAttr *out)
{ {
assert( tp != NULL ); if (!tp || !out) {
assert( out != NULL );
if( tp == NULL || out == NULL ) {
return EINVAL; return EINVAL;
} }
if (!tp->shutdown) { if (!tp->shutdown) {
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
} }
*out = tp->attr; *out = tp->attr;
if (!tp->shutdown) { if (!tp->shutdown) {
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
} }
@ -1127,42 +1019,39 @@ int ThreadPoolSetAttr( ThreadPool *tp, ThreadPoolAttr *attr )
ThreadPoolAttr temp; ThreadPoolAttr temp;
int i = 0; int i = 0;
assert( tp != NULL ); if (!tp) {
if( tp == NULL ) {
return EINVAL; return EINVAL;
} }
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
if( attr != NULL ) { if (attr) {
temp = ( *attr ); temp = *attr;
} else { } else {
TPAttrInit(&temp); TPAttrInit(&temp);
} }
if (SetPolicyType(temp.schedPolicy) != 0) { if (SetPolicyType(temp.schedPolicy) != 0) {
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
return INVALID_POLICY; return INVALID_POLICY;
} }
tp->attr = temp;
tp->attr = ( temp ); /* add threads */
if (tp->totalThreads < tp->attr.minThreads) {
// add threads
if( tp->totalThreads < tp->attr.minThreads )
{
for (i = tp->totalThreads; i < tp->attr.minThreads; i++) { for (i = tp->totalThreads; i < tp->attr.minThreads; i++) {
if( ( retCode = CreateWorker( tp ) ) != 0 ) { retCode = CreateWorker(tp);
if (retCode != 0) {
break; break;
} }
} }
} }
/* signal changes */
// signal changes
ithread_cond_signal(&tp->condition); ithread_cond_signal(&tp->condition);
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
if (retCode != 0) { if (retCode != 0) {
// clean up if the min threads could not be created /* clean up if the min threads could not be created */
ThreadPoolShutdown(tp); ThreadPoolShutdown(tp);
} }
@ -1188,14 +1077,13 @@ int ThreadPoolShutdown( ThreadPool *tp )
ListNode *head = NULL; ListNode *head = NULL;
ThreadPoolJob *temp = NULL; ThreadPoolJob *temp = NULL;
assert( tp != NULL ); if (!tp) {
if( tp == NULL ) {
return EINVAL; return EINVAL;
} }
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
// clean up high priority jobs /* clean up high priority jobs */
while (tp->highJobQ.size) { while (tp->highJobQ.size) {
head = ListHead(&tp->highJobQ); head = ListHead(&tp->highJobQ);
temp = (ThreadPoolJob *)head->item; temp = (ThreadPoolJob *)head->item;
@ -1207,7 +1095,7 @@ int ThreadPoolShutdown( ThreadPool *tp )
} }
ListDestroy(&tp->highJobQ, 0); ListDestroy(&tp->highJobQ, 0);
// clean up med priority jobs /* clean up med priority jobs */
while (tp->medJobQ.size) { while (tp->medJobQ.size) {
head = ListHead(&tp->medJobQ); head = ListHead(&tp->medJobQ);
temp = (ThreadPoolJob *)head->item; temp = (ThreadPoolJob *)head->item;
@ -1219,7 +1107,7 @@ int ThreadPoolShutdown( ThreadPool *tp )
} }
ListDestroy(&tp->medJobQ, 0); ListDestroy(&tp->medJobQ, 0);
// clean up low priority jobs /* clean up low priority jobs */
while (tp->lowJobQ.size) { while (tp->lowJobQ.size) {
head = ListHead(&tp->lowJobQ); head = ListHead(&tp->lowJobQ);
temp = (ThreadPoolJob *)head->item; temp = (ThreadPoolJob *)head->item;
@ -1231,7 +1119,7 @@ int ThreadPoolShutdown( ThreadPool *tp )
} }
ListDestroy(&tp->lowJobQ, 0); ListDestroy(&tp->lowJobQ, 0);
// clean up long term job /* clean up long term job */
if (tp->persistentJob) { if (tp->persistentJob) {
temp = tp->persistentJob; temp = tp->persistentJob;
if (temp->free_func) { if (temp->free_func) {
@ -1240,28 +1128,27 @@ int ThreadPoolShutdown( ThreadPool *tp )
FreeThreadPoolJob(tp, temp); FreeThreadPoolJob(tp, temp);
tp->persistentJob = NULL; tp->persistentJob = NULL;
} }
/* signal shutdown */
// signal shutdown
tp->shutdown = 1; tp->shutdown = 1;
ithread_cond_broadcast(&tp->condition); ithread_cond_broadcast(&tp->condition);
/* wait for all threads to finish */
// wait for all threads to finish
while (tp->totalThreads > 0) { while (tp->totalThreads > 0) {
ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex);
} }
/* destroy condition */
// destroy condition
while (ithread_cond_destroy(&tp->condition) != 0) { 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 /* destroy mutex */
while (ithread_mutex_destroy(&tp->mutex) != 0) { while (ithread_mutex_destroy(&tp->mutex) != 0) {
/**/
} }
return 0; return 0;
@ -1280,11 +1167,9 @@ int ThreadPoolShutdown( ThreadPool *tp )
*****************************************************************************/ *****************************************************************************/
int TPAttrInit(ThreadPoolAttr *attr) int TPAttrInit(ThreadPoolAttr *attr)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->jobsPerThread = DEFAULT_JOBS_PER_THREAD; attr->jobsPerThread = DEFAULT_JOBS_PER_THREAD;
attr->maxIdleTime = DEFAULT_IDLE_TIME; attr->maxIdleTime = DEFAULT_IDLE_TIME;
attr->maxThreads = DEFAULT_MAX_THREADS; attr->maxThreads = DEFAULT_MAX_THREADS;
@ -1312,12 +1197,9 @@ int TPAttrInit( ThreadPoolAttr *attr )
*****************************************************************************/ *****************************************************************************/
int TPJobInit(ThreadPoolJob *job, start_routine func, void *arg) int TPJobInit(ThreadPoolJob *job, start_routine func, void *arg)
{ {
assert( job != NULL ); if (!job || !func) {
assert( func != NULL );
if( job == NULL || func == NULL ) {
return EINVAL; return EINVAL;
} }
job->func = func; job->func = func;
job->arg = arg; job->arg = arg;
job->priority = DEFAULT_PRIORITY; job->priority = DEFAULT_PRIORITY;
@ -1340,11 +1222,9 @@ int TPJobInit( ThreadPoolJob *job, start_routine func, void *arg )
*****************************************************************************/ *****************************************************************************/
int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority) int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority)
{ {
assert( job != NULL ); if (!job) {
if( job == NULL ) {
return EINVAL; return EINVAL;
} }
if (priority == LOW_PRIORITY || if (priority == LOW_PRIORITY ||
priority == MED_PRIORITY || priority == MED_PRIORITY ||
priority == HIGH_PRIORITY) { priority == HIGH_PRIORITY) {
@ -1368,11 +1248,9 @@ int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority )
*****************************************************************************/ *****************************************************************************/
int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func) int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func)
{ {
assert( job != NULL ); if(!job) {
if( job == NULL ) {
return EINVAL; return EINVAL;
} }
job->free_func = func; job->free_func = func;
return 0; return 0;
@ -1391,11 +1269,9 @@ int TPJobSetFreeFunction( ThreadPoolJob *job, free_routine func )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetMaxThreads(ThreadPoolAttr *attr, int maxThreads) int TPAttrSetMaxThreads(ThreadPoolAttr *attr, int maxThreads)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->maxThreads = maxThreads; attr->maxThreads = maxThreads;
return 0; return 0;
@ -1414,11 +1290,9 @@ int TPAttrSetMaxThreads( ThreadPoolAttr *attr, int maxThreads )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetMinThreads(ThreadPoolAttr *attr, int minThreads) int TPAttrSetMinThreads(ThreadPoolAttr *attr, int minThreads)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->minThreads = minThreads; attr->minThreads = minThreads;
return 0; return 0;
@ -1436,11 +1310,9 @@ int TPAttrSetMinThreads( ThreadPoolAttr *attr, int minThreads )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetIdleTime(ThreadPoolAttr *attr, int idleTime) int TPAttrSetIdleTime(ThreadPoolAttr *attr, int idleTime)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->maxIdleTime = idleTime; attr->maxIdleTime = idleTime;
return 0; return 0;
@ -1458,11 +1330,9 @@ int TPAttrSetIdleTime( ThreadPoolAttr *attr, int idleTime )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetJobsPerThread(ThreadPoolAttr *attr, int jobsPerThread) int TPAttrSetJobsPerThread(ThreadPoolAttr *attr, int jobsPerThread)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->jobsPerThread = jobsPerThread; attr->jobsPerThread = jobsPerThread;
return 0; return 0;
@ -1480,11 +1350,9 @@ int TPAttrSetJobsPerThread( ThreadPoolAttr *attr, int jobsPerThread )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetStarvationTime(ThreadPoolAttr *attr, int starvationTime) int TPAttrSetStarvationTime(ThreadPoolAttr *attr, int starvationTime)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->starvationTime = starvationTime; attr->starvationTime = starvationTime;
return 0; return 0;
@ -1503,11 +1371,9 @@ int TPAttrSetStarvationTime( ThreadPoolAttr *attr, int starvationTime )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetSchedPolicy(ThreadPoolAttr *attr, PolicyType schedPolicy) int TPAttrSetSchedPolicy(ThreadPoolAttr *attr, PolicyType schedPolicy)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->schedPolicy = schedPolicy; attr->schedPolicy = schedPolicy;
return 0; return 0;
@ -1526,11 +1392,9 @@ int TPAttrSetSchedPolicy( ThreadPoolAttr *attr, PolicyType schedPolicy )
*****************************************************************************/ *****************************************************************************/
int TPAttrSetMaxJobsTotal(ThreadPoolAttr *attr, int maxJobsTotal) int TPAttrSetMaxJobsTotal(ThreadPoolAttr *attr, int maxJobsTotal)
{ {
assert( attr != NULL ); if (!attr) {
if( attr == NULL ) {
return EINVAL; return EINVAL;
} }
attr->maxJobsTotal = maxJobsTotal; attr->maxJobsTotal = maxJobsTotal;
return 0; return 0;
@ -1540,11 +1404,9 @@ int TPAttrSetMaxJobsTotal( ThreadPoolAttr *attr, int maxJobsTotal )
#ifdef STATS #ifdef STATS
void ThreadPoolPrintStats(ThreadPoolStats *stats) void ThreadPoolPrintStats(ThreadPoolStats *stats)
{ {
assert( stats != NULL ); if (!stats) {
if (stats == NULL) {
return; return;
} }
/* some OSses time_t length may depending on platform, promote it to long for safety */ /* 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("ThreadPoolStats at Time: %ld\n", (long)StatsTime(NULL));
printf("High Jobs pending: %d\n", stats->currentJobsHQ); printf("High Jobs pending: %d\n", stats->currentJobsHQ);
@ -1580,13 +1442,11 @@ void ThreadPoolPrintStats(ThreadPoolStats *stats)
#ifdef STATS #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) { if (tp == NULL || stats == NULL) {
return EINVAL; return EINVAL;
} }
//if not shutdown then acquire mutex /* if not shutdown then acquire mutex */
if (!tp->shutdown) { if (!tp->shutdown) {
ithread_mutex_lock(&tp->mutex); ithread_mutex_lock(&tp->mutex);
} }
@ -1597,26 +1457,22 @@ int ThreadPoolGetStats( ThreadPool *tp, ThreadPoolStats *stats )
} else { } else {
stats->avgWaitHQ = 0; stats->avgWaitHQ = 0;
} }
if (stats->totalJobsMQ > 0) { if (stats->totalJobsMQ > 0) {
stats->avgWaitMQ = stats->totalTimeMQ / stats->totalJobsMQ; stats->avgWaitMQ = stats->totalTimeMQ / stats->totalJobsMQ;
} else { } else {
stats->avgWaitMQ = 0; stats->avgWaitMQ = 0;
} }
if (stats->totalJobsLQ > 0) { if (stats->totalJobsLQ > 0) {
stats->avgWaitLQ = stats->totalTimeLQ / stats->totalJobsLQ; stats->avgWaitLQ = stats->totalTimeLQ / stats->totalJobsLQ;
} else { } else {
stats->avgWaitLQ = 0; stats->avgWaitLQ = 0;
} }
stats->totalThreads = tp->totalThreads; stats->totalThreads = tp->totalThreads;
stats->persistentThreads = tp->persistentThreads; stats->persistentThreads = tp->persistentThreads;
stats->currentJobsHQ = ListSize( &tp->highJobQ ); stats->currentJobsHQ = ListSize( &tp->highJobQ );
stats->currentJobsLQ = ListSize( &tp->lowJobQ ); stats->currentJobsLQ = ListSize( &tp->lowJobQ );
stats->currentJobsMQ = ListSize( &tp->medJobQ ); stats->currentJobsMQ = ListSize( &tp->medJobQ );
/* if not shutdown then release mutex */
//if not shutdown then release mutex
if (!tp->shutdown) { if (!tp->shutdown) {
ithread_mutex_unlock(&tp->mutex); ithread_mutex_unlock(&tp->mutex);
} }
@ -1628,6 +1484,7 @@ int ThreadPoolGetStats( ThreadPool *tp, ThreadPoolStats *stats )
#ifdef WIN32 #ifdef WIN32
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else #else
@ -1640,8 +1497,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
unsigned __int64 tmpres = 0; unsigned __int64 tmpres = 0;
static int tzflag; static int tzflag;
if (NULL != tv) if (tv) {
{
GetSystemTimeAsFileTime(&ft); GetSystemTimeAsFileTime(&ft);
tmpres |= ft.dwHighDateTime; tmpres |= ft.dwHighDateTime;
@ -1654,11 +1510,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_sec = (long)(tmpres / 1000000UL);
tv->tv_usec = (long)(tmpres % 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL);
} }
if (tz) {
if (NULL != tz) if (!tzflag) {
{
if (!tzflag)
{
_tzset(); _tzset();
tzflag++; tzflag++;
} }
@ -1669,3 +1522,4 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
return 0; return 0;
} }
#endif /* WIN32 */ #endif /* WIN32 */

View File

@ -73,6 +73,7 @@ libupnp_la_SOURCES = \
src/inc/util.h \ src/inc/util.h \
src/inc/utilall.h \ src/inc/utilall.h \
src/inc/uuid.h \ src/inc/uuid.h \
src/inc/VirtualDir.h \
src/inc/webserver.h src/inc/webserver.h
# ssdp # ssdp

View File

@ -644,7 +644,7 @@ struct Upnp_Action_Request
IXML_Document *ActionResult; IXML_Document *ActionResult;
/** IP address of the control point requesting this action. */ /** 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 DOM document containing the information from the
the SOAP header. */ the SOAP header. */
@ -691,7 +691,7 @@ struct Upnp_State_Var_Request
char StateVarName[NAME_SIZE]; char StateVarName[NAME_SIZE];
/** IP address of sender requesting the state variable. */ /** 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 current value of the variable. This needs to be allocated by
* the caller. When finished with it, the SDK frees this {\bf DOMString}. */ * the caller. When finished with it, the SDK frees this {\bf DOMString}. */
@ -837,112 +837,9 @@ struct File_Info
/** The content type of the file. This string needs to be allocated /** The content type of the file. This string needs to be allocated
* by the caller using {\bf ixmlCloneDOMString}. When finished * by the caller using {\bf ixmlCloneDOMString}. When finished
* with it, the SDK frees the {\bf DOMString}. */ * with it, the SDK frees the {\bf DOMString}. */
DOMString content_type; 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. /** All callback functions share the same prototype, documented below.
* Note that any memory passed to the callback function * 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 * \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. * 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 * It should be called only once. Subsequent calls to this API return a
* \c UPNP_E_INIT error code. * \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 * 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 * all UPnP operations. Since a port number can be used only by one
* process, multiple processes using the SDK must specify * process, multiple processes using the SDK must specify
* different port numbers. * 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. * and an arbitrary port.
* *
* This call is synchronous. * This call is synchronous.
@ -1025,14 +922,55 @@ extern "C" {
* \li \c UPNP_E_INTERNAL_ERROR: An internal error ocurred. * \li \c UPNP_E_INTERNAL_ERROR: An internal error ocurred.
*/ */
EXPORT_SPEC int UpnpInit( EXPORT_SPEC int UpnpInit(
/*! The host local IP address to use, in string format, for example /*! The host local IPv4 address to use, in string format, for example
* "192.168.0.1", or \c NULL to use the first adapter's IP address. */ * "192.168.0.1", or \c NULL to use the first IPv4 adapter's IP address. */
const char *HostIP, const char *HostIP,
/*! Local Port to listen for incoming connections /*! Local Port to listen for incoming connections
* \c NULL will pick an arbitrary free port. */ * \c NULL will pick an arbitrary free port. */
unsigned short DestPort); 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. * \brief Terminates the Linux SDK for UPnP Devices.
@ -1070,6 +1008,19 @@ EXPORT_SPEC int UpnpFinish(void);
EXPORT_SPEC unsigned short UpnpGetServerPort(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. * \brief Returns the local IPv4 listening ip address.
* *
@ -1084,6 +1035,20 @@ EXPORT_SPEC unsigned short UpnpGetServerPort(void);
EXPORT_SPEC char *UpnpGetServerIpAddress(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. * \brief Registers a device application with the UPnP Library.
* *
@ -1220,6 +1185,56 @@ EXPORT_SPEC int UpnpRegisterRootDevice2(
UpnpDevice_Handle* Hnd); 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 * \brief Unregisters a root device registered with \b UpnpRegisterRootDevice or
* \b UpnpRegisterRootDevice2. * \b UpnpRegisterRootDevice2.
@ -2592,6 +2607,147 @@ EXPORT_SPEC int UpnpSetWebServerRootDir(
const char *rootDir); 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. * \brief Enables or disables the webserver.
* *

View File

@ -7,12 +7,12 @@
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
@ -33,25 +33,34 @@
#ifndef UPNP_DEBUG_H #ifndef UPNP_DEBUG_H
#define UPNP_DEBUG_H #define UPNP_DEBUG_H
#include "upnp.h"
/*!
* \file
*/
#include "ThreadPool.h"
#include "upnpconfig.h" #include "upnpconfig.h"
#include "UpnpGlobal.h" /* for UPNP_INLINE */
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** @name Other debugging features /** \name Other debugging features
The UPnP SDK contains other features to aid in debugging. *
* 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, * 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 * The critical level will show only those messages
* which can halt the normal processing of the library, like memory * which can halt the normal processing of the library, like memory
* allocation errors. The remaining three levels are just for debugging * allocation errors. The remaining three levels are just for debugging
@ -60,14 +69,11 @@ extern "C" {
* Info Level displays the other important operational information * Info Level displays the other important operational information
* regarding the working of the library. If the user selects All, * regarding the working of the library. If the user selects All,
* then the library displays all the debugging information that it has. * then the library displays all the debugging information that it has.
* \begin{itemize} * \li \c UPNP_CRITICAL [0]
* \item {\tt UPNP_CRITICAL [0]} * \li \c UPNP_PACKET [1]
* \item {\tt UPNP_PACKET [1]} * \li \c UPNP_INFO [2]
* \item {\tt UPNP_INFO [2]} * \li \c UPNP_ALL [3]
* \item {\tt UPNP_ALL [3]}
* \end{itemize}
*/ */
typedef enum Upnp_Module { typedef enum Upnp_Module {
SSDP, SSDP,
SOAP, SOAP,
@ -79,67 +85,54 @@ typedef enum Upnp_Module {
HTTP HTTP
} Dbg_Module; } Dbg_Module;
/*! @{ */
/*@{*/
typedef enum Upnp_LogLevel_e { typedef enum Upnp_LogLevel_e {
UPNP_CRITICAL, UPNP_CRITICAL,
UPNP_PACKET, UPNP_PACKET,
UPNP_INFO, UPNP_INFO,
UPNP_ALL UPNP_ALL
} Upnp_LogLevel; } Upnp_LogLevel;
/*! @} */ /*@}*/
/** /**
* Default log level : see {\tt Upnp_LogLevel} * Default log level : see \c Upnp_LogLevel
*/ */
#define UPNP_DEFAULT_LOG_LEVEL UPNP_ALL #define UPNP_DEFAULT_LOG_LEVEL UPNP_ALL
/*************************************************************************** /*!
* Function : UpnpInitLog * \brief Initialize the log files.
* *
* Parameters: void * \return -1 if fails or UPNP_E_SUCCESS if succeeds.
* */
* Description:
* This functions initializes the log files
*
* Returns: int
* -1 : If fails
* UPNP_E_SUCCESS : if success
***************************************************************************/
#ifdef DEBUG #ifdef DEBUG
int UpnpInitLog(void); int UpnpInitLog(void);
#else #else
static UPNP_INLINE int UpnpInitLog(void) { return UPNP_E_SUCCESS; } static UPNP_INLINE int UpnpInitLog(void)
{
return UPNP_E_SUCCESS;
}
#endif #endif
/*************************************************************************** /*!
* Function : UpnpSetLogLevel * \brief Set the log level (see \c Upnp_LogLevel).
* */
* Parameters: Upnp_LogLevel log_level
*
* Description:
* This functions set the log level (see {\tt Upnp_LogLevel}
* Returns: void
***************************************************************************/
#ifdef DEBUG #ifdef DEBUG
void UpnpSetLogLevel(Upnp_LogLevel log_level); void UpnpSetLogLevel(
/*! [in] Log level. */
Upnp_LogLevel log_level);
#else #else
static UPNP_INLINE void UpnpSetLogLevel(Upnp_LogLevel log_level) {} static UPNP_INLINE void UpnpSetLogLevel(Upnp_LogLevel log_level) {}
#endif #endif
/*************************************************************************** /*!
* Function : UpnpCloseLog * \brief Closes the log files.
* */
* Parameters: void
*
* Description:
* This functions closes the log files
* Returns: void
***************************************************************************/
#ifdef DEBUG #ifdef DEBUG
void UpnpCloseLog(void); void UpnpCloseLog(void);
#else #else
@ -147,23 +140,14 @@ static UPNP_INLINE void UpnpCloseLog(void) {}
#endif #endif
/*************************************************************************** /*!
* Function : UpnpSetLogFileNames * \brief Set the name for error and information files, respectively.
* */
* 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
***************************************************************************/
#ifdef DEBUG #ifdef DEBUG
void UpnpSetLogFileNames( void UpnpSetLogFileNames(
/*! [in] Name of the error file. */
const char *ErrFileName, const char *ErrFileName,
/*! [in] Name of the information file. */
const char *InfoFileName); const char *InfoFileName);
#else #else
static UPNP_INLINE void UpnpSetLogFileNames( static UPNP_INLINE void UpnpSetLogFileNames(
@ -172,24 +156,20 @@ static UPNP_INLINE void UpnpSetLogFileNames(
#endif #endif
/*************************************************************************** /*!
* Function : UpnpGetDebugFile * \brief Check if the module is turned on for debug and returns the file
* descriptor corresponding to the debug level
* *
* Parameters: * \return NULL if the module is turn off for debug otheriwse returns the
* IN Upnp_LogLevel DLevel: The level of the debug logging. It will decide * right file descriptor.
* 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 #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 #else
static UPNP_INLINE FILE *UpnpGetDebugFile(Upnp_LogLevel level, Dbg_Module module) 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 #endif
/*************************************************************************** /*!
* Function : DebugAtThisLevel * \brief Returns true if debug output should be done in this module.
* *
* Parameters: * \return Nonzero value if true, zero if false.
* 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 #ifdef DEBUG
int DebugAtThisLevel( int DebugAtThisLevel(
IN Upnp_LogLevel DLevel, /*! [in] The level of the debug logging. It will decide whether debug
IN Dbg_Module Module); * 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 #else
static UPNP_INLINE int DebugAtThisLevel( static UPNP_INLINE int DebugAtThisLevel(
IN Upnp_LogLevel DLevel, Upnp_LogLevel DLevel,
IN Dbg_Module Module) { return 0; } Dbg_Module Module)
{
return 0;
}
#endif #endif
/*************************************************************************** /*!
* Function : UpnpPrintf * \brief Prints the debug statement either on the standard output or log file
* * along with the information from where this debug statement is coming.
* 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 #ifdef DEBUG
void UpnpPrintf( 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, Upnp_LogLevel DLevel,
/*! [in] debug will go in the name of this module. */
Dbg_Module Module, Dbg_Module Module,
/*! [in] Name of the file from where debug statement is coming. */
const char* DbgFileName, const char* DbgFileName,
/*! [in] Line number of the file from where debug statement is coming. */
int DbgLineNo, int DbgLineNo,
/*! [in] Printf like format specification. */
const char* FmtStr, const char* FmtStr,
/*! [in] Printf like Variable number of arguments that will go in the debug
* statement. */
...) ...)
#if (__GNUC__ >= 3) #if (__GNUC__ >= 3)
/* This enables printf like format checking by the compiler */ /* This enables printf like format checking by the compiler */
@ -265,29 +232,44 @@ static UPNP_INLINE void UpnpPrintf(
const char* DbgFileName, const char* DbgFileName,
int DbgLineNo, int DbgLineNo,
const char* FmtStr, const char* FmtStr,
...) {} ...)
{
}
#endif /* DEBUG */ #endif /* DEBUG */
/*************************************************************************** /*!
* Function : UpnpDisplayBanner * \brief Writes the file name and file number from where debug statement is
* * coming to the log file.
* Parameters: */
* IN FILE *fd: file descriptor where the banner will be written #ifdef DEBUG
* IN char **lines: The buffer that will be written void UpnpDisplayFileAndLine(
* IN int size: Size of the buffer /*! [in] File descriptor where line number and file name will be written. */
* IN int starLength: This parameter provides the width of the banner FILE *fd,
* /*! [in] Name of the file. */
* Description: const char *DbgFileName,
* This functions takes the buffer and writes the buffer in the file as /*! [in] Line number of the file. */
* per the requested banner int DbgLineNo);
* Returns: void #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 #ifdef DEBUG
void UpnpDisplayBanner( void UpnpDisplayBanner(
/*! [in] file descriptor where the banner will be written. */
FILE *fd, FILE *fd,
/*! [in] The buffer that will be written. */
const char **lines, const char **lines,
/*! [in] Size of the buffer. */
size_t size, size_t size,
/*! [in] This parameter provides the width of the banner. */
int starlength); int starlength);
#else #else
static UPNP_INLINE void UpnpDisplayBanner( static UPNP_INLINE void UpnpDisplayBanner(
@ -298,33 +280,49 @@ static UPNP_INLINE void UpnpDisplayBanner(
#endif #endif
/*************************************************************************** /*!
* Function : UpnpDisplayFileAndLine * \brief Prints thread pool statistics.
* */
* 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 #ifdef DEBUG
void UpnpDisplayFileAndLine( void PrintThreadPoolStats(
FILE *fd, /*! [in] The thread pool. */
ThreadPool *tp,
/*! [in] The file name that called this function, use the macro __FILE__. */
const char *DbgFileName, 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 #else
static UPNP_INLINE void UpnpDisplayFileAndLine( static UPNP_INLINE void PrintThreadPoolStats(
FILE *fd, ThreadPool *tp,
const char *DbgFileName, const char *DbgFileName,
int DbgLineNo) {} int DbgLineNo,
const char *msg)
{
}
#endif #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 #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,12 @@
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
@ -30,53 +30,79 @@
******************************************************************************/ ******************************************************************************/
#include "config.h" #include "config.h"
#include "ithread.h"
#include "ixml.h"
#include "upnp.h"
#include "upnpdebug.h" #include "upnpdebug.h"
#include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "ithread.h"
#include "upnp.h"
#include <stdarg.h>
#include <string.h> #include <string.h>
//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; static ithread_mutex_t GlobalDebugMutex;
// Global log level /*! Global log level */
static Upnp_LogLevel g_log_level = UPNP_DEFAULT_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; static FILE *ErrFileHnd = NULL;
//File handle for the information log file /*! File handle for the information log file */
static FILE *InfoFileHnd = NULL; static FILE *InfoFileHnd = NULL;
//Name of the error file /*! Name of the error file */
static const char *errFileName = "IUpnpErrFile.txt"; static const char *errFileName = "IUpnpErrFile.txt";
//Name of the info file /*! Name of the info file */
static const char *infoFileName = "IUpnpInfoFile.txt"; static const char *infoFileName = "IUpnpInfoFile.txt";
#ifdef DEBUG
/***************************************************************************
* Function : UpnpSetLogFileNames int UpnpInitLog(void)
* {
* Parameters: ithread_mutex_init(&GlobalDebugMutex, NULL);
* IN const char* ErrFileName: name of the error file if(DEBUG_TARGET == 1) {
* IN const char *InfoFileName: name of the information file if((ErrFileHnd = fopen( errFileName, "a")) == NULL) {
* IN int size: Size of the buffer return -1;
* IN int starLength: This parameter provides the width of the banner }
* if((InfoFileHnd = fopen( infoFileName, "a")) == NULL) {
* Description: return -1;
* This functions takes the buffer and writes the buffer in the file as }
* per the requested banner }
* Returns: void return UPNP_E_SUCCESS;
***************************************************************************/ }
void
UpnpSetLogFileNames ( IN const char *ErrFileName,
IN const char *InfoFileName ) void UpnpSetLogLevel(Upnp_LogLevel log_level)
{
g_log_level = log_level;
}
void UpnpCloseLog(void)
{
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) { if (ErrFileName) {
errFileName = ErrFileName; errFileName = ErrFileName;
@ -87,91 +113,9 @@ UpnpSetLogFileNames ( IN const char *ErrFileName,
} }
/***************************************************************************
* 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)
{
g_log_level = log_level;
}
/***************************************************************************
* Function : UpnpCloseLog
*
* Parameters: void
*
* Description:
* This functions closes the log files
* Returns: void
***************************************************************************/
void
UpnpCloseLog(void)
{
if( DEBUG_TARGET == 1 ) {
fflush( ErrFileHnd );
fflush( InfoFileHnd );
fclose( ErrFileHnd );
fclose( InfoFileHnd );
}
ithread_mutex_destroy( &GlobalDebugMutex );
}
/***************************************************************************
* 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( int DebugAtThisLevel(
IN Upnp_LogLevel DLevel, Upnp_LogLevel DLevel,
IN Dbg_Module Module) Dbg_Module Module)
{ {
int ret = DLevel <= g_log_level; int ret = DLevel <= g_log_level;
ret &= ret &=
@ -186,37 +130,14 @@ int DebugAtThisLevel(
return ret; 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( void UpnpPrintf(
IN Upnp_LogLevel DLevel, Upnp_LogLevel DLevel,
IN Dbg_Module Module, Dbg_Module Module,
IN const char *DbgFileName, const char *DbgFileName,
IN int DbgLineNo, int DbgLineNo,
IN const char *FmtStr, const char *FmtStr,
...) ...)
{ {
va_list ArgList; va_list ArgList;
@ -249,26 +170,8 @@ void UpnpPrintf(
va_end(ArgList); va_end(ArgList);
ithread_mutex_unlock(&GlobalDebugMutex); 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; FILE *ret;
@ -287,28 +190,12 @@ FILE *GetDebugFile( Upnp_LogLevel DLevel, Dbg_Module Module )
return ret; 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( void UpnpDisplayFileAndLine(
IN FILE * fd, FILE *fd,
IN const char *DbgFileName, const char *DbgFileName,
IN int DbgLineNo) int DbgLineNo)
{ {
#define NLINES 2 #define NLINES 2
#define MAX_LINE_SIZE 512 #define MAX_LINE_SIZE 512
@ -324,7 +211,12 @@ void UpnpDisplayFileAndLine(
/* Put the debug lines in the buffer */ /* Put the debug lines in the buffer */
sprintf(buf[0], "DEBUG - THREAD ID: 0x%lX", 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) { if (DbgFileName) {
sprintf(buf[1], sprintf(buf[1],
"FILE: %s, LINE: %d", "FILE: %s, LINE: %d",
@ -336,29 +228,13 @@ void UpnpDisplayFileAndLine(
UpnpDisplayBanner(fd, lines, NLINES, NUMBER_OF_STARS); UpnpDisplayBanner(fd, lines, NLINES, NUMBER_OF_STARS);
fflush(fd); 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( void UpnpDisplayBanner(
IN FILE * fd, FILE * fd,
IN const char **lines, const char **lines,
IN size_t size, size_t size,
IN int starLength) int starLength)
{ {
int leftMarginLength = starLength / 2 + 1; int leftMarginLength = starLength / 2 + 1;
int rightMarginLength = starLength / 2 + 1; int rightMarginLength = starLength / 2 + 1;
@ -406,5 +282,74 @@ void UpnpDisplayBanner(
free(rightMargin); free(rightMargin);
free(leftMargin); 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 */

View File

@ -127,7 +127,7 @@ static int ScheduleGenaAutoRenew(
/*! [in] The time out value of the subscription. */ /*! [in] The time out value of the subscription. */
IN int TimeOut, IN int TimeOut,
/*! [in] Subscription being renewed. */ /*! [in] Subscription being renewed. */
IN client_subscription *sub) IN ClientSubscription *sub)
{ {
struct Upnp_Event_Subscribe *RenewEventStruct = NULL; struct Upnp_Event_Subscribe *RenewEventStruct = NULL;
upnp_timeout *RenewEvent = NULL; upnp_timeout *RenewEvent = NULL;
@ -300,13 +300,23 @@ static int gena_subscribe(
"TIMEOUT: Second-", timeout_str ); "TIMEOUT: Second-", timeout_str );
} else { } else {
// subscribe // subscribe
if( dest_url.hostport.IPaddress.ss_family == AF_INET6 ) {
return_code = http_MakeMessage( return_code = http_MakeMessage(
&request, 1, 1, &request, 1, 1,
"q" "sssdsc" "sc" "sscc", "q" "sssdsc" "sc" "sscc",
HTTPMETHOD_SUBSCRIBE, &dest_url, HTTPMETHOD_SUBSCRIBE, &dest_url,
"CALLBACK: <http://", LOCAL_HOST, ":", LOCAL_PORT, "/>", "CALLBACK: <http://[", gIF_IPV6, "]:", LOCAL_PORT_V6, "/>",
"NT: upnp:event", "NT: upnp:event",
"TIMEOUT: Second-", timeout_str ); "TIMEOUT: Second-", timeout_str );
} else {
return_code = http_MakeMessage(
&request, 1, 1,
"q" "sssdsc" "sc" "sscc",
HTTPMETHOD_SUBSCRIBE, &dest_url,
"CALLBACK: <http://", gIF_IPV4, ":", LOCAL_PORT_V4, "/>",
"NT: upnp:event",
"TIMEOUT: Second-", timeout_str);
}
} }
if (return_code != 0) { if (return_code != 0) {
return return_code; return return_code;
@ -368,7 +378,7 @@ static int gena_subscribe(
int genaUnregisterClient(UpnpClient_Handle client_handle) int genaUnregisterClient(UpnpClient_Handle client_handle)
{ {
client_subscription sub_copy; ClientSubscription sub_copy;
int return_code = UPNP_E_SUCCESS; int return_code = UPNP_E_SUCCESS;
struct Handle_Info *handle_info = NULL; struct Handle_Info *handle_info = NULL;
http_parser_t response; http_parser_t response;
@ -413,10 +423,10 @@ int genaUnSubscribe(
UpnpClient_Handle client_handle, UpnpClient_Handle client_handle,
const Upnp_SID in_sid) const Upnp_SID in_sid)
{ {
client_subscription *sub = NULL; ClientSubscription *sub = NULL;
int return_code = GENA_SUCCESS; int return_code = GENA_SUCCESS;
struct Handle_Info *handle_info; struct Handle_Info *handle_info;
client_subscription sub_copy; ClientSubscription sub_copy;
http_parser_t response; http_parser_t response;
// validate handle and sid // validate handle and sid
@ -467,7 +477,7 @@ int genaSubscribe(
Upnp_SID out_sid) Upnp_SID out_sid)
{ {
int return_code = GENA_SUCCESS; int return_code = GENA_SUCCESS;
client_subscription *newSubscription = NULL; ClientSubscription *newSubscription = NULL;
uuid_upnp uid; uuid_upnp uid;
Upnp_SID temp_sid; Upnp_SID temp_sid;
char *ActualSID = NULL; char *ActualSID = NULL;
@ -517,7 +527,7 @@ int genaSubscribe(
strcpy( EventURL, PublisherURL ); strcpy( EventURL, PublisherURL );
// fill subscription // fill subscription
newSubscription = (client_subscription *)malloc(sizeof (client_subscription)); newSubscription = (ClientSubscription *)malloc(sizeof (ClientSubscription));
if (newSubscription == NULL) { if (newSubscription == NULL) {
return_code = UPNP_E_OUTOF_MEMORY; return_code = UPNP_E_OUTOF_MEMORY;
goto error_handler; goto error_handler;
@ -552,8 +562,8 @@ int genaRenewSubscription(
int *TimeOut) int *TimeOut)
{ {
int return_code = GENA_SUCCESS; int return_code = GENA_SUCCESS;
client_subscription *sub = NULL; ClientSubscription *sub = NULL;
client_subscription sub_copy; ClientSubscription sub_copy;
struct Handle_Info *handle_info; struct Handle_Info *handle_info;
char *ActualSID; char *ActualSID;
ThreadPoolJob tempJob; ThreadPoolJob tempJob;
@ -657,7 +667,7 @@ void gena_process_notification_event(
IXML_Document *ChangedVars = NULL; IXML_Document *ChangedVars = NULL;
int eventKey; int eventKey;
token sid; token sid;
client_subscription *subscription = NULL; ClientSubscription *subscription = NULL;
struct Handle_Info *handle_info; struct Handle_Info *handle_info;
void *cookie; void *cookie;
Upnp_FunPtr callback; Upnp_FunPtr callback;

View File

@ -1241,7 +1241,7 @@ void gena_process_subscription_request(
HandleLock(); HandleLock();
// CURRENTLY, ONLY ONE DEVICE // CURRENTLY, ONLY ONE DEVICE
if (GetDeviceHandleInfo( if (GetDeviceHandleInfo(info->foreign_sockaddr.ss_family ,
&device_handle, &handle_info) != HND_DEVICE) { &device_handle, &handle_info) != HND_DEVICE) {
free(event_url_path); free(event_url_path);
error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
@ -1409,7 +1409,7 @@ void gena_process_subscription_renewal_request(
HandleLock(); HandleLock();
// CURRENTLY, ONLY SUPPORT ONE DEVICE // CURRENTLY, ONLY SUPPORT ONE DEVICE
if (GetDeviceHandleInfo( if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family,
&device_handle, &handle_info ) != HND_DEVICE ) { &device_handle, &handle_info ) != HND_DEVICE ) {
error_respond( info, HTTP_PRECONDITION_FAILED, request ); error_respond( info, HTTP_PRECONDITION_FAILED, request );
membuffer_destroy( &event_url_path ); membuffer_destroy( &event_url_path );
@ -1520,7 +1520,7 @@ void gena_process_unsubscribe_request(
HandleLock(); HandleLock();
// CURRENTLY, ONLY SUPPORT ONE DEVICE // CURRENTLY, ONLY SUPPORT ONE DEVICE
if (GetDeviceHandleInfo( if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family,
&device_handle, &handle_info ) != HND_DEVICE ) { &device_handle, &handle_info ) != HND_DEVICE ) {
error_respond( info, HTTP_PRECONDITION_FAILED, request ); error_respond( info, HTTP_PRECONDITION_FAILED, request );
membuffer_destroy( &event_url_path ); membuffer_destroy( &event_url_path );

View File

@ -43,8 +43,8 @@
* Function : copy_client_subscription * Function : copy_client_subscription
* *
* Parameters : * Parameters :
* client_subscription * in ; - source client subscription * ClientSubscription * in ; - source client subscription
* client_subscription * out ; - destination client subscription * ClientSubscription * out ; - destination client subscription
* *
* Description : Make a copy of the client subscription data * Description : Make a copy of the client subscription data
* *
@ -54,8 +54,8 @@
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
CLIENTONLY( int copy_client_subscription( client_subscription * in, CLIENTONLY( int copy_client_subscription( ClientSubscription * in,
client_subscription * out ) { ClientSubscription * out ) {
int len = strlen( in->ActualSID ) + 1; int len = strlen( in->ActualSID ) + 1;
int len1 = strlen( in->EventURL ) + 1; int len1 = strlen( in->EventURL ) + 1;
memcpy( out->sid, in->sid, SID_SIZE ); memcpy( out->sid, in->sid, SID_SIZE );
@ -77,7 +77,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* Function : free_client_subscription * Function : free_client_subscription
* *
* Parameters : * Parameters :
* client_subscription * sub ; - Client subscription to be freed * ClientSubscription * sub ; - Client subscription to be freed
* *
* Description : Free memory allocated for client subscription data. * Description : Free memory allocated for client subscription data.
* Remove timer thread associated with this subscription event. * Remove timer thread associated with this subscription event.
@ -86,7 +86,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void free_client_subscription( client_subscription * sub ) { void free_client_subscription( ClientSubscription * sub ) {
upnp_timeout * event; ThreadPoolJob tempJob; if( sub ) { upnp_timeout * event; ThreadPoolJob tempJob; if( sub ) {
if( sub->ActualSID ) if( sub->ActualSID )
free( sub->ActualSID ); if( sub->EventURL ) free( sub->ActualSID ); if( sub->EventURL )
@ -106,7 +106,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* Function : freeClientSubList * Function : freeClientSubList
* *
* Parameters : * Parameters :
* client_subscription * list ; Client subscription * ClientSubscription * list ; Client subscription
* *
* Description : Free the client subscription table. * Description : Free the client subscription table.
* *
@ -114,8 +114,8 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void freeClientSubList( client_subscription * list ) { void freeClientSubList( ClientSubscription * list ) {
client_subscription * next; while( list ) { ClientSubscription * next; while( list ) {
free_client_subscription( list ); free_client_subscription( list );
next = list->next; free( list ); list = next;} next = list->next; free( list ); list = next;}
} }
@ -124,7 +124,7 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* Function : RemoveClientSubClientSID * Function : RemoveClientSubClientSID
* *
* Parameters : * 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 * const Upnp_SID sid ; Subscription ID to be mactched
* *
* Description : Remove the client subscription matching the * Description : Remove the client subscription matching the
@ -135,10 +135,10 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void RemoveClientSubClientSID( client_subscription ** head, void RemoveClientSubClientSID( ClientSubscription ** head,
const Upnp_SID sid ) { const Upnp_SID sid ) {
client_subscription * finger = ( *head ); ClientSubscription * finger = ( *head );
client_subscription * previous = NULL; while( finger ) { ClientSubscription * previous = NULL; while( finger ) {
if( !( strcmp( sid, finger->sid ) ) ) { if( !( strcmp( sid, finger->sid ) ) ) {
if( previous ) if( previous )
previous->next = finger->next; previous->next = finger->next;
@ -156,20 +156,20 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* Function : GetClientSubClientSID * Function : GetClientSubClientSID
* *
* Parameters : * 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 * const Upnp_SID sid ; Subscription ID to be matched
* *
* Description : Return the client subscription from the client table * Description : Return the client subscription from the client table
* that matches const Upnp_SID sid subscrition id value. * that matches const Upnp_SID sid subscrition id value.
* *
* Return : client_subscription * ; The matching subscription * Return : ClientSubscription * ; The matching subscription
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
client_subscription * ClientSubscription *
GetClientSubClientSID( client_subscription * head, GetClientSubClientSID( ClientSubscription * head,
const Upnp_SID sid ) { const Upnp_SID sid ) {
client_subscription * next = head; while( next ) { ClientSubscription * next = head; while( next ) {
if( !strcmp( next->sid, sid ) ) if( !strcmp( next->sid, sid ) )
break; break;
else else
@ -182,21 +182,21 @@ CLIENTONLY( int copy_client_subscription( client_subscription * in,
* Function : GetClientSubActualSID * Function : GetClientSubActualSID
* *
* Parameters : * Parameters :
* client_subscription *head ; Head of the subscription list * ClientSubscription *head ; Head of the subscription list
* token * sid ; Subscription ID to be matched * token * sid ; Subscription ID to be matched
* *
* Description : Returns the client subscription from the client * Description : Returns the client subscription from the client
* subscription table that has the matching token * sid buffer * subscription table that has the matching token * sid buffer
* value. * value.
* *
* Return : client_subscription * ; The matching subscription * Return : ClientSubscription * ; The matching subscription
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
client_subscription * ClientSubscription *
GetClientSubActualSID( client_subscription * head, GetClientSubActualSID( ClientSubscription * head,
token * sid ) { token * sid ) {
client_subscription * next = head; while( next ) { ClientSubscription * next = head; while( next ) {
if( !memcmp( next->ActualSID, sid->buff, sid->size ) ) if( !memcmp( next->ActualSID, sid->buff, sid->size ) )
break; break;

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,34 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
/****************************************************************************** /******************************************************************************
* Purpose: This file defines the Web Server and has functions to carry out * Purpose: This file defines the Web Server and has functions to carry out
@ -52,18 +53,28 @@
#include "upnp.h" #include "upnp.h"
#include "upnpapi.h" #include "upnpapi.h"
#include "util.h" #include "util.h"
#include "VirtualDir.h"
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#ifndef UPNP_USE_BCBPP #include <sys/stat.h>
#ifdef UPNP_USE_BCBPP
/* Do not #include <inttypes.h> */
/* Do not #include <stdint.h> */
#else
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#endif #endif /* !UPNP_USE_BCBPP */
#ifndef WIN32
#ifdef WIN32
/* Do not #include <unistd.h> */
#else
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <sys/stat.h>
/* /*
@ -301,8 +312,8 @@ get_content_type( IN const char *filename,
OUT DOMString * content_type ) OUT DOMString * content_type )
{ {
const char *extension; const char *extension;
const char *type, const char *type;
*subtype; const char *subtype;
xboolean ctype_found = FALSE; xboolean ctype_found = FALSE;
char *temp = NULL; char *temp = NULL;
int length = 0; int length = 0;
@ -325,11 +336,9 @@ get_content_type( IN const char *filename,
length = strlen( type ) + strlen( "/" ) + strlen( subtype ) + 1; length = strlen( type ) + strlen( "/" ) + strlen( subtype ) + 1;
temp = ( char * )malloc( length ); temp = ( char * )malloc( length );
if (!temp) { if (!temp) {
return UPNP_E_OUTOF_MEMORY; return UPNP_E_OUTOF_MEMORY;
} }
sprintf( temp, "%s/%s", type, subtype ); sprintf( temp, "%s/%s", type, subtype );
( *content_type ) = ixmlCloneDOMString( temp ); ( *content_type ) = ixmlCloneDOMString( temp );
@ -521,40 +530,33 @@ web_server_set_alias( IN const char *alias_name,
return UPNP_E_OUTOF_MEMORY; 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 ret_code;
int web_server_init()
{
int ret = 0;
if (bWebServerState == WEB_SERVER_DISABLED) { if (bWebServerState == WEB_SERVER_DISABLED) {
media_list_init(); // decode media list // decode media list
media_list_init();
membuffer_init(&gDocumentRootDir); membuffer_init(&gDocumentRootDir);
glob_alias_init(); glob_alias_init();
pVirtualDirList = NULL; pVirtualDirList = NULL;
ret_code = ithread_mutex_init( &gWebMutex, NULL ); // Initialize callbacks
if( ret_code == -1 ) { virtualDirCallback.get_info = NULL;
return UPNP_E_OUTOF_MEMORY; virtualDirCallback.open = NULL;
} virtualDirCallback.read = NULL;
virtualDirCallback.write = NULL;
virtualDirCallback.seek = NULL;
virtualDirCallback.close = NULL;
if (ithread_mutex_init(&gWebMutex, NULL) == -1) {
ret = UPNP_E_OUTOF_MEMORY;
} else {
bWebServerState = WEB_SERVER_ENABLED; bWebServerState = WEB_SERVER_ENABLED;
} }
}
return 0; return ret;
} }
/************************************************************************ /************************************************************************
@ -709,9 +711,7 @@ get_alias( IN const char *request_file,
OUT struct xml_alias_t *alias, OUT struct xml_alias_t *alias,
OUT struct File_Info *info ) OUT struct File_Info *info )
{ {
int cmp; int cmp = strcmp(alias->name.buf, request_file);
cmp = strcmp( alias->name.buf, request_file );
if (cmp == 0) { if (cmp == 0) {
// fill up info // fill up info
info->file_length = alias->doc.length; info->file_length = alias->doc.length;
@ -1209,11 +1209,11 @@ process_request( IN http_message_t * req,
xboolean using_virtual_dir; xboolean using_virtual_dir;
uri_type *url; uri_type *url;
char *temp_str; char *temp_str;
int resp_major, int resp_major;
resp_minor; int resp_minor;
xboolean alias_grabbed; xboolean alias_grabbed;
size_t dummy; size_t dummy;
struct UpnpVirtualDirCallbacks *pVirtualDirCallback; const char *extra_headers = NULL;
print_http_headers( req ); print_http_headers( req );
@ -1265,9 +1265,7 @@ process_request( IN http_message_t * req,
} }
} else { } else {
// /* try using alias */
// try using alias
//
if (is_valid_alias(&gAliasDoc)) { if (is_valid_alias(&gAliasDoc)) {
alias_grab(alias); alias_grab(alias);
alias_grabbed = TRUE; alias_grabbed = TRUE;
@ -1286,9 +1284,7 @@ process_request( IN http_message_t * req,
if (using_virtual_dir) { if (using_virtual_dir) {
if (req->method != HTTPMETHOD_POST) { if (req->method != HTTPMETHOD_POST) {
// get file info // get file info
pVirtualDirCallback = &virtualDirCallback; if (virtualDirCallback.get_info(filename->buf, &finfo) != 0) {
if( pVirtualDirCallback->get_info( filename->buf, &finfo ) !=
0 ) {
err_code = HTTP_NOT_FOUND; err_code = HTTP_NOT_FOUND;
goto error_handler; goto error_handler;
} }
@ -1303,9 +1299,8 @@ process_request( IN http_message_t * req,
goto error_handler; goto error_handler;
} }
// get info // get info
if( ( pVirtualDirCallback-> if( (virtualDirCallback.get_info(filename->buf, &finfo ) != UPNP_E_SUCCESS ) ||
get_info( filename->buf, &finfo ) != UPNP_E_SUCCESS ) finfo.is_directory) {
|| finfo.is_directory ) {
err_code = HTTP_NOT_FOUND; err_code = HTTP_NOT_FOUND;
goto error_handler; goto error_handler;
} }
@ -1392,34 +1387,40 @@ process_request( IN http_message_t * req,
goto error_handler; goto error_handler;
} }
/*extra_headers = UpnpFileInfo_get_ExtraHeaders(finfo);*/
if (!extra_headers) {
extra_headers = "";
}
if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) {
// Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
// Transfer-Encoding: chunked // Transfer-Encoding: chunked
if (http_MakeMessage( if (http_MakeMessage(
headers, resp_major, resp_minor, headers, resp_major, resp_minor,
"R" "T" "GKD" "s" "tcS" "XcCc", "R" "T" "GKD" "s" "tcS" "Xc" "sCc",
HTTP_PARTIAL_CONTENT, // status code HTTP_PARTIAL_CONTENT, // status code
finfo.content_type, // content type finfo.content_type, // content type
RespInstr, // range info RespInstr, // range info
"LAST-MODIFIED: ", "LAST-MODIFIED: ",
&finfo.last_modified, &finfo.last_modified,
X_USER_AGENT) != 0 ) { X_USER_AGENT,
extra_headers) != 0 ) {
goto error_handler; goto error_handler;
} }
} else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) { } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) {
// Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT
// Transfer-Encoding: chunked // Transfer-Encoding: chunked
if (http_MakeMessage( if (http_MakeMessage(
headers, resp_major, resp_minor, headers, resp_major, resp_minor,
"R" "N" "T" "GD" "s" "tcS" "XcCc", "R" "N" "T" "GD" "s" "tcS" "Xc" "sCc",
HTTP_PARTIAL_CONTENT, // status code HTTP_PARTIAL_CONTENT, // status code
RespInstr->ReadSendSize, // content length RespInstr->ReadSendSize, // content length
finfo.content_type, // content type finfo.content_type, // content type
RespInstr, // range info RespInstr, // range info
"LAST-MODIFIED: ", "LAST-MODIFIED: ",
&finfo.last_modified, &finfo.last_modified,
X_USER_AGENT) != 0 ) { X_USER_AGENT,
extra_headers) != 0 ) {
goto error_handler; goto error_handler;
} }
@ -1428,12 +1429,13 @@ process_request( IN http_message_t * req,
// Transfer-Encoding: chunked // Transfer-Encoding: chunked
if (http_MakeMessage( if (http_MakeMessage(
headers, resp_major, resp_minor, headers, resp_major, resp_minor,
"RK" "TD" "s" "tcS" "XcCc", "RK" "TD" "s" "tcS" "Xc" "sCc",
HTTP_OK, // status code HTTP_OK, // status code
finfo.content_type, // content type finfo.content_type, // content type
"LAST-MODIFIED: ", "LAST-MODIFIED: ",
&finfo.last_modified, &finfo.last_modified,
X_USER_AGENT) != 0 ) { X_USER_AGENT,
extra_headers) != 0 ) {
goto error_handler; goto error_handler;
} }
@ -1443,13 +1445,14 @@ process_request( IN http_message_t * req,
// Transfer-Encoding: chunked // Transfer-Encoding: chunked
if (http_MakeMessage( if (http_MakeMessage(
headers, resp_major, resp_minor, headers, resp_major, resp_minor,
"R" "N" "TD" "s" "tcS" "XcCc", "R" "N" "TD" "s" "tcS" "Xc" "sCc",
HTTP_OK, // status code HTTP_OK, // status code
RespInstr->ReadSendSize, // content length RespInstr->ReadSendSize, // content length
finfo.content_type, // content type finfo.content_type, // content type
"LAST-MODIFIED: ", "LAST-MODIFIED: ",
&finfo.last_modified, &finfo.last_modified,
X_USER_AGENT) != 0 ) { X_USER_AGENT,
extra_headers) != 0 ) {
goto error_handler; goto error_handler;
} }
} else { } else {
@ -1457,12 +1460,13 @@ process_request( IN http_message_t * req,
// Transfer-Encoding: chunked // Transfer-Encoding: chunked
if (http_MakeMessage( if (http_MakeMessage(
headers, resp_major, resp_minor, headers, resp_major, resp_minor,
"R" "TD" "s" "tcS" "XcCc", "R" "TD" "s" "tcS" "b" "Xc" "sCc",
HTTP_OK, // status code HTTP_OK, // status code
finfo.content_type, // content type finfo.content_type, // content type
"LAST-MODIFIED: ", "LAST-MODIFIED: ",
&finfo.last_modified, &finfo.last_modified,
X_USER_AGENT) != 0 ) { X_USER_AGENT,
extra_headers) != 0 ) {
goto error_handler; goto error_handler;
} }
} }
@ -1535,12 +1539,10 @@ http_RecvPostMessage( http_parser_t * parser,
int ret_code = 0; int ret_code = 0;
if( Instr && Instr->IsVirtualFile ) { if( Instr && Instr->IsVirtualFile ) {
Fp = (virtualDirCallback.open)( filename, UPNP_WRITE ); Fp = (virtualDirCallback.open)( filename, UPNP_WRITE );
if( Fp == NULL ) { if( Fp == NULL ) {
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
} else { } else {
Fp = fopen( filename, "wb" ); Fp = fopen( filename, "wb" );
if( Fp == NULL ) { if( Fp == NULL ) {

View File

@ -1,57 +1,55 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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 "config.h"
#include "sock.h"
#include "unixutil.h" /* for socklen_t, EAFNOSUPPORT */
#include "upnp.h"
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include "sock.h"
#include "upnp.h"
#ifndef WIN32
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#else
#include <winsock2.h>
#endif
#include "unixutil.h"
#ifndef MSG_NOSIGNAL #ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0 #define MSG_NOSIGNAL 0
@ -62,7 +60,7 @@
* *
* Parameters : * Parameters :
* OUT SOCKINFO* info ; Socket Information Object * 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 * Description : Assign the passed in socket descriptor to socket
* descriptor in the SOCKINFO structure. * descriptor in the SOCKINFO structure.
@ -76,7 +74,7 @@
************************************************************************/ ************************************************************************/
int int
sock_init( OUT SOCKINFO * info, sock_init( OUT SOCKINFO * info,
IN int sockfd ) IN SOCKET sockfd )
{ {
assert( info ); assert( info );
@ -92,9 +90,8 @@ sock_init( OUT SOCKINFO * info,
* *
* Parameters : * Parameters :
* OUT SOCKINFO* info ; Socket Information Object * OUT SOCKINFO* info ; Socket Information Object
* IN int sockfd ; Socket Descriptor * IN SOCKET sockfd ; Socket Descriptor
* IN struct in_addr foreign_ip_addr ; Remote IP Address * IN struct sockaddr* foreign_sockaddr; remote socket address.
* IN unsigned short foreign_ip_port ; Remote Port number
* *
* Description : Calls the sock_init function and assigns the passed in * Description : Calls the sock_init function and assigns the passed in
* IP address and port to the IP address and port in the SOCKINFO * IP address and port to the IP address and port in the SOCKINFO
@ -109,9 +106,8 @@ sock_init( OUT SOCKINFO * info,
************************************************************************/ ************************************************************************/
int int
sock_init_with_ip( OUT SOCKINFO * info, sock_init_with_ip( OUT SOCKINFO * info,
IN int sockfd, IN SOCKET sockfd,
IN struct in_addr foreign_ip_addr, IN struct sockaddr* foreign_sockaddr )
IN unsigned short foreign_ip_port )
{ {
int ret; int ret;
@ -120,8 +116,8 @@ sock_init_with_ip( OUT SOCKINFO * info,
return ret; return ret;
} }
info->foreign_ip_addr = foreign_ip_addr; memcpy( &info->foreign_sockaddr, foreign_sockaddr,
info->foreign_ip_port = foreign_ip_port; sizeof( info->foreign_sockaddr) );
return UPNP_E_SUCCESS; return UPNP_E_SUCCESS;
} }
@ -149,10 +145,12 @@ int
sock_destroy( INOUT SOCKINFO * info, sock_destroy( INOUT SOCKINFO * info,
int ShutdownMethod ) int ShutdownMethod )
{ {
if( info->socket != INVALID_SOCKET ) {
shutdown( info->socket, ShutdownMethod ); shutdown( info->socket, ShutdownMethod );
if( UpnpCloseSocket( info->socket ) == -1 ) { if( UpnpCloseSocket( info->socket ) == -1 ) {
return UPNP_E_SOCKET_ERROR; return UPNP_E_SOCKET_ERROR;
} }
}
return UPNP_E_SUCCESS; return UPNP_E_SUCCESS;
} }
@ -190,7 +188,7 @@ sock_read_write( IN SOCKINFO * info,
struct timeval timeout; struct timeval timeout;
int numBytes; int numBytes;
time_t start_time = time( NULL ); time_t start_time = time( NULL );
int sockfd = info->socket; SOCKET sockfd = info->socket;
long bytes_sent = 0, long bytes_sent = 0,
byte_left = 0, byte_left = 0,
num_written; num_written;
@ -202,9 +200,9 @@ sock_read_write( IN SOCKINFO * info,
FD_ZERO( &readSet ); FD_ZERO( &readSet );
FD_ZERO( &writeSet ); FD_ZERO( &writeSet );
if( bRead ) { if( bRead ) {
FD_SET( ( unsigned )sockfd, &readSet ); FD_SET( sockfd, &readSet );
} else { } else {
FD_SET( ( unsigned )sockfd, &writeSet ); FD_SET( sockfd, &writeSet );
} }
timeout.tv_sec = *timeoutSecs; timeout.tv_sec = *timeoutSecs;

69
upnp/src/inc/VirtualDir.h Normal file
View File

@ -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 <tt> 0</tt>: The file contains no more data (EOF).
* \li <tt> > 0</tt>: A successful read of the number of bytes in the
* return code.
* \li <tt> < 0</tt>: 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 */

View File

@ -57,14 +57,14 @@ typedef struct CLIENT_SUBSCRIPTION {
char * EventURL; char * EventURL;
int RenewEventId; int RenewEventId;
struct CLIENT_SUBSCRIPTION *next; struct CLIENT_SUBSCRIPTION *next;
} client_subscription; } ClientSubscription;
/************************************************************************ /************************************************************************
* Function : copy_client_subscription * Function : copy_client_subscription
* *
* Parameters : * Parameters :
* client_subscription * in ; - source client subscription * ClientSubscription * in ; - source client subscription
* client_subscription * out ; - destination client subscription * ClientSubscription * out ; - destination client subscription
* *
* Description : Make a copy of the client subscription data * Description : Make a copy of the client subscription data
* *
@ -74,13 +74,13 @@ typedef struct CLIENT_SUBSCRIPTION {
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
int copy_client_subscription(client_subscription * in, client_subscription * out); int copy_client_subscription(ClientSubscription * in, ClientSubscription * out);
/************************************************************************ /************************************************************************
* Function : free_client_subscription * Function : free_client_subscription
* *
* Parameters : * Parameters :
* client_subscription * sub ; - Client subscription to be freed * ClientSubscription * sub ; - Client subscription to be freed
* *
* Description : Free memory allocated for client subscription data. * Description : Free memory allocated for client subscription data.
* Remove timer thread associated with this subscription event. * Remove timer thread associated with this subscription event.
@ -89,14 +89,14 @@ int copy_client_subscription(client_subscription * in, client_subscription * out
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void free_client_subscription(client_subscription * sub); void free_client_subscription(ClientSubscription * sub);
/************************************************************************ /************************************************************************
* Function : freeClientSubList * Function : freeClientSubList
* *
* Parameters : * Parameters :
* client_subscription * list ; Client subscription * ClientSubscription * list ; Client subscription
* *
* Description : Free the client subscription table. * Description : Free the client subscription table.
* *
@ -104,13 +104,13 @@ void free_client_subscription(client_subscription * sub);
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void freeClientSubList(client_subscription * list); void freeClientSubList(ClientSubscription * list);
/************************************************************************ /************************************************************************
* Function : RemoveClientSubClientSID * Function : RemoveClientSubClientSID
* *
* Parameters : * 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 * const Upnp_SID sid ; Subscription ID to be mactched
* *
* Description : Remove the client subscription matching the * Description : Remove the client subscription matching the
@ -121,43 +121,42 @@ void freeClientSubList(client_subscription * list);
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
void RemoveClientSubClientSID(client_subscription **head, void RemoveClientSubClientSID(ClientSubscription **head,
const Upnp_SID sid); const Upnp_SID sid);
/************************************************************************ /************************************************************************
* Function : GetClientSubClientSID * Function : GetClientSubClientSID
* *
* Parameters : * 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 * const Upnp_SID sid ; Subscription ID to be matched
* *
* Description : Return the client subscription from the client table * Description : Return the client subscription from the client table
* that matches const Upnp_SID sid subscrition id value. * that matches const Upnp_SID sid subscrition id value.
* *
* Return : client_subscription * ; The matching subscription * Return : ClientSubscription * ; The matching subscription
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
client_subscription * GetClientSubClientSID(client_subscription *head ClientSubscription * GetClientSubClientSID(ClientSubscription *head
, const Upnp_SID sid); , const Upnp_SID sid);
/************************************************************************ /************************************************************************
* Function : GetClientSubActualSID * Function : GetClientSubActualSID
* *
* Parameters : * Parameters :
* client_subscription *head ; Head of the subscription list * ClientSubscription *head ; Head of the subscription list
* token * sid ; Subscription ID to be matched * token * sid ; Subscription ID to be matched
* *
* Description : Returns the client subscription from the client * Description : Returns the client subscription from the client
* subscription table that has the matching token * sid buffer * subscription table that has the matching token * sid buffer
* value. * value.
* *
* Return : client_subscription * ; The matching subscription * Return : ClientSubscription * ; The matching subscription
* *
* Note : * Note :
************************************************************************/ ************************************************************************/
client_subscription * GetClientSubActualSID(client_subscription *head ClientSubscription * GetClientSubActualSID(ClientSubscription *head, token * sid);
, token * sid);
) )
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1,33 +1,38 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
#ifndef GLOBAL_H
#define GLOBAL_H
/* GLOBAL.H - RSAREF types and constants */ /* GLOBAL.H - RSAREF types and constants */
/* PROTOTYPES should be set to one if and only if the compiler supports /* PROTOTYPES should be set to one if and only if the compiler supports
@ -37,6 +42,7 @@
been defined with C compiler flags. been defined with C compiler flags.
*/ */
#ifndef PROTOTYPES #ifndef PROTOTYPES
#define PROTOTYPES 0 #define PROTOTYPES 0
#endif #endif
@ -50,13 +56,17 @@ typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */ /* UINT4 defines a four byte word */
typedef unsigned long int UINT4; 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 * PROTO_LIST is defined depending on how PROTOTYPES is defined above.
returns an empty list. * If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
* returns an empty list.
*/ */
#if PROTOTYPES #if PROTOTYPES
#define PROTO_LIST(list) list #define PROTO_LIST(list) list
#else #else
#define PROTO_LIST(list) () #define PROTO_LIST(list) ()
#endif #endif
#endif /* GLOBAL_H */

View File

@ -42,17 +42,21 @@ extern SOCKET gMiniServerStopSock;
typedef struct MServerSockArray { typedef struct MServerSockArray {
/* socket for listening for miniserver requests */ /* socket for listening for miniserver requests */
int miniServerSock; SOCKET miniServerSock4;
SOCKET miniServerSock6;
/* socket for stopping miniserver */ /* socket for stopping miniserver */
int miniServerStopSock; SOCKET miniServerStopSock;
/* socket for incoming advertisments and search requests */ /* socket for incoming advertisments and search requests */
int ssdpSock; SOCKET ssdpSock4;
SOCKET ssdpSock6;
int stopPort; SOCKET stopPort;
int miniServerPort; SOCKET miniServerPort4;
SOCKET miniServerPort6;
/* socket for sending search requests and receiving search replies */ /* socket for sending search requests and receiving search replies */
CLIENTONLY(int ssdpReqSock;) CLIENTONLY(SOCKET ssdpReqSock4;)
CLIENTONLY(SOCKET ssdpReqSock6;)
} MiniServerSockArray; } MiniServerSockArray;
@ -66,78 +70,62 @@ typedef void (*MiniServerCallback)(
extern "C" { extern "C" {
#endif #endif
/************************************************************************
* Function: SetHTTPGetCallback
*
* Parameters:
* MiniServerCallback callback; - HTTP Callback to be invoked
*
* Description: Set HTTP Get Callback
*
* Return: void
************************************************************************/
void SetHTTPGetCallback( MiniServerCallback callback );
/************************************************************************ /*!
* Function: SetSoapCallback * \brief Set HTTP Get Callback.
* */
* Parameters: void SetHTTPGetCallback(
* MiniServerCallback callback; - SOAP Callback to be invoked /*! [in] HTTP Callback to be invoked . */
* MiniServerCallback callback);
* Description: Set SOAP Callback
*
* Return: void /*!
************************************************************************/ * \brief Set SOAP Callback.
*/
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
void SetSoapCallback( MiniServerCallback callback ); void SetSoapCallback(
/*! [in] SOAP Callback to be invoked . */
MiniServerCallback callback);
#else /* INCLUDE_DEVICE_APIS */ #else /* INCLUDE_DEVICE_APIS */
static inline void SetSoapCallback(MiniServerCallback callback) {} static inline void SetSoapCallback(MiniServerCallback callback) {}
#endif /* INCLUDE_DEVICE_APIS */ #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 * \brief Set GENA Callback.
*/
void SetGenaCallback(
/*! [in] GENA Callback to be invoked. */
MiniServerCallback callback);
/*!
* \brief Initialize the sockets functionality for the Miniserver.
* *
* Parameters: * Initialize a thread pool job to run the MiniServer and the job to the
* unsigned short listen_port ; Port on which the server listens for * thread pool.
* incoming connections
* *
* Description: Initialize the sockets functionality for the * If listen port is 0, port is dynamically picked.
* 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 * Use timer mechanism to start the MiniServer, failure to meet the
* allowed delay aborts the attempt to launch the MiniServer. * allowed delay aborts the attempt to launch the MiniServer.
* *
* Return: int; * \return
* Actual port socket is bound to - On Success: * \li On success: UPNP_E_SUCCESS.
* A negative number UPNP_E_XXX - On Error * \li On error: UPNP_E_XXX.
************************************************************************/ */
int StartMiniServer( unsigned short listen_port ); 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);
/************************************************************************
* Function: StopMiniServer /*!
* \brief Stop and Shutdown the MiniServer and free socket resources.
* *
* Parameters: * \return Always returns 0.
* void; */
*
* Description: Stop and Shutdown the MiniServer and free socket resources.
*
* Return : int;
* Always returns 0
************************************************************************/
int StopMiniServer(); int StopMiniServer();

View File

@ -1,44 +1,50 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
#ifndef GENLIB_NET_SOCK_H #ifndef GENLIB_NET_SOCK_H
#define GENLIB_NET_SOCK_H #define GENLIB_NET_SOCK_H
#include "util.h" #include "util.h"
#ifndef WIN32
#ifdef WIN32
/* Do not #include <netinet/in.h> */
#else
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
//Following variable is not defined under winsock.h
/* Following variable is not defined under winsock.h */
#ifndef SD_RECEIVE #ifndef SD_RECEIVE
#define SD_RECEIVE 0x00 #define SD_RECEIVE 0x00
#define SD_SEND 0x01 #define SD_SEND 0x01
@ -48,24 +54,25 @@
typedef struct 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; } SOCKINFO;
#ifdef __cplusplus #ifdef __cplusplus
#extern "C" { #extern "C" {
#endif #endif
/************************************************************************ /************************************************************************
* Function : sock_init * Function : sock_init
* *
* Parameters : * Parameters :
* OUT SOCKINFO* info ; Socket Information Object * 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 * Description : Assign the passed in socket descriptor to socket
* descriptor in the SOCKINFO structure. * descriptor in the SOCKINFO structure.
@ -76,16 +83,15 @@ typedef struct
* UPNP_E_SOCKET_ERROR * UPNP_E_SOCKET_ERROR
* Note : * Note :
************************************************************************/ ************************************************************************/
int sock_init( OUT SOCKINFO* info, IN int sockfd ); int sock_init(OUT SOCKINFO* info, IN SOCKET sockfd);
/************************************************************************ /************************************************************************
* Function : sock_init_with_ip * Function : sock_init_with_ip
* *
* Parameters : * Parameters :
* OUT SOCKINFO* info ; Socket Information Object * OUT SOCKINFO* info ; Socket Information Object
* IN int sockfd ; Socket Descriptor * IN SOCKET sockfd ; Socket Descriptor
* IN struct in_addr foreign_ip_addr ; Remote IP Address * IN struct sockaddr* foreign_sockaddr; Remote socket address
* IN unsigned short foreign_ip_port ; Remote Port number
* *
* Description : Calls the sock_init function and assigns the passed in * Description : Calls the sock_init function and assigns the passed in
* IP address and port to the IP address and port in the SOCKINFO * 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 : * Note :
************************************************************************/ ************************************************************************/
int sock_init_with_ip( OUT SOCKINFO* info, IN int sockfd, int sock_init_with_ip(
IN struct in_addr foreign_ip_addr, IN unsigned short foreign_ip_port ); OUT SOCKINFO* info,
IN SOCKET sockfd,
IN struct sockaddr *foreign_sockaddr);
/************************************************************************ /************************************************************************
* Function : sock_read * Function : sock_read
@ -164,9 +172,11 @@ int sock_write( IN SOCKINFO *info, IN char* buffer, IN size_t bufsize,
************************************************************************/ ************************************************************************/
int sock_destroy(INOUT SOCKINFO* info, int); int sock_destroy(INOUT SOCKINFO* info, int);
#ifdef __cplusplus #ifdef __cplusplus
} // #extern "C" } /* #extern "C" */
#endif #endif
#endif // GENLIB_NET_SOCK_H #endif /* GENLIB_NET_SOCK_H */

View File

@ -1,59 +1,64 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
#ifndef SSDPLIB_H #ifndef SSDPLIB_H
#define SSDPLIB_H #define SSDPLIB_H
#include "httpparser.h"
#include "httpreadwrite.h"
#include "miniserver.h"
#include "UpnpInet.h"
#include <sys/types.h> #include <sys/types.h>
#include <signal.h> #include <signal.h>
#include <setjmp.h> #include <setjmp.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include "httpparser.h"
#include "httpreadwrite.h"
#include "miniserver.h" #ifdef WIN32
#ifndef WIN32 #else
#include <syslog.h> #include <syslog.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <sys/time.h> #include <sys/time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#else
#include <winsock2.h>
#endif #endif
//Enumeration to define all different types of ssdp searches
/* Enumeration to define all different types of ssdp searches */
typedef enum SsdpSearchType{ typedef enum SsdpSearchType{
SSDP_SERROR=-1, SSDP_SERROR=-1,
SSDP_ALL,SSDP_ROOTDEVICE, SSDP_ALL,SSDP_ROOTDEVICE,
@ -63,8 +68,9 @@ typedef enum SsdpSearchType{
} SType; } SType;
//Enumeration to define all different type of ssdp messages /* Enumeration to define all different type of ssdp messages */
typedef enum SsdpCmdType{SSDP_ERROR=-1, typedef enum SsdpCmdType{
SSDP_ERROR=-1,
SSDP_OK, SSDP_OK,
SSDP_ALIVE, SSDP_ALIVE,
SSDP_BYEBYE, SSDP_BYEBYE,
@ -75,16 +81,18 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1,
//Constant /* Constant */
#define BUFSIZE 2500 #define BUFSIZE 2500
#define SSDP_IP "239.255.255.250" #define SSDP_IP "239.255.255.250"
#define SSDP_IPV6_LINKLOCAL "FF02::C"
#define SSDP_PORT 1900 #define SSDP_PORT 1900
#define NUM_TRY 3 #define NUM_TRY 3
#define NUM_COPY 1 #define NUM_COPY 1
#define THREAD_LIMIT 50 #define THREAD_LIMIT 50
#define COMMAND_LEN 300 #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 /** @name X_USER_AGENT
* The {\tt X_USER_AGENT} constant specifies the value of the 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 * 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" #define X_USER_AGENT "redsonic"
#endif #endif
//Error code /* Error code */
#define NO_ERROR_FOUND 0 #define NO_ERROR_FOUND 0
#define E_REQUEST_INVALID -3 #define E_REQUEST_INVALID -3
#define E_RES_EXPIRED -4 #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 typedef struct SsdpEventStruct
{ {
enum SsdpCmdType Cmd; enum SsdpCmdType Cmd;
@ -121,7 +129,7 @@ typedef struct SsdpEventStruct
char Os[LINE_SIZE]; char Os[LINE_SIZE];
char Ext[LINE_SIZE]; char Ext[LINE_SIZE];
char Date[LINE_SIZE]; char Date[LINE_SIZE];
struct sockaddr_in * DestAddr; struct sockaddr *DestAddr;
void * Cookie; void * Cookie;
} Event; } Event;
@ -143,7 +151,7 @@ typedef struct TData
int Mx; int Mx;
void * Cookie; void * Cookie;
char * Data; char * Data;
struct sockaddr_in DestAddr; struct sockaddr_storage DestAddr;
}ThreadData; }ThreadData;
@ -151,7 +159,7 @@ typedef struct ssdpsearchreply
{ {
int MaxAge; int MaxAge;
UpnpDevice_Handle handle; UpnpDevice_Handle handle;
struct sockaddr_in dest_addr; struct sockaddr_storage dest_addr;
SsdpEvent event; SsdpEvent event;
}SsdpSearchReply; }SsdpSearchReply;
@ -168,21 +176,18 @@ typedef struct ssdpsearcharg
typedef struct typedef struct
{ {
http_parser_t parser; http_parser_t parser;
struct sockaddr_in dest_addr; struct sockaddr_storage dest_addr;
} ssdp_thread_data; } ssdp_thread_data;
/* globals */ /* globals */
CLIENTONLY(extern SOCKET gSsdpReqSocket;); CLIENTONLY(extern SOCKET gSsdpReqSocket4;);
CLIENTONLY(extern SOCKET gSsdpReqSocket6;);
typedef int (*ParserFun)(char *, Event *); typedef int (*ParserFun)(char *, Event *);
//void InitParser();
//int AnalyzeCommand(char * szCommand, Event * Evt);
/************************************************************************ /************************************************************************
* Function : Make_Socket_NoBlocking * Function : Make_Socket_NoBlocking
* *
@ -214,11 +219,11 @@ int Make_Socket_NoBlocking (int sock);
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
void ssdp_handle_device_request( void ssdp_handle_device_request(
IN http_message_t* hmsg, IN http_message_t* hmsg,
IN struct sockaddr_in* dest_addr ); IN struct sockaddr* dest_addr );
#else #else
static inline void ssdp_handle_device_request( static inline void ssdp_handle_device_request(
IN http_message_t* hmsg, IN http_message_t* hmsg,
IN struct sockaddr_in* dest_addr ) {} IN struct sockaddr* dest_addr ) {}
#endif #endif
/************************************************************************ /************************************************************************
@ -226,7 +231,7 @@ static inline void ssdp_handle_device_request(
* *
* Parameters: * Parameters:
* IN http_message_t* hmsg: SSDP message from the device * 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 * IN xboolean timeout: timeout kept by the control point while sending
* search message * search message
* IN void* cookie: Cookie stored by the control point application. * 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( void ssdp_handle_ctrlpt_msg(
IN http_message_t* hmsg, IN http_message_t* hmsg,
IN struct sockaddr_in* dest_addr, IN struct sockaddr* dest_addr,
IN xboolean timeout, IN xboolean timeout,
IN void* cookie ); IN void* cookie );
@ -356,6 +361,7 @@ int SearchByTarget(IN int Mx, IN char *St, IN void *Cookie);
* IN char *Udn : * IN char *Udn :
* IN char *Location: Location URL. * IN char *Location: Location URL.
* IN int Duration : Service duration in sec. * IN int Duration : Service duration in sec.
* IN int AddressFamily: Device address family.
* *
* Description: * Description:
* This function creates the device advertisement request based on * This function creates the device advertisement request based on
@ -369,7 +375,8 @@ int DeviceAdvertisement(
IN int RootDev, IN int RootDev,
IN char *Udn, IN char *Udn,
IN char *Location, IN char *Location,
IN int Duration); IN int Duration,
IN int AddressFamily);
/************************************************************************ /************************************************************************
@ -382,6 +389,7 @@ int DeviceAdvertisement(
* IN char *_Server: * IN char *_Server:
* IN char *Location: Location URL * IN char *Location: Location URL
* IN int Duration :Device duration in sec. * IN int Duration :Device duration in sec.
* IN int AddressFamily: Device address family.
* *
* Description: * Description:
* This function creates a HTTP device shutdown request packet * This function creates a HTTP device shutdown request packet
@ -396,13 +404,14 @@ int DeviceShutdown(
IN char *Udn, IN char *Udn,
IN char *_Server, IN char *_Server,
IN char *Location, IN char *Location,
IN int Duration); IN int Duration,
IN int AddressFamily);
/************************************************************************ /************************************************************************
* Function : DeviceReply * Function : DeviceReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in * DestAddr:destination IP address. * IN struct sockaddr *DestAddr: destination IP address.
* IN char *DevType: Device type * IN char *DevType: Device type
* IN int RootDev: 1 means root device 0 means embedded device. * IN int RootDev: 1 means root device 0 means embedded device.
* IN char *Udn: Device UDN * IN char *Udn: Device UDN
@ -417,17 +426,18 @@ int DeviceShutdown(
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int DeviceReply( int DeviceReply(
IN struct sockaddr_in * DestAddr, IN struct sockaddr *DestAddr,
IN char *DevType, IN char *DevType,
IN int RootDev, IN int RootDev,
IN char *Udn, IN char *Udn,
IN char *Location, IN int Duration); IN char *Location,
IN int Duration);
/************************************************************************ /************************************************************************
* Function : SendReply * Function : SendReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in * DestAddr:destination IP address. * IN struct sockaddr *DestAddr: destination IP address.
* IN char *DevType: Device type * IN char *DevType: Device type
* IN int RootDev: 1 means root device 0 means embedded device. * IN int RootDev: 1 means root device 0 means embedded device.
* IN char * Udn: Device UDN * IN char * Udn: Device UDN
@ -444,7 +454,7 @@ int DeviceReply(
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int SendReply( int SendReply(
IN struct sockaddr_in * DestAddr, IN struct sockaddr *DestAddr,
IN char *DevType, IN char *DevType,
IN int RootDev, IN int RootDev,
IN char *Udn, IN char *Udn,
@ -460,6 +470,7 @@ int SendReply(
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char * Location: Location of Device description document. * 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: * Description:
* This function creates the advertisement packet based * This function creates the advertisement packet based
@ -472,13 +483,14 @@ int ServiceAdvertisement(
IN char *Udn, IN char *Udn,
IN char *ServType, IN char *ServType,
IN char *Location, IN char *Location,
IN int Duration); IN int Duration,
IN int AddressFamily);
/************************************************************************ /************************************************************************
* Function : ServiceReply * Function : ServiceReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in *DestAddr: * IN struct sockaddr *DestAddr:
* IN char *Udn: Device UDN * IN char *Udn: Device UDN
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char *Server: Not used * IN char *Server: Not used
@ -493,7 +505,7 @@ int ServiceAdvertisement(
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int ServiceReply( int ServiceReply(
IN struct sockaddr_in *DestAddr, IN struct sockaddr *DestAddr,
IN char *ServType, IN char *ServType,
IN char *Udn, IN char *Udn,
IN char *Location, IN char *Location,
@ -507,6 +519,7 @@ int ServiceReply(
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char *Location: Location of Device description document. * IN char *Location: Location of Device description document.
* IN int Duration :Service duration in sec. * IN int Duration :Service duration in sec.
* IN int AddressFamily: Device address family
* *
* Description: * Description:
* This function creates a HTTP service shutdown request packet * This function creates a HTTP service shutdown request packet
@ -519,7 +532,8 @@ int ServiceShutdown(
IN char *Udn, IN char *Udn,
IN char *ServType, IN char *ServType,
IN char *Location, IN char *Location,
IN int Duration); IN int Duration,
IN int AddressFamily);
/************************************************************************ /************************************************************************
@ -546,7 +560,7 @@ void *advertiseAndReplyThread(IN void * data);
* 1 = Send Advertisement * 1 = Send Advertisement
* IN UpnpDevice_Handle Hnd: Device handle * IN UpnpDevice_Handle Hnd: Device handle
* IN enum SsdpSearchType SearchType:Search type for sending replies * 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 *DeviceType:Device type
* IN char *DeviceUDN:Device UDN * IN char *DeviceUDN:Device UDN
* IN char *ServiceType:Service type * IN char *ServiceType:Service type
@ -562,10 +576,10 @@ int AdvertiseAndReply(
IN int AdFlag, IN int AdFlag,
IN UpnpDevice_Handle Hnd, IN UpnpDevice_Handle Hnd,
IN enum SsdpSearchType SearchType, IN enum SsdpSearchType SearchType,
IN struct sockaddr_in *DestAddr, IN struct sockaddr *DestAddr,
IN char *DeviceType, IN char *DeviceType,
IN char *DeviceUDN, IN char *DeviceUDN,
IN char *ServiceType, int Exp); IN char *ServiceType, int Exp);
#endif #endif /* SSDPLIB_H */

View File

@ -1,65 +1,90 @@
/* /*
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Digital Equipment Corporation, Maynard, Mass. * Digital Equipment Corporation, Maynard, Mass.
** Copyright (c) 1998 Microsoft. * Copyright (c) 1998 Microsoft.
** To anyone who acknowledges that this file is provided "AS IS" * To anyone who acknowledges that this file is provided "AS IS"
** without any express or implied warranty: permission to use, copy, * without any express or implied warranty: permission to use, copy,
** modify, and distribute this file for any purpose is hereby * modify, and distribute this file for any purpose is hereby
** granted without fee, provided that the above copyright notices and * granted without fee, provided that the above copyright notices and
** this notice appears in all source code copies, and that none of * this notice appears in all source code copies, and that none of
** the names of Open Software Foundation, Inc., Hewlett-Packard * the names of Open Software Foundation, Inc., Hewlett-Packard
** Company, or Digital Equipment Corporation be used in advertising * Company, or Digital Equipment Corporation be used in advertising
** or publicity pertaining to distribution of the software without * or publicity pertaining to distribution of the software without
** specific, written prior permission. Neither Open Software * specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
** Corporation makes any representations about the suitability of * Corporation makes any representations about the suitability of
** this software for any purpose. * this software for any purpose.
*/ */
#include <sys/types.h>
#ifndef WIN32 #ifndef SYSDEP_H
#include <sys/time.h> #define SYSDEP_H
#endif
//#include <sys/sysinfo.h>
#include "ithread.h" #include "ithread.h"
/* change to point to where MD5 .h's live */ /* change to point to where MD5 .h's live */
/* get MD5 sample implementation from RFC 1321 */ /* get MD5 sample implementation from RFC 1321 */
#include "global.h" #include "global.h"
#include "md5.h" #include "md5.h"
#include <sys/types.h>
#ifdef WIN32
/* Do not #include <sys/time.h> */
#else
#include <sys/time.h>
#endif
/* set the following to the number of 100ns ticks of the actual /* set the following to the number of 100ns ticks of the actual
resolution of resolution of
your system's clock */ your system's clock */
#define UUIDS_PER_TICK 1024 #define UUIDS_PER_TICK 1024
/* Set the following to a call to acquire a system wide global lock /* Set the following to a call to acquire a system wide global lock
*/ */
extern ithread_mutex_t gUUIDMutex; extern ithread_mutex_t gUUIDMutex;
#define UUIDLock() ithread_mutex_lock(&gUUIDMutex) #define UUIDLock() ithread_mutex_lock(&gUUIDMutex)
#define UUIDUnlock() ithread_mutex_unlock(&gUUIDMutex) #define UUIDUnlock() ithread_mutex_unlock(&gUUIDMutex)
typedef unsigned long unsigned32; typedef unsigned long unsigned32;
typedef unsigned short unsigned16; typedef unsigned short unsigned16;
typedef unsigned char unsigned8; typedef unsigned char unsigned8;
typedef unsigned char byte; typedef unsigned char byte;
/* Set this to what your compiler uses for 64 bit data type */ /* Set this to what your compiler uses for 64 bit data type */
#ifndef WIN32 #ifdef WIN32
#define unsigned64_t unsigned long long
#else
#define unsigned64_t __int64 #define unsigned64_t __int64
#else
#define unsigned64_t unsigned long long
#endif #endif
#define I64(C) C##LL #define I64(C) C##LL
typedef unsigned64_t uuid_time_t; typedef unsigned64_t uuid_time_t;
typedef struct { typedef struct {
char nodeID[6]; char nodeID[6];
} uuid_node_t; } uuid_node_t;
void get_ieee_node_identifier(uuid_node_t *node); void get_ieee_node_identifier(uuid_node_t *node);
void get_system_time(uuid_time_t *uuid_time); void get_system_time(uuid_time_t *uuid_time);
void get_random_info(char seed[16]); void get_random_info(char seed[16]);
#endif /* SYSDEP_H */

View File

@ -1,46 +1,56 @@
/////////////////////////////////////////////////////////////////////////// /*******************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// ******************************************************************************/
/* Unix-specific network utilities */
// Unix-specific network utilities
#ifndef GENLIB_NET_UNIXUTIL_H #ifndef GENLIB_NET_UNIXUTIL_H
#define GENLIB_NET_UNIXUTIL_H #define GENLIB_NET_UNIXUTIL_H
#include <sys/types.h>
#ifndef WIN32 #include "UpnpInet.h"
#include <sys/socket.h>
#else
#ifdef WIN32
typedef int socklen_t; typedef int socklen_t;
#define EAFNOSUPPORT 97 #define EAFNOSUPPORT 97
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#endif #endif
#endif // GENLIB_NET_UNIXUTIL_H
#endif /* GENLIB_NET_UNIXUTIL_H */

View File

@ -1,42 +1,48 @@
/////////////////////////////////////////////////////////////////////////// /*******************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// ******************************************************************************/
// File : upnpapi.h
#ifndef UPNPDK_H #ifndef UPNPAPI_H
#define UPNPDK_H #define UPNPAPI_H
/*!
* \file
*/
#include "upnp.h"
#include "client_table.h" #include "client_table.h"
//#include "../ssdp/ssdplib.h" #include "upnp.h"
#include "VirtualDir.h" /* for struct VirtualDirCallbacks */
#define MAX_INTERFACES 256 #define MAX_INTERFACES 256
@ -55,80 +61,142 @@
extern size_t g_maxContentLength; extern size_t g_maxContentLength;
// 30-second timeout /* 30-second timeout */
#define UPNP_TIMEOUT 30 #define UPNP_TIMEOUT 30
typedef enum {HND_INVALID=-1,HND_CLIENT,HND_DEVICE} Upnp_Handle_Type; 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 struct Handle_Info
{ {
/*! . */
Upnp_Handle_Type HType; Upnp_Handle_Type HType;
Upnp_FunPtr Callback; // Callback function pointer. /*! Callback function pointer. */
Upnp_FunPtr Callback;
/*! . */
char *Cookie; char *Cookie;
/*! 0 = not installed; otherwise installed. */
int aliasInstalled;
// Device Only /* Device Only */
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
char DescURL[LINE_SIZE]; // URL for the use of SSDP /*! URL for the use of SSDP. */
char DescXML[LINE_SIZE]; // XML file path for device char DescURL[LINE_SIZE];
//description /*! XML file path for device description. */
char DescXML[LINE_SIZE];
int MaxAge; // Advertisement timeout /* Advertisement timeout */
IXML_Document *DescDocument;// Description parsed in int MaxAge;
//terms of DOM document /*! Description parsed in terms of DOM document. */
IXML_NodeList *DeviceList; // List of devices in the IXML_Document *DescDocument;
//description document /*! List of devices in the description document. */
IXML_NodeList *ServiceList; // List of services in the IXML_NodeList *DeviceList;
// description document /*! List of services in the description document. */
service_table ServiceTable; //table holding subscriptions and IXML_NodeList *ServiceList;
//URL information /*! Table holding subscriptions and URL information. */
service_table ServiceTable;
/*! . */
int MaxSubscriptions; int MaxSubscriptions;
/*! . */
int MaxSubscriptionTimeOut; int MaxSubscriptionTimeOut;
/*! Address family: AF_INET or AF_INET6. */
int DeviceAf;
#endif #endif
// Client only /* Client only */
#ifdef INCLUDE_CLIENT_APIS #ifdef INCLUDE_CLIENT_APIS
client_subscription *ClientSubList; //client subscription list /*! Client subscription list. */
LinkedList SsdpSearchList; // active ssdp searches ClientSubscription *ClientSubList;
/*! Active SSDP searches. */
LinkedList SsdpSearchList;
#endif #endif
int aliasInstalled; // 0 = not installed; otherwise installed
}; };
extern ithread_rwlock_t GlobalHndRWLock; 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 HandleLock() HandleWriteLock()
#define HandleWriteLock() \ #define HandleWriteLock() \
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a write lock"); \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a write lock"); \
ithread_rwlock_wrlock(&GlobalHndRWLock); \ ithread_rwlock_wrlock(&GlobalHndRWLock); \
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Write lock acquired"); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Write lock acquired");
#define HandleReadLock() \ #define HandleReadLock() \
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a read lock"); \ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Trying a read lock"); \
ithread_rwlock_rdlock(&GlobalHndRWLock); \ ithread_rwlock_rdlock(&GlobalHndRWLock); \
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Read lock acquired"); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Read lock acquired");
#define HandleUnlock() \ #define HandleUnlock() \
UpnpPrintf(UPNP_INFO, API,__FILE__, __LINE__, "Trying Unlock"); \ UpnpPrintf(UPNP_INFO, API,__FILE__, __LINE__, "Trying Unlock"); \
ithread_rwlock_unlock(&GlobalHndRWLock); \ ithread_rwlock_unlock(&GlobalHndRWLock); \
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Unlocked rwlock"); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Unlocked rwlock");
Upnp_Handle_Type GetClientHandleInfo(int *client_handle_out,
/*!
* \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); struct Handle_Info **HndInfo);
Upnp_Handle_Type GetDeviceHandleInfo(int *device_handle_out, /*!
* \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); 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 TimerThread gTimerThread;
extern ThreadPool gRecvThreadPool; extern ThreadPool gRecvThreadPool;
extern ThreadPool gSendThreadPool; extern ThreadPool gSendThreadPool;
extern ThreadPool gMiniServerThreadPool; extern ThreadPool gMiniServerThreadPool;
typedef enum { typedef enum {
SUBSCRIBE, SUBSCRIBE,
UNSUBSCRIBE, UNSUBSCRIBE,
@ -139,7 +207,9 @@ typedef enum {
DEVDESCRIPTION, DEVDESCRIPTION,
SERVDESCRIPTION, SERVDESCRIPTION,
MINI, MINI,
RENEW} UpnpFunName; RENEW
} UpnpFunName;
struct UpnpNonblockParam struct UpnpNonblockParam
{ {
@ -163,26 +233,105 @@ struct UpnpNonblockParam
extern virtualDirList *pVirtualDirList; 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 #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(); 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 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 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; extern WebServerState bWebServerState;
#endif
#endif /* UPNPAPI_H */
/************************ END OF upnpapi.h **********************/

View File

@ -1,56 +1,63 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
#ifndef URLCONFIG_H #ifndef URLCONFIG_H
#define URLCONFIG_H #define URLCONFIG_H
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h> #include "UpnpInet.h"
#include <arpa/inet.h>
#ifdef WIN32
#else #else
#include <winsock2.h> #include <arpa/inet.h>
#include <sys/socket.h>
#endif #endif
// functions available only if the web server is included
/* functions available only if the web server is included */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/************************************************************************ /************************************************************************
* Function: configure_urlbase * Function: configure_urlbase
* *
* Parameters : * Parameters :
* INOUT IXML_Document *doc ; IXML Description document * 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 * providing the IP address and port information
* IN const char* alias ; string containing the alias * IN const char* alias ; string containing the alias
* IN time_t last_modified ; time when the XML document was * IN time_t last_modified ; time when the XML document was
@ -66,19 +73,18 @@ extern "C" {
* Return : int ; * Return : int ;
* UPNP_E_SUCCESS - On Success * UPNP_E_SUCCESS - On Success
* UPNP_E_OUTOF_MEMORY - Default Error * UPNP_E_OUTOF_MEMORY - Default Error
*
* Note :
****************************************************************************/ ****************************************************************************/
int configure_urlbase( 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 const char* alias,
IN time_t last_modified, IN time_t last_modified,
OUT char docURL[LINE_SIZE]); OUT char docURL[LINE_SIZE]);
#ifdef __cplusplus #ifdef __cplusplus
} // extern C } /* extern C */
#endif #endif
#endif /* URLCONFIG_H */ #endif /* URLCONFIG_H */

View File

@ -1,50 +1,90 @@
/* /*
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Digital Equipment Corporation, Maynard, Mass. * Digital Equipment Corporation, Maynard, Mass.
** Copyright (c) 1998 Microsoft. * Copyright (c) 1998 Microsoft.
** To anyone who acknowledges that this file is provided "AS IS" * To anyone who acknowledges that this file is provided "AS IS"
** without any express or implied warranty: permission to use, copy, * without any express or implied warranty: permission to use, copy,
** modify, and distribute this file for any purpose is hereby * modify, and distribute this file for any purpose is hereby
** granted without fee, provided that the above copyright notices and * granted without fee, provided that the above copyright notices and
** this notice appears in all source code copies, and that none of * this notice appears in all source code copies, and that none of
** the names of Open Software Foundation, Inc., Hewlett-Packard * the names of Open Software Foundation, Inc., Hewlett-Packard
** Company, or Digital Equipment Corporation be used in advertising * Company, or Digital Equipment Corporation be used in advertising
** or publicity pertaining to distribution of the software without * or publicity pertaining to distribution of the software without
** specific, written prior permission. Neither Open Software * specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
** Corporation makes any representations about the suitability of * Corporation makes any representations about the suitability of
** this software for any purpose. * this software for any purpose.
*/ */
#include "sysdep.h"
/*! . */
typedef struct _uuid_upnp { typedef struct _uuid_upnp {
/*! . */
unsigned32 time_low; unsigned32 time_low;
/*! . */
unsigned16 time_mid; unsigned16 time_mid;
/*! . */
unsigned16 time_hi_and_version; unsigned16 time_hi_and_version;
/*! . */
unsigned8 clock_seq_hi_and_reserved; unsigned8 clock_seq_hi_and_reserved;
/*! . */
unsigned8 clock_seq_low; unsigned8 clock_seq_low;
/*! . */
byte node[6]; byte node[6];
} uuid_upnp; } 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
/* uuid_create_from_name -- create a UUID using a "name" /*!
from a "name space" */ * \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( void uuid_create_from_name(
uuid_upnp * uid, /* resulting UUID */ /*! Resulting UUID. */
uuid_upnp nsid, /* UUID to serve as context, so identical uuid_upnp *uid,
names from different name spaces generate /*! UUID to serve as context, so identical names from different name
different UUIDs */ * spaces generate different UUIDs. */
void * name, /* the name from which to generate a UUID */ uuid_upnp nsid,
int namelen /* the length of the name */ /*! The name from which to generate a UUID. */
void *name,
/*! The length of the name. */
int namelen
); );
/* uuid_compare -- Compare two UUID's "lexically" and return
-1 u1 is lexically before u2 /*!
0 u1 is equal to u2 * \brief Compare two UUID's "lexically".
1 u1 is lexically after u2 *
Note: lexical ordering is not temporal ordering! * \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); int uuid_compare(
/*! . */
uuid_upnp *u1,
/*! . */
uuid_upnp *u2);

View File

@ -1,57 +1,68 @@
/////////////////////////////////////////////////////////////////////////// /*******************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// ******************************************************************************/
/*!
* \file
*/
#include "config.h" #include "config.h"
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
#if EXCLUDE_SOAP == 0 #if EXCLUDE_SOAP == 0
#define SOAP_BODY "Body" #define SOAP_BODY "Body"
#define SOAP_URN "http:/""/schemas.xmlsoap.org/soap/envelope/" #define SOAP_URN "http:/""/schemas.xmlsoap.org/soap/envelope/"
#define QUERY_STATE_VAR_URN "urn:schemas-upnp-org:control-1-0" #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 "httpparser.h"
#include "httpreadwrite.h" #include "httpreadwrite.h"
#include "unixutil.h" #include "parsetools.h"
#include "soaplib.h" #include "soaplib.h"
#include "ssdplib.h" #include "ssdplib.h"
#include "statcodes.h"
#include "unixutil.h"
#include "upnpapi.h"
#ifdef WIN32 #ifdef WIN32
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
// timeout duration in secs for transmission/reception
/*! timeout duration in secs for transmission/reception */
#define SOAP_TIMEOUT UPNP_TIMEOUT #define SOAP_TIMEOUT UPNP_TIMEOUT
#define SREQ_HDR_NOT_FOUND -1 #define SREQ_HDR_NOT_FOUND -1
@ -65,13 +76,14 @@
static const char *Soap_Invalid_Action = "Invalid Action"; 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_Action_Failed = "Action Failed";
static const char *Soap_Invalid_Var = "Invalid Var"; static const char *Soap_Invalid_Var = "Invalid Var";
const char *ContentTypeHeader = const char *ContentTypeHeader =
"CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"; "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n";
/**************************************************************************** /****************************************************************************
* Function : get_request_type * Function : get_request_type
* *
@ -589,6 +601,7 @@ static int
get_device_info( IN http_message_t *request, get_device_info( IN http_message_t *request,
IN int isQuery, IN int isQuery,
IN IXML_Document *actionDoc, IN IXML_Document *actionDoc,
IN int AddressFamily,
OUT char device_udn[LINE_SIZE], OUT char device_udn[LINE_SIZE],
OUT char service_id[LINE_SIZE], OUT char service_id[LINE_SIZE],
OUT Upnp_FunPtr *callback, OUT Upnp_FunPtr *callback,
@ -609,7 +622,8 @@ get_device_info( IN http_message_t * request,
HandleLock(); HandleLock();
if( GetDeviceHandleInfo( &device_hnd, &device_info ) != HND_DEVICE ) { if( GetDeviceHandleInfo( AddressFamily,
&device_hnd, &device_info ) != HND_DEVICE ) {
goto error_handler; goto error_handler;
} }
@ -840,8 +854,8 @@ error_handler:
* *
* Note : * Note :
****************************************************************************/ ****************************************************************************/
static UPNP_INLINE void static UPNP_INLINE void handle_query_variable(
handle_query_variable( IN SOCKINFO * info, IN SOCKINFO *info,
IN http_message_t *request, IN http_message_t *request,
IN IXML_Document *xml_doc ) IN IXML_Document *xml_doc )
{ {
@ -859,9 +873,14 @@ handle_query_variable( IN SOCKINFO * info,
return; return;
} }
// get info for event // get info for event
if( get_device_info( request, 1, xml_doc, variable.DevUDN, err_code = get_device_info(
request, 1, xml_doc,
info->foreign_sockaddr.ss_family,
variable.DevUDN,
variable.ServiceID, variable.ServiceID,
&soap_event_callback, &cookie ) != 0 ) { &soap_event_callback,
&cookie);
if( err_code != 0 ) {
send_error_response( info, SOAP_INVALID_VAR, send_error_response( info, SOAP_INVALID_VAR,
Soap_Invalid_Var, request ); Soap_Invalid_Var, request );
return; return;
@ -871,7 +890,7 @@ handle_query_variable( IN SOCKINFO * info,
variable.ErrCode = UPNP_E_SUCCESS; variable.ErrCode = UPNP_E_SUCCESS;
namecopy( variable.StateVarName, var_name ); namecopy( variable.StateVarName, var_name );
variable.CurrentVal = NULL; variable.CurrentVal = NULL;
variable.CtrlPtIPAddr = info->foreign_ip_addr; variable.CtrlPtIPAddr = info->foreign_sockaddr;
// send event // send event
soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie ); soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie );
@ -883,8 +902,8 @@ handle_query_variable( IN SOCKINFO * info,
if( variable.CurrentVal == NULL ) { if( variable.CurrentVal == NULL ) {
err_code = SOAP_ACTION_FAILED; err_code = SOAP_ACTION_FAILED;
err_str = Soap_Action_Failed; err_str = Soap_Action_Failed;
send_error_response( info, SOAP_INVALID_VAR, send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request );
Soap_Invalid_Var, request );
return; return;
} }
if( variable.ErrCode != UPNP_E_SUCCESS ) { if( variable.ErrCode != UPNP_E_SUCCESS ) {
@ -951,8 +970,14 @@ handle_invoke_action( IN SOCKINFO * info,
goto error_handler; goto error_handler;
} }
// get device info for action event // get device info for action event
err_code = get_device_info( request, 0, xml_doc, action.DevUDN, err_code = get_device_info(
action.ServiceID, &soap_event_callback, request,
0,
xml_doc,
info->foreign_sockaddr.ss_family,
action.DevUDN,
action.ServiceID,
&soap_event_callback,
&cookie ); &cookie );
if( err_code != UPNP_E_SUCCESS ) { if( err_code != UPNP_E_SUCCESS ) {
@ -964,10 +989,9 @@ handle_invoke_action( IN SOCKINFO * info,
action.ActionRequest = resp_node; action.ActionRequest = resp_node;
action.ActionResult = NULL; action.ActionResult = NULL;
action.ErrCode = UPNP_E_SUCCESS; action.ErrCode = UPNP_E_SUCCESS;
action.CtrlPtIPAddr = info->foreign_ip_addr; action.CtrlPtIPAddr = info->foreign_sockaddr;
UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Calling Callback\n");
"Calling Callback\n" );
soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie ); soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie );

View File

@ -1,53 +1,60 @@
/////////////////////////////////////////////////////////////////////////// /**************************************************************************
// *
// Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2000-2003 Intel Corporation
// All rights reserved. * All rights reserved.
// *
// Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: * 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. * 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 * this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. * 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 * may be used to endorse or promote products derived from this software
// without specific prior written permission. * without specific prior written permission.
// *
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *
/////////////////////////////////////////////////////////////////////////// **************************************************************************/
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
#ifdef INCLUDE_CLIENT_APIS #ifdef INCLUDE_CLIENT_APIS
#if EXCLUDE_SSDP == 0 #if EXCLUDE_SSDP == 0
#include "ssdplib.h"
#include "upnpapi.h"
#include <stdio.h>
#include "ThreadPool.h"
#include "httpparser.h" #include "httpparser.h"
#include "httpreadwrite.h" #include "httpreadwrite.h"
/*#include "ssdp_ResultData.h"*/
#include "ssdplib.h"
#include "statcodes.h" #include "statcodes.h"
#include "unixutil.h" #include "unixutil.h"
#include "upnpapi.h"
#include "UpnpInet.h"
#include "ThreadPool.h"
#include <stdio.h>
#ifdef WIN32 #ifdef WIN32
#include <ws2tcpip.h>
#include <winsock2.h>
#include <string.h> #include <string.h>
#endif /* WIN32 */ #endif /* WIN32 */
@ -65,8 +72,7 @@
* Returns: void * Returns: void
* *
***************************************************************************/ ***************************************************************************/
void void send_search_result(IN void *data)
send_search_result( IN void *data )
{ {
ResultData *temp = ( ResultData * ) data; ResultData *temp = ( ResultData * ) data;
@ -79,11 +85,15 @@ send_search_result( IN void *data )
* Function: ssdp_handle_ctrlpt_msg * Function: ssdp_handle_ctrlpt_msg
* *
* Parameters: * Parameters:
* IN http_message_t* hmsg: SSDP message from the device * IN http_message_t *hmsg:
* IN struct sockaddr_in* dest_addr: Address of the device * SSDP message from the device
* IN xboolean timeout: timeout kept by the control point while * IN struct sockaddr *dest_addr:
* Address of the device
* IN xboolean timeout:
* timeout kept by the control point while
* sending search message * sending search message
* IN void* cookie: Cookie stored by the control point application. * IN void* cookie:
* Cookie stored by the control point application.
* This cookie will be returned to the control point * This cookie will be returned to the control point
* in the callback * in the callback
* *
@ -95,11 +105,10 @@ send_search_result( IN void *data )
* Returns: void * Returns: void
* *
***************************************************************************/ ***************************************************************************/
void void ssdp_handle_ctrlpt_msg(
ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg, IN http_message_t *hmsg,
IN struct sockaddr_in *dest_addr, IN struct sockaddr *dest_addr,
IN xboolean timeout, // only in search reply IN xboolean timeout, // only in search reply
IN void *cookie) // only in search reply IN void *cookie) // only in search reply
{ {
int handle; int handle;
@ -108,9 +117,9 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
xboolean is_byebye; // byebye or alive xboolean is_byebye; // byebye or alive
struct Upnp_Discovery param; struct Upnp_Discovery param;
SsdpEvent event; SsdpEvent event;
xboolean nt_found, xboolean nt_found;
usn_found, xboolean usn_found;
st_found; xboolean st_found;
char save_char; char save_char;
Upnp_EventType event_type; Upnp_EventType event_type;
Upnp_FunPtr ctrlpt_callback; Upnp_FunPtr ctrlpt_callback;
@ -191,9 +200,7 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
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]; save_char = hdr_value.buf[hdr_value.length];
hdr_value.buf[hdr_value.length] = '\0'; hdr_value.buf[hdr_value.length] = '\0';
nt_found = ( ssdp_request_type( hdr_value.buf, &event ) == 0 ); nt_found = ( ssdp_request_type( hdr_value.buf, &event ) == 0 );
hdr_value.buf[hdr_value.length] = save_char; hdr_value.buf[hdr_value.length] = save_char;
} }
@ -201,9 +208,7 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
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]; save_char = hdr_value.buf[hdr_value.length];
hdr_value.buf[hdr_value.length] = '\0'; hdr_value.buf[hdr_value.length] = '\0';
usn_found = ( unique_service_name( hdr_value.buf, &event ) == 0 ); usn_found = ( unique_service_name( hdr_value.buf, &event ) == 0 );
hdr_value.buf[hdr_value.length] = save_char; hdr_value.buf[hdr_value.length] = save_char;
} }
@ -216,7 +221,6 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
// ADVERT. OR BYEBYE // ADVERT. OR BYEBYE
if( hmsg->is_request ) { if( hmsg->is_request ) {
// use NTS hdr to determine advert., or byebye // 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 return; // error; NTS header not found
} }
@ -243,7 +247,6 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
strlen( param.Location ) == 0 || param.Expires <= 0 ) { strlen( param.Location ) == 0 || param.Expires <= 0 ) {
return; // bad advertisement return; // bad advertisement
} }
event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE; event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
} }
@ -283,33 +286,24 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
// check for match of ST header and search target // check for match of ST header and search target
switch ( searchArg->requestType ) { switch ( searchArg->requestType ) {
case SSDP_ALL: case SSDP_ALL:
{
matched = 1; matched = 1;
break; break;
}
case SSDP_ROOTDEVICE: case SSDP_ROOTDEVICE:
{
matched = ( event.RequestType == SSDP_ROOTDEVICE ); matched = ( event.RequestType == SSDP_ROOTDEVICE );
break; break;
}
case SSDP_DEVICEUDN: case SSDP_DEVICEUDN:
{
matched = !( strncmp( searchArg->searchTarget, matched = !( strncmp( searchArg->searchTarget,
hdr_value.buf, hdr_value.buf,
hdr_value.length ) ); hdr_value.length ) );
break; break;
} case SSDP_DEVICETYPE: {
case SSDP_DEVICETYPE:
{
int m = min( hdr_value.length, int m = min( hdr_value.length,
strlen( searchArg->searchTarget ) ); strlen( searchArg->searchTarget ) );
matched = !( strncmp( searchArg->searchTarget, matched = !( strncmp( searchArg->searchTarget,
hdr_value.buf, m ) ); hdr_value.buf, m ) );
break; break;
} }
case SSDP_SERVICE: case SSDP_SERVICE: {
{
int m = min( hdr_value.length, int m = min( hdr_value.length,
strlen( searchArg->searchTarget ) ); strlen( searchArg->searchTarget ) );
@ -318,11 +312,9 @@ ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
break; break;
} }
default: default:
{
matched = 0; matched = 0;
break; break;
} }
}
if (matched) { if (matched) {
// schedule call back // schedule call back
@ -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 * Function : CreateClientRequestPacket
@ -400,6 +348,7 @@ process_reply( IN char *request_buf,
* IN char *SearchTarget:Search Target * IN char *SearchTarget:Search Target
* IN int Mx dest_addr: Number of seconds to wait to * IN int Mx dest_addr: Number of seconds to wait to
* collect all the responses * collect all the responses
* IN int AddressFamily: search address family
* *
* Description: * Description:
* This function creates a HTTP search request packet * This function creates a HTTP search request packet
@ -411,13 +360,18 @@ process_reply( IN char *request_buf,
static void static void
CreateClientRequestPacket( IN char *RqstBuf, CreateClientRequestPacket( IN char *RqstBuf,
IN int Mx, IN int Mx,
IN char *SearchTarget ) IN char *SearchTarget,
IN int AddressFamily )
{ {
char TempBuf[COMMAND_LEN]; char TempBuf[COMMAND_LEN];
strcpy( RqstBuf, "M-SEARCH * HTTP/1.1\r\n" ); strcpy( RqstBuf, "M-SEARCH * HTTP/1.1\r\n" );
if (AddressFamily == AF_INET) {
sprintf( TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT ); 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, TempBuf );
strcat( RqstBuf, "MAN: \"ssdp:discover\"\r\n" ); strcat( RqstBuf, "MAN: \"ssdp:discover\"\r\n" );
@ -431,7 +385,6 @@ CreateClientRequestPacket( IN char *RqstBuf,
strcat( RqstBuf, TempBuf ); strcat( RqstBuf, TempBuf );
} }
strcat( RqstBuf, "\r\n" ); strcat( RqstBuf, "\r\n" );
} }
/************************************************************************ /************************************************************************
@ -507,7 +460,17 @@ searchExpired( void *arg )
* This cokie will be returned to application in the callback. * This cokie will be returned to application in the callback.
* *
* Description: * 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:<device-uuid>" : Search for a particular device.
* - "urn:schemas-upnp-org:device:<deviceType:v>"
* - "urn:schemas-upnp-org:service:<serviceType:v>"
* - "urn:<domain-name>:device:<deviceType:v>"
* - "urn:<domain-name>:service:<serviceType:v>"
* *
* Returns: int * Returns: int
* 1 if successful else appropriate error * 1 if successful else appropriate error
@ -518,18 +481,23 @@ SearchByTarget( IN int Mx,
IN void *Cookie ) IN void *Cookie )
{ {
char errorBuffer[ERROR_BUFFER_LEN]; char errorBuffer[ERROR_BUFFER_LEN];
int socklen = sizeof( struct sockaddr_in ); int socklen = sizeof( struct sockaddr_storage );
int *id = NULL; int *id = NULL;
int ret = 0; int ret = 0;
char *ReqBuf; char ReqBufv4[BUFSIZE];
struct sockaddr_in destAddr; 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; fd_set wrSet;
SsdpSearchArg *newArg = NULL; SsdpSearchArg *newArg = NULL;
int timeTillRead = 0; int timeTillRead = 0;
int handle; int handle;
struct Handle_Info *ctrlpt_info = NULL; struct Handle_Info *ctrlpt_info = NULL;
enum SsdpSearchType requestType; enum SsdpSearchType requestType;
unsigned long addr = inet_addr( LOCAL_HOST ); unsigned long addrv4 = inet_addr( gIF_IPV4 );
int max_fd = 0;
//ThreadData *ThData; //ThreadData *ThData;
ThreadPoolJob job; ThreadPoolJob job;
@ -539,12 +507,7 @@ SearchByTarget( IN int Mx,
return UPNP_E_INVALID_PARAM; return UPNP_E_INVALID_PARAM;
} }
ReqBuf = (char *)malloc( BUFSIZE ); UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n");
if( ReqBuf == NULL ) {
return UPNP_E_OUTOF_MEMORY;
}
UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND >>>\n");
timeTillRead = Mx; timeTillRead = Mx;
@ -554,21 +517,24 @@ SearchByTarget( IN int Mx,
timeTillRead = MAX_SEARCH_TIME; timeTillRead = MAX_SEARCH_TIME;
} }
CreateClientRequestPacket( ReqBuf, timeTillRead, St ); CreateClientRequestPacket( ReqBufv4, timeTillRead, St, AF_INET );
memset( ( char * )&destAddr, 0, sizeof( struct sockaddr_in ) ); CreateClientRequestPacket( ReqBufv6, timeTillRead, St, AF_INET6 );
destAddr.sin_family = AF_INET; memset( &__ss_v4, 0, sizeof( __ss_v4 ) );
destAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); destAddr4->sin_family = AF_INET;
destAddr.sin_port = htons( SSDP_PORT ); inet_pton( AF_INET, SSDP_IP, &destAddr4->sin_addr );
destAddr4->sin_port = htons( SSDP_PORT );
FD_ZERO( &wrSet ); memset( &__ss_v6, 0, sizeof( __ss_v6 ) );
FD_SET( gSsdpReqSocket, &wrSet ); 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 // add search criteria to list
HandleLock(); HandleLock();
if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) { if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
HandleUnlock(); HandleUnlock();
free( ReqBuf );
return UPNP_E_INTERNAL_ERROR; return UPNP_E_INTERNAL_ERROR;
} }
@ -590,34 +556,56 @@ SearchByTarget( IN int Mx,
ListAddTail( &ctrlpt_info->SsdpSearchList, newArg ); ListAddTail( &ctrlpt_info->SsdpSearchList, newArg );
HandleUnlock(); HandleUnlock();
ret = setsockopt( gSsdpReqSocket, IPPROTO_IP, IP_MULTICAST_IF, FD_ZERO( &wrSet );
(char *)&addr, sizeof (addr) ); 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 ) { if( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
"SSDP_LIB: Error in select(): %s\n", "SSDP_LIB: Error in select(): %s\n",
errorBuffer ); errorBuffer );
shutdown( gSsdpReqSocket, SD_BOTH ); shutdown( gSsdpReqSocket4, SD_BOTH );
UpnpCloseSocket( gSsdpReqSocket ); UpnpCloseSocket( gSsdpReqSocket4 );
free( ReqBuf ); shutdown( gSsdpReqSocket6, SD_BOTH );
UpnpCloseSocket( gSsdpReqSocket6 );
return UPNP_E_INTERNAL_ERROR; return UPNP_E_INTERNAL_ERROR;
} else if( FD_ISSET( gSsdpReqSocket, &wrSet ) ) { }
if( gSsdpReqSocket6 != INVALID_SOCKET &&
FD_ISSET( gSsdpReqSocket6, &wrSet ) ) {
int NumCopy = 0; int NumCopy = 0;
while( NumCopy < NUM_SSDP_COPY ) { while( NumCopy < NUM_SSDP_COPY ) {
sendto( gSsdpReqSocket, ReqBuf, strlen( ReqBuf ), 0, sendto( gSsdpReqSocket6, ReqBufv6, strlen( ReqBufv6 ), 0,
(struct sockaddr *)&destAddr, socklen ); (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++; NumCopy++;
imillisleep( SSDP_PAUSE ); imillisleep( SSDP_PAUSE );
} }
} }
free( ReqBuf );
return 1; return 1;
} }
#endif // EXCLUDE_SSDP #endif // EXCLUDE_SSDP
#endif // INCLUDE_CLIENT_APIS #endif // INCLUDE_CLIENT_APIS

View File

@ -77,7 +77,7 @@ advertiseAndReplyThread( IN void *data )
AdvertiseAndReply( 0, arg->handle, AdvertiseAndReply( 0, arg->handle,
arg->event.RequestType, arg->event.RequestType,
&arg->dest_addr, (struct sockaddr*)&arg->dest_addr,
arg->event.DeviceType, arg->event.DeviceType,
arg->event.UDN, arg->event.UDN,
arg->event.ServiceType, arg->MaxAge ); arg->event.ServiceType, arg->MaxAge );
@ -91,7 +91,7 @@ advertiseAndReplyThread( IN void *data )
* *
* Parameters: * Parameters:
* IN http_message_t *hmsg: SSDP search request from the control point * 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: * Description:
* This function handles the search request. It do the sanity checks of * This function handles the search request. It do the sanity checks of
@ -104,7 +104,7 @@ advertiseAndReplyThread( IN void *data )
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
void void
ssdp_handle_device_request( IN http_message_t *hmsg, 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 #define MX_FUDGE_FACTOR 10
@ -144,7 +144,8 @@ ssdp_handle_device_request( IN http_message_t *hmsg,
HandleLock(); HandleLock();
// device info // device info
if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) { if( GetDeviceHandleInfo( dest_addr->sa_family,
&handle, &dev_info ) != HND_DEVICE ) {
HandleUnlock(); HandleUnlock();
return; // no info found return; // no info found
} }
@ -172,7 +173,7 @@ ssdp_handle_device_request( IN http_message_t *hmsg,
return; return;
} }
threadArg->handle = handle; threadArg->handle = handle;
threadArg->dest_addr = ( *dest_addr ); memcpy( &threadArg->dest_addr, dest_addr, sizeof(threadArg->dest_addr) );
threadArg->event = event; threadArg->event = event;
threadArg->MaxAge = maxAge; threadArg->MaxAge = maxAge;
@ -203,7 +204,7 @@ ssdp_handle_device_request( IN http_message_t *hmsg,
* Function : NewRequestHandler * Function : NewRequestHandler
* *
* Parameters: * 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 int NumPacket: Number of packet to be sent.
* IN char **RqPacket: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 * 1 if successful else appropriate error
***************************************************************************/ ***************************************************************************/
static int static int
NewRequestHandler( IN struct sockaddr_in *DestAddr, NewRequestHandler( IN struct sockaddr *DestAddr,
IN int NumPacket, IN int NumPacket,
IN char **RqPacket ) IN char **RqPacket )
{ {
char errorBuffer[ERROR_BUFFER_LEN]; char errorBuffer[ERROR_BUFFER_LEN];
int ReplySock; SOCKET ReplySock;
int socklen = sizeof( struct sockaddr_in ); int socklen = sizeof( struct sockaddr_storage );
int NumCopy; int NumCopy;
int Index; 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 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 ) { if ( ReplySock == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
@ -237,10 +240,24 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr,
return UPNP_E_OUTOF_SOCKET; return UPNP_E_OUTOF_SOCKET;
} }
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, setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&replyAddr, sizeof (replyAddr) ); (char *)&replyAddr, sizeof (replyAddr) );
setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&ttl, sizeof (int) ); (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++ ) { for( Index = 0; Index < NumPacket; Index++ ) {
int rc; int rc;
@ -258,11 +275,11 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr,
NumCopy = 0; NumCopy = 0;
while( NumCopy < NUM_COPY ) { while( NumCopy < NUM_COPY ) {
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
">>> SSDP SEND >>>\n%s\n", ">>> SSDP SEND to %s >>>\n%s\n",
*( RqPacket + Index ) ); buf_ntop, *( RqPacket + Index ) );
rc = sendto( ReplySock, *( RqPacket + Index ), rc = sendto( ReplySock, *( RqPacket + Index ),
strlen( *( RqPacket + Index ) ), strlen( *( RqPacket + Index ) ),
0, ( struct sockaddr * )DestAddr, socklen ); 0, DestAddr, socklen );
imillisleep( SSDP_PAUSE ); imillisleep( SSDP_PAUSE );
++NumCopy; ++NumCopy;
} }
@ -285,6 +302,7 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr,
* IN char * location :Location URL. * IN char * location :Location URL.
* IN int duration :Service duration in sec. * IN int duration :Service duration in sec.
* OUT char** packet :Output buffer filled with HTTP statement. * OUT char** packet :Output buffer filled with HTTP statement.
* IN int AddressFamily: Address family of the HTTP request.
* *
* Description: * Description:
* This function creates a HTTP request packet. Depending * This function creates a HTTP request packet. Depending
@ -300,7 +318,8 @@ CreateServicePacket( IN int msg_type,
IN char *usn, IN char *usn,
IN char *location, IN char *location,
IN int duration, IN int duration,
OUT char **packet ) OUT char **packet,
IN int AddressFamily)
{ {
int ret_code; int ret_code;
char *nts; char *nts;
@ -317,11 +336,13 @@ CreateServicePacket( IN int msg_type,
if( msg_type == MSGTYPE_REPLY ) { if( msg_type == MSGTYPE_REPLY ) {
ret_code = http_MakeMessage( ret_code = http_MakeMessage(
&buf, 1, 1, &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, HTTP_OK,
"CACHE-CONTROL: max-age=", duration, "CACHE-CONTROL: max-age=", duration,
"EXT:", "EXT:",
"LOCATION: ", location, "LOCATION: ", location,
"OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
"01-NLS: ", gUpnpSdkNLSuuid,
X_USER_AGENT, X_USER_AGENT,
"ST: ", nt, "ST: ", nt,
"USN: ", usn); "USN: ", usn);
@ -342,11 +363,15 @@ CreateServicePacket( IN int msg_type,
ret_code = http_MakeMessage( ret_code = http_MakeMessage(
&buf, 1, 1, &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, 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, "CACHE-CONTROL: max-age=", duration,
"LOCATION: ", location, "LOCATION: ", location,
"OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
"01-NLS: ", gUpnpSdkNLSuuid,
"NT: ", nt, "NT: ", nt,
"NTS: ", nts, "NTS: ", nts,
X_USER_AGENT, X_USER_AGENT,
@ -389,9 +414,12 @@ DeviceAdvertisement( IN char *DevType,
int RootDev, int RootDev,
char *Udn, char *Udn,
IN char *Location, 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_Nt[LINE_SIZE]
char Mil_Usn[LINE_SIZE]; char Mil_Usn[LINE_SIZE];
@ -401,9 +429,20 @@ DeviceAdvertisement( IN char *DevType,
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
"In function DeviceAdvertisement\n" ); "In function DeviceAdvertisement\n" );
DestAddr.sin_family = AF_INET; memset( &__ss, 0, sizeof(__ss) );
DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); if( AddressFamily == AF_INET ) {
DestAddr.sin_port = htons( SSDP_PORT ); 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[0] = NULL;
msgs[1] = NULL; msgs[1] = NULL;
@ -414,17 +453,17 @@ DeviceAdvertisement( IN char *DevType,
if( RootDev ) { if( RootDev ) {
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
CreateServicePacket( MSGTYPE_ADVERTISEMENT, "upnp:rootdevice", 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 // both root and sub-devices need to send these two messages
// //
CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn, CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn,
Location, Duration, &msgs[1] ); Location, Duration, &msgs[1], AddressFamily );
sprintf( Mil_Usn, "%s::%s", Udn, DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType );
CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn, CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn,
Location, Duration, &msgs[2] ); Location, Duration, &msgs[2], AddressFamily );
// check error // check error
if( ( RootDev && msgs[0] == NULL ) || if( ( RootDev && msgs[0] == NULL ) ||
@ -437,11 +476,11 @@ DeviceAdvertisement( IN char *DevType,
// send packets // send packets
if( RootDev ) { if( RootDev ) {
// send 3 msg types // send 3 msg types
ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] );
} else // sub-device } else // sub-device
{ {
// send 2 msg types // send 2 msg types
ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] );
} }
// free msgs // free msgs
@ -456,7 +495,7 @@ DeviceAdvertisement( IN char *DevType,
* Function : SendReply * Function : SendReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in * DestAddr:destination IP address. * IN struct sockaddr * DestAddr:destination IP address.
* IN char *DevType: Device type * IN char *DevType: Device type
* IN int RootDev: 1 means root device 0 means embedded device. * IN int RootDev: 1 means root device 0 means embedded device.
* IN char * Udn: Device UDN * IN char * Udn: Device UDN
@ -472,7 +511,7 @@ DeviceAdvertisement( IN char *DevType,
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int int
SendReply( IN struct sockaddr_in *DestAddr, SendReply( IN struct sockaddr *DestAddr,
IN char *DevType, IN char *DevType,
IN int RootDev, IN int RootDev,
IN char *Udn, IN char *Udn,
@ -495,7 +534,7 @@ SendReply( IN struct sockaddr_in *DestAddr,
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice", CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice",
Mil_Usn, Location, Duration, &msgs[0] ); Mil_Usn, Location, Duration, &msgs[0], DestAddr->sa_family );
} else { } else {
// two msgs for embedded devices // two msgs for embedded devices
num_msgs = 1; num_msgs = 1;
@ -503,11 +542,11 @@ SendReply( IN struct sockaddr_in *DestAddr,
//NK: FIX for extra response when someone searches by udn //NK: FIX for extra response when someone searches by udn
if( !ByType ) { if( !ByType ) {
CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location, CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location,
Duration, &msgs[0] ); Duration, &msgs[0], DestAddr->sa_family );
} else { } else {
sprintf( Mil_Usn, "%s::%s", Udn, DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType );
CreateServicePacket( MSGTYPE_REPLY, DevType, Mil_Usn, 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 * Function : DeviceReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in * DestAddr:destination IP address. * IN struct sockaddr *DestAddr:destination IP address.
* IN char *DevType: Device type * IN char *DevType: Device type
* IN int RootDev: 1 means root device 0 means embedded device. * IN int RootDev: 1 means root device 0 means embedded device.
* IN char * Udn: Device UDN * IN char * Udn: Device UDN
@ -547,7 +586,7 @@ SendReply( IN struct sockaddr_in *DestAddr,
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int int
DeviceReply( IN struct sockaddr_in *DestAddr, DeviceReply( IN struct sockaddr *DestAddr,
IN char *DevType, IN char *DevType,
IN int RootDev, IN int RootDev,
IN char *Udn, IN char *Udn,
@ -570,18 +609,18 @@ DeviceReply( IN struct sockaddr_in *DestAddr,
strcpy( Mil_Nt, "upnp:rootdevice" ); strcpy( Mil_Nt, "upnp:rootdevice" );
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, 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_Nt, "%s", Udn );
sprintf( Mil_Usn, "%s", Udn ); sprintf( Mil_Usn, "%s", Udn );
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, 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_Nt, "%s", DevType );
sprintf( Mil_Usn, "%s::%s", Udn, DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType );
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
Location, Duration, &szReq[2] ); Location, Duration, &szReq[2], DestAddr->sa_family );
// check error // check error
@ -615,6 +654,7 @@ DeviceReply( IN struct sockaddr_in *DestAddr,
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char * Location: Location of Device description document. * 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: * Description:
* This function creates the advertisement packet based * This function creates the advertisement packet based
* on the input parameter, and send it to the multicast channel. * on the input parameter, and send it to the multicast channel.
@ -626,28 +666,42 @@ int
ServiceAdvertisement( IN char *Udn, ServiceAdvertisement( IN char *Udn,
IN char *ServType, IN char *ServType,
IN char *Location, IN char *Location,
IN int Duration) IN int Duration,
IN int AddressFamily)
{ {
char Mil_Usn[LINE_SIZE]; char Mil_Usn[LINE_SIZE];
char *szReq[1]; char *szReq[1];
struct sockaddr_in DestAddr;
int RetVal; 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; memset( &__ss, 0, sizeof(__ss) );
DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); if( AddressFamily == AF_INET ) {
DestAddr.sin_port = htons( SSDP_PORT ); 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 ); sprintf( Mil_Usn, "%s::%s", Udn, ServType );
//CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn, //CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn,
//Server,Location,Duration); //Server,Location,Duration);
CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn, CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn,
Location, Duration, &szReq[0] ); Location, Duration, &szReq[0], AddressFamily );
if( szReq[0] == NULL ) { if( szReq[0] == NULL ) {
return UPNP_E_OUTOF_MEMORY; return UPNP_E_OUTOF_MEMORY;
} }
RetVal = NewRequestHandler( &DestAddr, 1, szReq ); RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq );
free( szReq[0] ); free( szReq[0] );
return RetVal; return RetVal;
@ -657,7 +711,7 @@ ServiceAdvertisement( IN char *Udn,
* Function : ServiceReply * Function : ServiceReply
* *
* Parameters: * Parameters:
* IN struct sockaddr_in *DestAddr: * IN struct sockaddr *DestAddr:
* IN char * Udn: Device UDN * IN char * Udn: Device UDN
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char * Location: Location of Device description document. * IN char * Location: Location of Device description document.
@ -670,7 +724,7 @@ ServiceAdvertisement( IN char *Udn,
* UPNP_E_SUCCESS if successful else appropriate error * UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int int
ServiceReply( IN struct sockaddr_in *DestAddr, ServiceReply( IN struct sockaddr *DestAddr,
IN char *ServType, IN char *ServType,
IN char *Udn, IN char *Udn,
IN char *Location, IN char *Location,
@ -685,7 +739,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr,
sprintf( Mil_Usn, "%s::%s", Udn, ServType ); sprintf( Mil_Usn, "%s::%s", Udn, ServType );
CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn, CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn,
Location, Duration, &szReq[0] ); Location, Duration, &szReq[0], DestAddr->sa_family );
if( szReq[0] == NULL ) { if( szReq[0] == NULL ) {
return UPNP_E_OUTOF_MEMORY; return UPNP_E_OUTOF_MEMORY;
} }
@ -704,6 +758,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr,
* IN char *ServType: Service Type. * IN char *ServType: Service Type.
* IN char * Location: Location of Device description document. * IN char * Location: Location of Device description document.
* IN int Duration :Service duration in sec. * IN int Duration :Service duration in sec.
* IN int AddressFamily: Device address family
* Description: * Description:
* This function creates a HTTP service shutdown request packet * This function creates a HTTP service shutdown request packet
* and sent it to the multicast channel through RequestHandler. * and sent it to the multicast channel through RequestHandler.
@ -715,27 +770,41 @@ int
ServiceShutdown( IN char *Udn, ServiceShutdown( IN char *Udn,
IN char *ServType, IN char *ServType,
IN char *Location, IN char *Location,
IN int Duration) IN int Duration,
IN int AddressFamily)
{ {
char Mil_Usn[LINE_SIZE]; char Mil_Usn[LINE_SIZE];
char *szReq[1]; 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; int RetVal;
DestAddr.sin_family = AF_INET; memset( &__ss, 0, sizeof(__ss) );
DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); if( AddressFamily == AF_INET ) {
DestAddr.sin_port = htons( SSDP_PORT ); 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_Nt,"%s",ServType);
sprintf( Mil_Usn, "%s::%s", Udn, ServType ); sprintf( Mil_Usn, "%s::%s", Udn, ServType );
//CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn, //CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn,
//Server,Location,Duration); //Server,Location,Duration);
CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn, CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn,
Location, Duration, &szReq[0] ); Location, Duration, &szReq[0], AddressFamily );
if( szReq[0] == NULL ) { if( szReq[0] == NULL ) {
return UPNP_E_OUTOF_MEMORY; return UPNP_E_OUTOF_MEMORY;
} }
RetVal = NewRequestHandler( &DestAddr, 1, szReq ); RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq );
free( szReq[0] ); free( szReq[0] );
return RetVal; return RetVal;
@ -750,6 +819,7 @@ ServiceShutdown( IN char *Udn,
* IN char * Udn: Device UDN * IN char * Udn: Device UDN
* IN char * Location: Location URL * IN char * Location: Location URL
* IN int Duration :Device duration in sec. * IN int Duration :Device duration in sec.
* IN int AddressFamily: Device address family.
* *
* Description: * Description:
* This function creates a HTTP device shutdown request packet * This function creates a HTTP device shutdown request packet
@ -764,9 +834,12 @@ DeviceShutdown( IN char *DevType,
IN char *Udn, IN char *Udn,
IN char *_Server, IN char *_Server,
IN char *Location, 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 *msgs[3];
char Mil_Usn[LINE_SIZE]; char Mil_Usn[LINE_SIZE];
int ret_code; int ret_code;
@ -775,26 +848,37 @@ DeviceShutdown( IN char *DevType,
msgs[1] = NULL; msgs[1] = NULL;
msgs[2] = NULL; msgs[2] = NULL;
DestAddr.sin_family = AF_INET; memset( &__ss, 0, sizeof(__ss) );
DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); if( AddressFamily == AF_INET ) {
DestAddr.sin_port = htons( SSDP_PORT ); 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 // root device has one extra msg
if( RootDev ) { if( RootDev ) {
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice", CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice",
Mil_Usn, Location, Duration, &msgs[0] ); Mil_Usn, Location, Duration, &msgs[0], AddressFamily );
} }
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
"In function DeviceShutdown\n" ); "In function DeviceShutdown\n" );
// both root and sub-devices need to send these two messages // both root and sub-devices need to send these two messages
CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn, CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn,
Location, Duration, &msgs[1] ); Location, Duration, &msgs[1], AddressFamily );
sprintf( Mil_Usn, "%s::%s", Udn, DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType );
CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn, CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn,
Location, Duration, &msgs[2] ); Location, Duration, &msgs[2], AddressFamily );
// check error // check error
if( ( RootDev && msgs[0] == NULL ) || if( ( RootDev && msgs[0] == NULL ) ||
@ -807,11 +891,11 @@ DeviceShutdown( IN char *DevType,
// send packets // send packets
if( RootDev ) { if( RootDev ) {
// send 3 msg types // send 3 msg types
ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] );
} else // sub-device } else // sub-device
{ {
// send 2 msg types // send 2 msg types
ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] );
} }
// free msgs // free msgs

View File

@ -50,18 +50,23 @@
#define MAX_TIME_TOREAD 45 #define MAX_TIME_TOREAD 45
CLIENTONLY( SOCKET gSsdpReqSocket = 0; ) CLIENTONLY( SOCKET gSsdpReqSocket4 = INVALID_SOCKET; )
CLIENTONLY( SOCKET gSsdpReqSocket6 = INVALID_SOCKET; )
void RequestHandler(); 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; Event ErrotEvt;
enum Listener { Idle, Stopping, Running }; enum Listener { Idle, Stopping, Running };
unsigned short ssdpStopPort;
struct SSDPSockArray { struct SSDPSockArray {
// socket for incoming advertisments and search requests // socket for incoming advertisments and search requests
int ssdpSock; SOCKET ssdpSock;
// socket for sending search requests and receiving search replies // socket for sending search requests and receiving search replies
CLIENTONLY( int ssdpReqSock; ) CLIENTONLY( int ssdpReqSock; )
}; };
@ -79,7 +84,7 @@ struct SSDPSockArray {
* 1 = Send Advertisement * 1 = Send Advertisement
* IN UpnpDevice_Handle Hnd: Device handle * IN UpnpDevice_Handle Hnd: Device handle
* IN enum SsdpSearchType SearchType:Search type for sending replies * 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 *DeviceType:Device type
* IN char *DeviceUDN:Device UDN * IN char *DeviceUDN:Device UDN
* IN char *ServiceType:Service type * IN char *ServiceType:Service type
@ -95,7 +100,7 @@ int AdvertiseAndReply(
IN int AdFlag, IN int AdFlag,
IN UpnpDevice_Handle Hnd, IN UpnpDevice_Handle Hnd,
IN enum SsdpSearchType SearchType, IN enum SsdpSearchType SearchType,
IN struct sockaddr_in *DestAddr, IN struct sockaddr *DestAddr,
IN char *DeviceType, IN char *DeviceType,
IN char *DeviceUDN, IN char *DeviceUDN,
IN char *ServiceType, IN char *ServiceType,
@ -213,11 +218,11 @@ int AdvertiseAndReply(
/* send the device advertisement */ /* send the device advertisement */
if (AdFlag == 1) { if (AdFlag == 1) {
DeviceAdvertisement(devType, i == 0, DeviceAdvertisement(devType, i == 0,
UDNstr, SInfo->DescURL, Exp); UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf );
} else { } else {
/* AdFlag == -1 */ /* AdFlag == -1 */
DeviceShutdown(devType, i == 0, UDNstr, DeviceShutdown(devType, i == 0, UDNstr,
SERVER, SInfo->DescURL, Exp); SERVER, SInfo->DescURL, Exp, SInfo->DeviceAf );
} }
} else { } else {
switch (SearchType) { switch (SearchType) {
@ -311,11 +316,11 @@ int AdvertiseAndReply(
if (AdFlag) { if (AdFlag) {
if (AdFlag == 1) { if (AdFlag == 1) {
ServiceAdvertisement(UDNstr, servType, ServiceAdvertisement(UDNstr, servType,
SInfo->DescURL, Exp); SInfo->DescURL, Exp, SInfo->DeviceAf );
} else { } else {
/* AdFlag == -1 */ /* AdFlag == -1 */
ServiceShutdown(UDNstr, servType, ServiceShutdown(UDNstr, servType,
SInfo->DescURL, Exp); SInfo->DescURL, Exp, SInfo->DeviceAf );
} }
} else { } else {
switch (SearchType) { switch (SearchType) {
@ -362,7 +367,7 @@ end_function:
* Function : Make_Socket_NoBlocking * Function : Make_Socket_NoBlocking
* *
* Parameters: * Parameters:
* IN int sock: socket * IN SOCKET sock: socket
* *
* Description: * Description:
* This function makes socket non-blocking. * This function makes socket non-blocking.
@ -371,7 +376,7 @@ end_function:
* 0 if successful else -1 * 0 if successful else -1
***************************************************************************/ ***************************************************************************/
int int
Make_Socket_NoBlocking( int sock ) Make_Socket_NoBlocking( SOCKET sock )
{ {
#ifdef WIN32 #ifdef WIN32
u_long val=1; u_long val=1;
@ -614,8 +619,11 @@ valid_ssdp_msg( IN http_message_t * hmsg )
} }
// check HOST header // check HOST header
if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) || 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; return FALSE;
} }
} }
@ -664,7 +672,7 @@ start_event_handler( void *Data )
goto error_handler; goto error_handler;
} }
// check msg // check msg
if( !valid_ssdp_msg( &parser->msg ) ) { if( valid_ssdp_msg( &parser->msg ) != TRUE ) {
goto error_handler; goto error_handler;
} }
return 0; //////// done; thread will free 'data' return 0; //////// done; thread will free 'data'
@ -699,9 +707,10 @@ ssdp_event_handler_thread( void *the_data )
// send msg to device or ctrlpt // send msg to device or ctrlpt
if( ( hmsg->method == HTTPMETHOD_NOTIFY ) || if( ( hmsg->method == HTTPMETHOD_NOTIFY ) ||
( hmsg->request_method == HTTPMETHOD_MSEARCH ) ) { ( 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 { } else {
ssdp_handle_device_request( hmsg, &data->dest_addr ); ssdp_handle_device_request( hmsg, (struct sockaddr*)&data->dest_addr );
} }
// free data // free data
@ -725,11 +734,12 @@ readFromSSDPSocket( SOCKET socket )
{ {
char *requestBuf = NULL; char *requestBuf = NULL;
char staticBuf[BUFSIZE]; char staticBuf[BUFSIZE];
struct sockaddr_in clientAddr; struct sockaddr_storage __ss;
ThreadPoolJob job; ThreadPoolJob job;
ssdp_thread_data *data = NULL; ssdp_thread_data *data = NULL;
socklen_t socklen = 0; socklen_t socklen = sizeof( __ss );
int byteReceived = 0; int byteReceived = 0;
char ntop_buf[64];
requestBuf = staticBuf; requestBuf = staticBuf;
@ -737,8 +747,6 @@ readFromSSDPSocket( SOCKET socket )
//can't be allocated, still drain the //can't be allocated, still drain the
//socket using a static buffer //socket using a static buffer
socklen = sizeof( struct sockaddr_in );
data = ( ssdp_thread_data * ) data = ( ssdp_thread_data * )
malloc( sizeof( ssdp_thread_data ) ); malloc( sizeof( ssdp_thread_data ) );
@ -746,7 +754,7 @@ readFromSSDPSocket( SOCKET socket )
//initialize parser //initialize parser
#ifdef INCLUDE_CLIENT_APIS #ifdef INCLUDE_CLIENT_APIS
if( socket == gSsdpReqSocket ) { if( socket == gSsdpReqSocket4 || socket == gSsdpReqSocket6 ) {
parser_response_init( &data->parser, HTTPMETHOD_MSEARCH ); parser_response_init( &data->parser, HTTPMETHOD_MSEARCH );
} else { } else {
parser_request_init( &data->parser ); parser_request_init( &data->parser );
@ -768,10 +776,18 @@ readFromSSDPSocket( SOCKET socket )
} }
byteReceived = recvfrom( socket, requestBuf, byteReceived = recvfrom( socket, requestBuf,
BUFSIZE - 1, 0, BUFSIZE - 1, 0,
( struct sockaddr * )&clientAddr, &socklen ); (struct sockaddr *)&__ss, &socklen );
if( byteReceived > 0 ) { if( byteReceived > 0 ) {
requestBuf[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, "<Invalid address family>", sizeof(ntop_buf) );
UpnpPrintf( UPNP_INFO, SSDP, UpnpPrintf( UPNP_INFO, SSDP,
__FILE__, __LINE__, __FILE__, __LINE__,
"Start of received response ----------------------------------------------------\n" "Start of received response ----------------------------------------------------\n"
@ -779,7 +795,7 @@ readFromSSDPSocket( SOCKET socket )
"End of received response ------------------------------------------------------\n" "End of received response ------------------------------------------------------\n"
"From host %s\n", "From host %s\n",
requestBuf, requestBuf,
inet_ntoa( clientAddr.sin_addr ) ); ntop_buf );
UpnpPrintf( UPNP_PACKET, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_PACKET, SSDP, __FILE__, __LINE__,
"Start of received multicast packet --------------------------------------------\n" "Start of received multicast packet --------------------------------------------\n"
"%s\n" "%s\n"
@ -790,7 +806,7 @@ readFromSSDPSocket( SOCKET socket )
data->parser.msg.msg.length += byteReceived; data->parser.msg.msg.length += byteReceived;
// null-terminate // null-terminate
data->parser.msg.msg.buf[byteReceived] = 0; data->parser.msg.msg.buf[byteReceived] = 0;
data->dest_addr = clientAddr; memcpy( &data->dest_addr, &__ss, sizeof(__ss) );
TPJobInit( &job, ( start_routine ) TPJobInit( &job, ( start_routine )
ssdp_event_handler_thread, data ); ssdp_event_handler_thread, data );
TPJobSetFreeFunction( &job, free_ssdp_event_handler_data ); TPJobSetFreeFunction( &job, free_ssdp_event_handler_data );
@ -805,6 +821,7 @@ readFromSSDPSocket( SOCKET socket )
} }
} }
/************************************************************************ /************************************************************************
* Function : get_ssdp_sockets * Function : get_ssdp_sockets
* *
@ -812,125 +829,252 @@ readFromSSDPSocket( SOCKET socket )
* OUT MiniServerSockArray *out: Array of SSDP sockets * OUT MiniServerSockArray *out: Array of SSDP sockets
* *
* Description: * Description:
* This function creates the ssdp sockets. It set their option to listen * This function creates the IPv4 and IPv6 ssdp sockets required by the
* for multicast traffic. * control point and device operation.
* *
* Returns: int * Returns: int
* return UPNP_E_SUCCESS if successful else returns appropriate error * return UPNP_E_SUCCESS if successful else returns appropriate error
***************************************************************************/ ***************************************************************************/
int int get_ssdp_sockets( MiniServerSockArray * out )
get_ssdp_sockets( MiniServerSockArray * out )
{ {
char errorBuffer[ERROR_BUFFER_LEN]; int retVal;
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;
#if INCLUDE_CLIENT_APIS #if INCLUDE_CLIENT_APIS
SOCKET ssdpReqSock; // Create the IPv4 socket for SSDP REQUESTS
if( strlen( gIF_IPV4 ) > 0 ) {
ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ); retVal = create_ssdp_sock_reqv4( &out->ssdpReqSock4 );
if ( ssdpReqSock == -1 ) { if( retVal != UPNP_E_SUCCESS ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); return retVal;
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, }
"Error in socket(): %s\n", errorBuffer ); // For use by ssdp control point.
gSsdpReqSocket4 = out->ssdpReqSock4;
return UPNP_E_OUTOF_SOCKET; } 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 */ #endif /* INCLUDE_CLIENT_APIS */
ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ); // Create the IPv4 socket for SSDP
if ( ssdpSock == -1 ) { 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); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in socket(): %s\n", errorBuffer ); "Error in socket(): %s\n", errorBuffer );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); )
return UPNP_E_OUTOF_SOCKET; return UPNP_E_OUTOF_SOCKET;
} }
onOff = 1; onOff = 1;
ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEADDR, ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEADDR,
(char*)&onOff, sizeof(onOff) ); (char*)&onOff, sizeof(onOff) );
if ( ret == -1) { if ( ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer ); "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) shutdown( *ssdpSock, SD_BOTH );
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) UpnpCloseSocket( *ssdpSock );
shutdown( ssdpSock, SD_BOTH );
UpnpCloseSocket( ssdpSock );
return UPNP_E_SOCKET_ERROR; return UPNP_E_SOCKET_ERROR;
} }
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__) #if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEPORT, onOff = 1;
ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT,
(char *)&onOff, sizeof(onOff) ); (char *)&onOff, sizeof(onOff) );
if ( ret == -1 ) { if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer ); "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) shutdown( *ssdpSock, SD_BOTH );
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) UpnpCloseSocket( *ssdpSock );
shutdown( ssdpSock, SD_BOTH );
UpnpCloseSocket( ssdpSock );
return UPNP_E_SOCKET_ERROR; return UPNP_E_SOCKET_ERROR;
} }
#endif /* BSD */ #endif /* BSD */
memset( (void *)&ssdpAddr, 0, sizeof( struct sockaddr_in ) ); memset( &__ss, 0, sizeof( __ss ) );
ssdpAddr.sin_family = AF_INET; ssdpAddr4->sin_family = AF_INET;
// ssdpAddr.sin_addr.s_addr = inet_addr(LOCAL_HOST); ssdpAddr4->sin_addr.s_addr = htonl( INADDR_ANY );
ssdpAddr.sin_addr.s_addr = htonl( INADDR_ANY ); ssdpAddr4->sin_port = htons( SSDP_PORT );
ssdpAddr.sin_port = htons( SSDP_PORT ); ret = bind( *ssdpSock, (struct sockaddr *)ssdpAddr4, sizeof(*ssdpAddr4) );
ret = bind( ssdpSock, (struct sockaddr *)&ssdpAddr, sizeof (ssdpAddr) );
if ( ret == -1 ) { if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in bind(), addr=0x%08X, port=%d: %s\n", "Error in bind(), addr=0x%08X, port=%d: %s\n",
INADDR_ANY, SSDP_PORT, errorBuffer ); INADDR_ANY, SSDP_PORT, errorBuffer );
shutdown( ssdpSock, SD_BOTH ); shutdown( *ssdpSock, SD_BOTH );
UpnpCloseSocket( ssdpSock ); UpnpCloseSocket( *ssdpSock );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); )
return UPNP_E_SOCKET_BIND; return UPNP_E_SOCKET_BIND;
} }
memset( (void *)&ssdpMcastAddr, 0, sizeof (struct ip_mreq) ); 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 ); ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr( SSDP_IP );
ret = setsockopt( ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, ret = setsockopt( *ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&ssdpMcastAddr, sizeof(struct ip_mreq) ); (char *)&ssdpMcastAddr, sizeof(struct ip_mreq) );
if ( ret == -1 ) { if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() IP_ADD_MEMBERSHIP (join multicast group): %s\n", "Error in setsockopt() IP_ADD_MEMBERSHIP (join multicast group): %s\n",
errorBuffer ); errorBuffer );
shutdown( ssdpSock, SD_BOTH ); shutdown( *ssdpSock, SD_BOTH );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) UpnpCloseSocket( *ssdpSock );
UpnpCloseSocket( ssdpSock );
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); )
return UPNP_E_SOCKET_ERROR; return UPNP_E_SOCKET_ERROR;
} }
/* Set multicast interface. */ /* Set multicast interface. */
memset( (void *)&addr, 0, sizeof (struct in_addr) ); memset( (void *)&addr, 0, sizeof (struct in_addr) );
addr.s_addr = inet_addr(LOCAL_HOST); addr.s_addr = inet_addr(gIF_IPV4);
ret = setsockopt(ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, ret = setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&addr, sizeof addr); (char *)&addr, sizeof addr);
if ( ret == -1 ) { if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); 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. */ /* 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) ); IP_MULTICAST_TTL, &ttl, sizeof (ttl) );
ret = setsockopt( ssdpSock, SOL_SOCKET, SO_BROADCAST, onOff = 1;
(char *)&option, sizeof (option) ); ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST,
(char*)&onOff, sizeof(onOff) );
if( ret == -1) { if( ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_BROADCAST (set broadcast): %s\n", "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n",
errorBuffer ); errorBuffer );
shutdown( ssdpSock, SD_BOTH ); shutdown( *ssdpSock, SD_BOTH );
CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) UpnpCloseSocket( *ssdpSock );
UpnpCloseSocket( ssdpSock );
CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); )
return UPNP_E_NETWORK_ERROR; return UPNP_E_NETWORK_ERROR;
} }
CLIENTONLY( out->ssdpReqSock = ssdpReqSock; ) return UPNP_E_SUCCESS;
out->ssdpSock = ssdpSock; }
/************************************************************************
* 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; return UPNP_E_SUCCESS;
} }

View File

@ -60,7 +60,7 @@
* Function : addrToString * Function : addrToString
* *
* Parameters : * 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 * the IP Address and port information
* OUT char ipaddr_port[] ; character array which will hold the * OUT char ipaddr_port[] ; character array which will hold the
* IP Address in a string format. * IP Address in a string format.
@ -73,11 +73,20 @@
* Note : * Note :
************************************************************************/ ************************************************************************/
static UPNP_INLINE void static UPNP_INLINE void
addrToString( IN const struct sockaddr_in *addr, addrToString( IN const struct sockaddr *addr,
OUT char ipaddr_port[] ) OUT char ipaddr_port[] )
{ {
sprintf( ipaddr_port, "%s:%d", inet_ntoa( addr->sin_addr ), char buf_ntop[64];
ntohs( addr->sin_port ) );
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 : * Parameters :
* INOUT IXML_Document *doc ; IXML Description document * 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 * providing the IP address and port information
* IN const char* alias ; string containing the alias * IN const char* alias ; string containing the alias
* IN time_t last_modified ; time when the XML document was * 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 * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the
* document. * document.
* INOUT IXML_Document *doc:dom document whose urlbase is to be modified * 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 * the miniserver
* IN const char* alias : a name to be used for the temp; e.g.:"foo.xml" * IN const char* alias : a name to be used for the temp; e.g.:"foo.xml"
* IN time_t last_modified : time * IN time_t last_modified : time
@ -380,7 +389,7 @@ config_description_doc( INOUT IXML_Document * doc,
************************************************************************/ ************************************************************************/
int int
configure_urlbase( INOUT IXML_Document * doc, configure_urlbase( INOUT IXML_Document * doc,
IN const struct sockaddr_in *serverAddr, IN const struct sockaddr *serverAddr,
IN const char *alias, IN const char *alias,
IN time_t last_modified, IN time_t last_modified,
OUT char docURL[LINE_SIZE] ) OUT char docURL[LINE_SIZE] )

View File

@ -1,34 +1,39 @@
/* /**************************************************************************
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. *
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Digital Equipment Corporation, Maynard, Mass. * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Copyright (c) 1998 Microsoft. * Digital Equipment Corporation, Maynard, Mass.
** To anyone who acknowledges that this file is provided "AS IS" * Copyright (c) 1998 Microsoft.
** without any express or implied warranty: permission to use, copy, * To anyone who acknowledges that this file is provided "AS IS"
** modify, and distribute this file for any purpose is hereby * without any express or implied warranty: permission to use, copy,
** granted without fee, provided that the above copyright notices and * modify, and distribute this file for any purpose is hereby
** this notice appears in all source code copies, and that none of * granted without fee, provided that the above copyright notices and
** the names of Open Software Foundation, Inc., Hewlett-Packard * this notice appears in all source code copies, and that none of
** Company, or Digital Equipment Corporation be used in advertising * the names of Open Software Foundation, Inc., Hewlett-Packard
** or publicity pertaining to distribution of the software without * Company, or Digital Equipment Corporation be used in advertising
** specific, written prior permission. Neither Open Software * or publicity pertaining to distribution of the software without
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment * specific, written prior permission. Neither Open Software
** Corporation makes any representations about the suitability of * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
** this software for any purpose. * Corporation makes any representations about the suitability of
*/ * this software for any purpose.
*
**************************************************************************/
#include "config.h" #include "config.h"
#include "uuid.h"
#include "UpnpInet.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#ifndef WIN32
#include <netinet/in.h>
#else
#include <winsock2.h>
#endif
#include "sysdep.h"
#include "uuid.h"
/* /*
various forward declarations various forward declarations
@ -386,3 +391,4 @@ uuid_compare( uuid_upnp * u1,
return 0; return 0;
}; };