コード例 #1
0
ファイル: miniserver.c プロジェクト: hotgloupi/upnp
/*!
 * \brief Initilize the thread pool to handle a request, sets priority for the
 * job and adds the job to the thread pool.
 */
static UPNP_INLINE void schedule_request_job(
	/*! [in] Socket Descriptor on which connection is accepted. */
	SOCKET connfd,
	/*! [in] Clients Address information. */
	struct sockaddr *clientAddr)
{
	struct mserv_request_t *request;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	request = (struct mserv_request_t *)malloc(
		sizeof (struct mserv_request_t));
	if (request == NULL) {
		UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
			"mserv %d: out of memory\n", connfd);
		sock_close(connfd);
		return;
	}

	request->connfd = connfd;
	memcpy(&request->foreign_sockaddr, clientAddr,
		sizeof(request->foreign_sockaddr));
	TPJobInit(&job, (start_routine)handle_request, (void *)request);
	TPJobSetFreeFunction(&job, free_handle_request_arg);
	TPJobSetPriority(&job, MED_PRIORITY);
	if (ThreadPoolAdd(&gMiniServerThreadPool, &job, NULL) != 0) {
		UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
			"mserv %d: cannot schedule request\n", connfd);
		free(request);
		sock_close(connfd);
		return;
	}
}
コード例 #2
0
ファイル: gena_ctrlpt.c プロジェクト: brolee/EMule-GIFC
/************************************************************************
* Function : ScheduleGenaAutoRenew									
*																	
* Parameters:														
*	IN int client_handle: Handle that also contains the subscription list
*	IN int TimeOut: The time out value of the subscription
*	IN client_subscription * sub: Subscription being renewed
*
* Description:														
*	This function schedules a job to renew the subscription just before
*	time out.
*
* Returns: int
*	return GENA_E_SUCCESS if successful else returns appropriate error
***************************************************************************/
static int
ScheduleGenaAutoRenew( IN int client_handle,
                       IN int TimeOut,
                       IN client_subscription * sub )
{
    struct Upnp_Event_Subscribe *RenewEventStruct = NULL;
    upnp_timeout *RenewEvent = NULL;
    int return_code = GENA_SUCCESS;
    ThreadPoolJob job;

    if( TimeOut == UPNP_INFINITE ) {
        return GENA_SUCCESS;
    }

    RenewEventStruct = ( struct Upnp_Event_Subscribe * )malloc( sizeof
                                                                ( struct
                                                                  Upnp_Event_Subscribe ) );

    if( RenewEventStruct == NULL ) {
        return UPNP_E_OUTOF_MEMORY;
    }

    RenewEvent = ( upnp_timeout * ) malloc( sizeof( upnp_timeout ) );

    if( RenewEvent == NULL ) {
        free( RenewEventStruct );
        return UPNP_E_OUTOF_MEMORY;
    }
    //schedule expire event
    strcpy( RenewEventStruct->Sid, sub->sid );
    RenewEventStruct->ErrCode = UPNP_E_SUCCESS;
    strncpy( RenewEventStruct->PublisherUrl, sub->EventURL,
             UPNP_NAME_SIZE - 1 );
    RenewEventStruct->TimeOut = TimeOut;

    //RenewEvent->EventType=UPNP_EVENT_SUBSCRIPTION_EXPIRE;
    RenewEvent->handle = client_handle;
    RenewEvent->Event = RenewEventStruct;

    TPJobInit( &job, ( start_routine ) GenaAutoRenewSubscription,
               RenewEvent );
    TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
    TPJobSetPriority( &job, MED_PRIORITY );

    //Schedule the job
    if( ( return_code = TimerThreadSchedule( &gTimerThread,
                                             TimeOut - AUTO_RENEW_TIME,
                                             REL_SEC, &job, SHORT_TERM,
                                             &( RenewEvent->
                                                eventId ) ) ) !=
        UPNP_E_SUCCESS ) {
        free( RenewEvent );
        free( RenewEventStruct );
        return return_code;
    }

    sub->RenewEventId = RenewEvent->eventId;
    return GENA_SUCCESS;
}
コード例 #3
0
/************************************************************************
 * Function: TimerThreadInit
 * 
 *  Description:
 *     Initializes and starts timer thread.
 *
 *  Parameters:
 *             timer - valid timer thread pointer.
 *             tp  - valid thread pool to use. Must be
 *                   started. Must be valid for lifetime
 *                   of timer.  Timer must be shutdown
 *                   BEFORE thread pool.
 *  Return:
 *            0 on success, nonzero on failure
 *            Returns error from ThreadPoolAddPersistent if failure.
 ************************************************************************/
int
TimerThreadInit( TimerThread * timer,
                 ThreadPool * tp )
{

    int rc = 0;

    ThreadPoolJob timerThreadWorker;

    assert( timer != NULL );
    assert( tp != NULL );

    if( ( timer == NULL ) || ( tp == NULL ) ) {
        return EINVAL;
    }

    rc += ithread_mutex_init( &timer->mutex, NULL );

    assert( rc == 0 );

    rc += ithread_mutex_lock( &timer->mutex );
    assert( rc == 0 );

    rc += ithread_cond_init( &timer->condition, NULL );
    assert( rc == 0 );

    rc += FreeListInit( &timer->freeEvents, sizeof( TimerEvent ), 100 );
    assert( rc == 0 );

    timer->shutdown = 0;
    timer->tp = tp;
    timer->lastEventId = 0;
    rc += ListInit( &timer->eventQ, NULL, NULL );

    assert( rc == 0 );

    if( rc != 0 ) {
        rc = EAGAIN;
    } else {

        TPJobInit( &timerThreadWorker, TimerThreadWorker, timer );
        TPJobSetPriority( &timerThreadWorker, HIGH_PRIORITY );

        rc = ThreadPoolAddPersistent( tp, &timerThreadWorker, NULL );
    }

    ithread_mutex_unlock( &timer->mutex );

    if( rc != 0 ) {
        ithread_cond_destroy( &timer->condition );
        ithread_mutex_destroy( &timer->mutex );
        FreeListDestroy( &timer->freeEvents );
        ListDestroy( &timer->eventQ, 0 );
    }

    return rc;

}
コード例 #4
0
ファイル: miniserver.c プロジェクト: mchalain/libdlna
/************************************************************************
 * Function: schedule_request_job
 *
 * Parameters:
 *	IN int connfd - Socket Descriptor on which connection is accepted
 *	IN struct sockaddr_in* clientAddr - Clients Address information
 *
 * Description:
 * 	Initilize the thread pool to handle a request.
 *	Sets priority for the job and adds the job to the thread pool
 *
 * Return: void
 ************************************************************************/
static DLNA_INLINE void
schedule_request_job( IN int connfd,
                      IN struct sockaddr_in *clientAddr )
{
    struct mserv_request_t *request;
    ThreadPoolJob job;

    request =
        ( struct mserv_request_t * )
        malloc( sizeof( struct mserv_request_t ) );
    if( request == NULL ) {
        dlnaPrintf( DLNA_INFO, MSERV, __FILE__, __LINE__,
            "mserv %d: out of memory\n", connfd );
        shutdown( request->connfd, SD_BOTH );
        dlnaCloseSocket( connfd );
        return;
    }

    request->connfd = connfd;
    request->foreign_ip_addr = clientAddr->sin_addr;
    request->foreign_ip_port = ntohs( clientAddr->sin_port );

    TPJobInit( &job, ( start_routine ) handle_request, ( void * )request );
    TPJobSetFreeFunction( &job, free_handle_request_arg );
    TPJobSetPriority( &job, MED_PRIORITY );

    if( ThreadPoolAdd( &gMiniServerThreadPool, &job, NULL ) != 0 ) {
        dlnaPrintf( DLNA_INFO, MSERV, __FILE__, __LINE__,
            "mserv %d: cannot schedule request\n", connfd );
            free( request );
        shutdown( connfd, SD_BOTH );
        dlnaCloseSocket( connfd );
        return;
    }

}
コード例 #5
0
ファイル: gena_device.c プロジェクト: mrjimenez/pupnp
/* We take ownership of propertySet and will free it */
static int genaNotifyAllCommon(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	DOMString propertySet)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *finger = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN NOTIFY ALL COMMON");

	/* Keep this allocation first */
	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if( servId_copy == NULL ) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
	} else {
		service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
		if (service != NULL) {
			finger = GetFirstSubscription(service);
			while (finger) {
				ThreadPoolJob *job = NULL;
				ListNode *node;

				thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
				if (thread_struct == NULL) {
					line = __LINE__;
					ret = UPNP_E_OUTOF_MEMORY;
					break;
				}

				(*reference_count)++;
				thread_struct->reference_count = reference_count;
				thread_struct->UDN = UDN_copy;
				thread_struct->servId = servId_copy;
				thread_struct->headers = headers;
				thread_struct->propertySet = propertySet;
				memset(thread_struct->sid, 0,
					sizeof(thread_struct->sid));
				strncpy(thread_struct->sid, finger->sid,
					sizeof(thread_struct->sid) - 1);
				thread_struct->ctime = time(0);
				thread_struct->device_handle = device_handle;

				maybeDiscardEvents(&finger->outgoing);
				job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob));
				if (job == NULL) {
					line = __LINE__;
					ret = UPNP_E_OUTOF_MEMORY;
					break;
				}
				memset(job, 0, sizeof(ThreadPoolJob));
				TPJobInit(job, (start_routine)genaNotifyThread, thread_struct);
				TPJobSetFreeFunction(job, (free_routine)free_notify_struct);
				TPJobSetPriority(job, MED_PRIORITY);
				node = ListAddTail(&finger->outgoing, job);

				/* If there is only one element on the list (which we just
				   added), need to kickstart the threadpool */
				if (ListSize(&finger->outgoing) == 1) {
					ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
					if (ret != 0) {
						line = __LINE__;
						if (ret == EOUTOFMEM) {
							line = __LINE__;
							ret = UPNP_E_OUTOF_MEMORY;
						}
						break;
					}
					if (node) {
						((ThreadPoolJob *)(node->item))->jobId = STALE_JOBID;
					}
				}
				finger = GetNextSubscription(service, finger);
			}
		} else {
			line = __LINE__;
			ret = GENA_E_BAD_SERVICE;
		}
	}

ExitFunction:
	/* The only case where we want to free memory here is if the
	   struct was never queued. Else, let the normal cleanup take place.
	   reference_count is allocated first so it's ok to do nothing if it's 0
	*/
	if (reference_count && *reference_count == 0) {
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END NOTIFY ALL COMMON, ret = %d",
		ret);

	return ret;
}
コード例 #6
0
ファイル: gena_device.c プロジェクト: mrjimenez/pupnp
/* We take ownership of propertySet and will free it */
static int genaInitNotifyCommon(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	DOMString propertySet,
	const Upnp_SID sid)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *sub = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;
	ThreadPoolJob *job = NULL;

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN INITIAL NOTIFY COMMON");

	job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob));
	if (job == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	memset(job, 0, sizeof(ThreadPoolJob));

	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if (servId_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
		goto ExitFunction;
	}

	service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
	if (service == NULL) {
		line = __LINE__;
		ret = GENA_E_BAD_SERVICE;
		goto ExitFunction;
	}
	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SERVICE IN INIT NOTFY: UDN %s, ServID: %s",
		UDN, servId);

	sub = GetSubscriptionSID(sid, service);
	if (sub == NULL || sub->active) {
		line = __LINE__;
		ret = GENA_E_BAD_SID;
		goto ExitFunction;
	}
	UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SUBSCRIPTION IN INIT NOTIFY: SID %s", sid);
	sub->active = 1;

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	/* schedule thread for initial notification */

	thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
	if (thread_struct == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
	} else {
		*reference_count = 1;
		thread_struct->servId = servId_copy;
		thread_struct->UDN = UDN_copy;
		thread_struct->headers = headers;
		thread_struct->propertySet = propertySet;
		memset(thread_struct->sid, 0, sizeof(thread_struct->sid));
		strncpy(thread_struct->sid, sid,
			sizeof(thread_struct->sid) - 1);
		thread_struct->ctime = time(0);
		thread_struct->reference_count = reference_count;
		thread_struct->device_handle = device_handle;

		TPJobInit(job, (start_routine)genaNotifyThread, thread_struct);
		TPJobSetFreeFunction(job, (free_routine)free_notify_struct);
		TPJobSetPriority(job, MED_PRIORITY);

		ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
		if (ret != 0) {
			if (ret == EOUTOFMEM) {
				line = __LINE__;
				ret = UPNP_E_OUTOF_MEMORY;
			}
		} else {
			ListNode *node = ListAddTail(&sub->outgoing, job);
			if (node != NULL) {
				((ThreadPoolJob *)node->item)->jobId = STALE_JOBID;
				line = __LINE__;
				ret = GENA_SUCCESS;
			} else {
				line = __LINE__;
				ret = UPNP_E_OUTOF_MEMORY;
			}
		}
	}

ExitFunction:
	if (ret != GENA_SUCCESS) {
		free(job);
		free(thread_struct);
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END INITIAL NOTIFY COMMON, ret = %d",
		ret);

	return ret;
}
コード例 #7
0
ファイル: gena_device.c プロジェクト: ffontaine/pupnp
int genaNotifyAll(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	char **VarNames,
	char **VarValues,
	int var_count)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	DOMString propertySet = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *finger = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN NOTIFY ALL");

	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if( servId_copy == NULL ) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet);
	if (ret != XML_SUCCESS) {
		line = __LINE__;
		goto ExitFunction;
	}
	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENERATED PROPERTY SET IN EXT NOTIFY: %s",
		propertySet);

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
	} else {
		service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
		if (service != NULL) {
			finger = GetFirstSubscription(service);
			while (finger) {
				thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
				if (thread_struct == NULL) {
					line = __LINE__;
					ret = UPNP_E_OUTOF_MEMORY;
					break;
				}

				(*reference_count)++;
				thread_struct->reference_count = reference_count;
				thread_struct->UDN = UDN_copy;
				thread_struct->servId = servId_copy;
				thread_struct->headers = headers;
				thread_struct->propertySet = propertySet;
				memset(thread_struct->sid, 0,
					sizeof(thread_struct->sid));
				strncpy(thread_struct->sid, finger->sid,
					sizeof(thread_struct->sid) - 1);
				thread_struct->eventKey = finger->eventKey++;
				thread_struct->device_handle = device_handle;
				/* if overflow, wrap to 1 */
				if (finger->eventKey < 0) {
					finger->eventKey = 1;
				}


				TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct);
				TPJobSetFreeFunction(&job, (free_routine)free_notify_struct);
				TPJobSetPriority(&job, MED_PRIORITY);
				ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL);
				if (ret != 0) {
					line = __LINE__;
					if (ret == EOUTOFMEM) {
						line = __LINE__;
						ret = UPNP_E_OUTOF_MEMORY;
					}
					break;
				}

				finger = GetNextSubscription(service, finger);
			}
		} else {
			line = __LINE__;
			ret = GENA_E_BAD_SERVICE;
		}
	}

ExitFunction:
	if (ret != GENA_SUCCESS || *reference_count == 0) {
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END NOTIFY ALL, ret = %d",
		ret);

	return ret;
}
コード例 #8
0
ファイル: gena_device.c プロジェクト: ffontaine/pupnp
int genaInitNotifyExt(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	IXML_Document *PropSet,
	const Upnp_SID sid)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	DOMString propertySet = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *sub = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN INITIAL NOTIFY EXT");
	
	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if( servId_copy == NULL ) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
		goto ExitFunction;
	}

	service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
	if (service == NULL) {
		line = __LINE__;
		ret = GENA_E_BAD_SERVICE;
		goto ExitFunction;
	}
	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SERVICE IN INIT NOTFY EXT: UDN %s, ServID: %s",
		UDN, servId);

	sub = GetSubscriptionSID(sid, service);
	if (sub == NULL || sub->active) {
		line = __LINE__;
		ret = GENA_E_BAD_SID;
		goto ExitFunction;
	}
	UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SUBSCRIPTION IN INIT NOTIFY EXT: SID %s", sid);
	sub->active = 1;

	if (PropSet == 0) {
		line = __LINE__;
		ret = GENA_SUCCESS;
		goto ExitFunction;
	}

	propertySet = ixmlPrintNode((IXML_Node *)PropSet);
	if (propertySet == NULL) {
		line = __LINE__;
		ret = UPNP_E_INVALID_PARAM;
		goto ExitFunction;
	}
	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENERATED PROPERTY SET IN INIT EXT NOTIFY: %s",
		propertySet);

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	/* schedule thread for initial notification */

	thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
	if (thread_struct == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
	} else {
		*reference_count = 1;
		thread_struct->servId = servId_copy;
		thread_struct->UDN = UDN_copy;
		thread_struct->headers = headers;
		thread_struct->propertySet = propertySet;
		memset(thread_struct->sid, 0, sizeof(thread_struct->sid));
		strncpy(thread_struct->sid, sid,
			sizeof(thread_struct->sid) - 1);
		thread_struct->eventKey = sub->eventKey++;
		thread_struct->reference_count = reference_count;
		thread_struct->device_handle = device_handle;

		TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct);
		TPJobSetFreeFunction(&job, (free_routine)free_notify_struct);
		TPJobSetPriority(&job, MED_PRIORITY);

		ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL);
		if (ret != 0) {
			if (ret == EOUTOFMEM) {
				line = __LINE__;
				ret = UPNP_E_OUTOF_MEMORY;
			}
		} else {
			line = __LINE__;
			ret = GENA_SUCCESS;
		}
	}

ExitFunction:
	if (ret != GENA_SUCCESS || PropSet == 0) {
		free(thread_struct);
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END INITIAL NOTIFY EXT, ret = %d",
		ret);

	return ret;
}
コード例 #9
0
ファイル: gena_device.c プロジェクト: ffontaine/pupnp
/*!
 * \brief Thread job to Notify a control point.
 *
 * It validates the subscription and copies the subscription. Also make sure
 * that events are sent in order.
 *
 * \note calls the genaNotify to do the actual work.
 */
static void genaNotifyThread(
	/*! [in] notify thread structure containing all the headers and property set info. */
	void *input)
{
	subscription *sub;
	service_info *service;
	subscription sub_copy;
	notify_thread_struct *in = (notify_thread_struct *) input;
	int return_code;
	struct Handle_Info *handle_info;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	/* This should be a HandleLock and not a HandleReadLock otherwise if there
	 * is a lot of notifications, then multiple threads will acquire a read
	 * lock and the thread which sends the notification will be blocked forever
	 * on the HandleLock at the end of this function. */
	/*HandleReadLock(); */
	HandleLock();
	/* validate context */

	if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}

	if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) ||
	    !service->active ||
	    !(sub = GetSubscriptionSID(in->sid, service)) ||
	    copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}
#ifdef UPNP_ENABLE_NOTIFICATION_REORDERING
	/*If the event is out of order push it back to the job queue */
	if (in->eventKey != sub->ToSendEventKey) {
		TPJobInit(&job, (start_routine) genaNotifyThread, input);
		TPJobSetFreeFunction(&job, (free_function) free_notify_struct);
		TPJobSetPriority(&job, MED_PRIORITY);
		/* Sleep a little before creating another thread otherwise if there is
		 * a lot of notifications to send, the device will take 100% of the CPU
		 * to create threads and push them back to the job queue. */
		imillisleep(1);
		ThreadPoolAdd(&gSendThreadPool, &job, NULL);
		freeSubscription(&sub_copy);
		HandleUnlock();
		return;
	}
#endif

	HandleUnlock();

	/* send the notify */
	return_code = genaNotify(in->headers, in->propertySet, &sub_copy);
	freeSubscription(&sub_copy);
	HandleLock();
	if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}
	/* validate context */
	if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) ||
	    !service->active ||
	    !(sub = GetSubscriptionSID(in->sid, service))) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}
	sub->ToSendEventKey++;
	if (sub->ToSendEventKey < 0)
		/* wrap to 1 for overflow */
		sub->ToSendEventKey = 1;
	if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB)
		RemoveSubscriptionSID(in->sid, service);
	free_notify_struct(in);

	HandleUnlock();
}
コード例 #10
0
ファイル: ssdp_ctrlpt.c プロジェクト: Tieske/pupnp
void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, struct sockaddr_storage *dest_addr,
			    int timeout, void *cookie)
{
	int handle;
	struct Handle_Info *ctrlpt_info = NULL;
	memptr hdr_value;
	/* byebye or alive */
	int is_byebye;
	UpnpDiscovery *param = UpnpDiscovery_new();
	int expires;
	int ret;
	SsdpEvent event;
	int nt_found;
	int usn_found;
	int st_found;
	char save_char;
	Upnp_EventType event_type;
	Upnp_FunPtr ctrlpt_callback;
	void *ctrlpt_cookie;
	ListNode *node = NULL;
	SsdpSearchArg *searchArg = NULL;
	int matched = 0;
	SSDPResultData *threadData = NULL;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	/* we are assuming that there can be only one client supported at a time */
	HandleReadLock();

	if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
		HandleUnlock();
		goto end_ssdp_handle_ctrlpt_msg;
	}
	/* copy */
	ctrlpt_callback = ctrlpt_info->Callback;
	ctrlpt_cookie = ctrlpt_info->Cookie;
	HandleUnlock();
	/* search timeout */
	if (timeout) {
		ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie);
		goto end_ssdp_handle_ctrlpt_msg;
	}

	UpnpDiscovery_set_ErrCode(param, UPNP_E_SUCCESS);
	/* MAX-AGE, assume error */
	expires = -1;
	UpnpDiscovery_set_Expires(param, expires);
	if (httpmsg_find_hdr(hmsg, HDR_CACHE_CONTROL, &hdr_value) != NULL) {
		ret = matchstr(hdr_value.buf, hdr_value.length,
			"%imax-age = %d%0", &expires);
		UpnpDiscovery_set_Expires(param, expires);
		if (ret != PARSE_OK)
			goto end_ssdp_handle_ctrlpt_msg;
	}
	/* DATE */
	if (httpmsg_find_hdr(hmsg, HDR_DATE, &hdr_value) != NULL) {
		UpnpDiscovery_strcpy_Date(param, hdr_value.buf);
	}
	/* dest addr */
	UpnpDiscovery_set_DestAddr(param, dest_addr);
	/* EXT */
	if (httpmsg_find_hdr(hmsg, HDR_EXT, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Ext(param, hdr_value.buf,
					  hdr_value.length);
	}
	/* LOCATION */
	if (httpmsg_find_hdr(hmsg, HDR_LOCATION, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Location(param, hdr_value.buf,
					       hdr_value.length);
	}
	/* SERVER / USER-AGENT */
	if (httpmsg_find_hdr(hmsg, HDR_SERVER, &hdr_value) != NULL ||
	    httpmsg_find_hdr(hmsg, HDR_USER_AGENT, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Os(param, hdr_value.buf,
					 hdr_value.length);
	}
	/* clear everything */
	event.UDN[0] = '\0';
	event.DeviceType[0] = '\0';
	event.ServiceType[0] = '\0';
	nt_found = FALSE;
	if (httpmsg_find_hdr(hmsg, HDR_NT, &hdr_value) != NULL) {
		save_char = hdr_value.buf[hdr_value.length];
		hdr_value.buf[hdr_value.length] = '\0';
		nt_found = (ssdp_request_type(hdr_value.buf, &event) == 0);
		hdr_value.buf[hdr_value.length] = save_char;
	}
	usn_found = FALSE;
	if (httpmsg_find_hdr(hmsg, HDR_USN, &hdr_value) != NULL) {
		save_char = hdr_value.buf[hdr_value.length];
		hdr_value.buf[hdr_value.length] = '\0';
		usn_found = (unique_service_name(hdr_value.buf, &event) == 0);
		hdr_value.buf[hdr_value.length] = save_char;
	}
	if (nt_found || usn_found) {
		UpnpDiscovery_strcpy_DeviceID(param, event.UDN);
		UpnpDiscovery_strcpy_DeviceType(param, event.DeviceType);
		UpnpDiscovery_strcpy_ServiceType(param, event.ServiceType);
	}
	/* ADVERT. OR BYEBYE */
	if (hmsg->is_request) {
		/* use NTS hdr to determine advert., or byebye */
		if (httpmsg_find_hdr(hmsg, HDR_NTS, &hdr_value) == NULL) {
			/* error; NTS header not found */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		if (memptr_cmp(&hdr_value, "ssdp:alive") == 0) {
			is_byebye = FALSE;
		} else if (memptr_cmp(&hdr_value, "ssdp:byebye") == 0) {
			is_byebye = TRUE;
		} else {
			/* bad value */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		if (is_byebye) {
			/* check device byebye */
			if (!nt_found || !usn_found) {
				/* bad byebye */
				goto end_ssdp_handle_ctrlpt_msg;
			}
			event_type = UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE;
		} else {
			/* check advertisement.
			 * Expires is valid if positive. This is for testing
			 * only. Expires should be greater than 1800 (30 mins) */
			if (!nt_found ||
			    !usn_found ||
			    UpnpString_get_Length(UpnpDiscovery_get_Location(param)) == 0 ||
			    UpnpDiscovery_get_Expires(param) <= 0) {
				/* bad advertisement */
				goto end_ssdp_handle_ctrlpt_msg;
			}
			event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
		}
		/* call callback */
		ctrlpt_callback(event_type, param, ctrlpt_cookie);
	} else {
		/* reply (to a SEARCH) */
		/* only checking to see if there is a valid ST header */
		st_found = FALSE;
		if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) != NULL) {
			save_char = hdr_value.buf[hdr_value.length];
			hdr_value.buf[hdr_value.length] = '\0';
			st_found =
			    ssdp_request_type(hdr_value.buf, &event) == 0;
			hdr_value.buf[hdr_value.length] = save_char;
		}
		if (hmsg->status_code != HTTP_OK ||
		    UpnpDiscovery_get_Expires(param) <= 0 ||
		    UpnpString_get_Length(UpnpDiscovery_get_Location(param)) == 0 ||
		    !usn_found || !st_found) {
			/* bad reply */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		/* check each current search */
		HandleLock();
		if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
			HandleUnlock();
			goto end_ssdp_handle_ctrlpt_msg;
		}
		node = ListHead(&ctrlpt_info->SsdpSearchList);
		/* temporary add null termination */
		/*save_char = hdr_value.buf[ hdr_value.length ]; */
		/*hdr_value.buf[ hdr_value.length ] = '\0'; */
		while (node != NULL) {
			searchArg = node->item;
			/* check for match of ST header and search target */
			switch (searchArg->requestType) {
			case SSDP_ALL:
				matched = 1;
				break;
			case SSDP_ROOTDEVICE:
				matched =
				    (event.RequestType == SSDP_ROOTDEVICE);
				break;
			case SSDP_DEVICEUDN:
				matched = !strncmp(searchArg->searchTarget,
						   hdr_value.buf,
						   hdr_value.length);
				break;
			case SSDP_DEVICETYPE:{
					size_t m = min(hdr_value.length,
						       strlen
						       (searchArg->searchTarget));
					matched =
					    !strncmp(searchArg->searchTarget,
						     hdr_value.buf, m);
					break;
				}
			case SSDP_SERVICE:{
					size_t m = min(hdr_value.length,
						       strlen
						       (searchArg->searchTarget));
					matched =
					    !strncmp(searchArg->searchTarget,
						     hdr_value.buf, m);
					break;
				}
			default:
				matched = 0;
				break;
			}
			if (matched) {
				/* schedule call back */
				threadData = SSDPResultData_new();
				if (threadData != NULL) {
					SSDPResultData_set_Param(threadData,
								 param);
					SSDPResultData_set_Cookie(threadData,
								  searchArg->
								  cookie);
					SSDPResultData_set_CtrlptCallback
					    (threadData, ctrlpt_callback);
					TPJobInit(&job, (start_routine)
						  send_search_result,
						  threadData);
					TPJobSetPriority(&job, MED_PRIORITY);
					TPJobSetFreeFunction(&job,
							     (free_routine)
							     SSDPResultData_delete);
					ThreadPoolAdd(&gRecvThreadPool, &job,
						      NULL);
				}
			}
			node = ListNext(&ctrlpt_info->SsdpSearchList, node);
		}

		HandleUnlock();
		/*ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, param, cookie ); */
	}

end_ssdp_handle_ctrlpt_msg:
	UpnpDiscovery_delete(param);
}
コード例 #11
0
ファイル: ssdp_ctrlpt.c プロジェクト: Tieske/pupnp
int SearchByTarget(int Mx, char *St, void *Cookie)
{
	char errorBuffer[ERROR_BUFFER_LEN];
	int *id = NULL;
	int ret = 0;
	char ReqBufv4[BUFSIZE];
#ifdef UPNP_ENABLE_IPV6
	char ReqBufv6[BUFSIZE];
	char ReqBufv6UlaGua[BUFSIZE];
#endif
	struct sockaddr_storage __ss_v4;
#ifdef UPNP_ENABLE_IPV6
	struct sockaddr_storage __ss_v6;
#endif
	struct sockaddr_in *destAddr4 = (struct sockaddr_in *)&__ss_v4;
#ifdef UPNP_ENABLE_IPV6
	struct sockaddr_in6 *destAddr6 = (struct sockaddr_in6 *)&__ss_v6;
#endif
	fd_set wrSet;
	SsdpSearchArg *newArg = NULL;
	int timeTillRead = 0;
	int handle;
	struct Handle_Info *ctrlpt_info = NULL;
	enum SsdpSearchType requestType;
	unsigned long addrv4 = inet_addr(gIF_IPV4);
	SOCKET max_fd = 0;
	int retVal;

	/*ThreadData *ThData; */
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	requestType = ssdp_request_type1(St);
	if (requestType == SSDP_SERROR)
		return UPNP_E_INVALID_PARAM;
	UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
		   "Inside SearchByTarget\n");
	timeTillRead = Mx;
	if (timeTillRead < MIN_SEARCH_TIME)
		timeTillRead = MIN_SEARCH_TIME;
	else if (timeTillRead > MAX_SEARCH_TIME)
		timeTillRead = MAX_SEARCH_TIME;
	retVal = CreateClientRequestPacket(ReqBufv4, sizeof(ReqBufv4), timeTillRead, St, AF_INET);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
#ifdef UPNP_ENABLE_IPV6
	retVal = CreateClientRequestPacket(ReqBufv6, sizeof(ReqBufv6), timeTillRead, St, AF_INET6);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
	retVal = CreateClientRequestPacketUlaGua(ReqBufv6UlaGua, sizeof(ReqBufv6UlaGua), timeTillRead, St, AF_INET6);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
#endif

	memset(&__ss_v4, 0, sizeof(__ss_v4));
	destAddr4->sin_family = (sa_family_t)AF_INET;
	inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr);
	destAddr4->sin_port = htons(SSDP_PORT);

#ifdef UPNP_ENABLE_IPV6
	memset(&__ss_v6, 0, sizeof(__ss_v6));
	destAddr6->sin6_family = (sa_family_t)AF_INET6;
	inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
	destAddr6->sin6_port = htons(SSDP_PORT);
	destAddr6->sin6_scope_id = gIF_INDEX;
#endif

	/* add search criteria to list */
	HandleLock();
	if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
		HandleUnlock();
		return UPNP_E_INTERNAL_ERROR;
	}
	newArg = (SsdpSearchArg *) malloc(sizeof(SsdpSearchArg));
	newArg->searchTarget = strdup(St);
	newArg->cookie = Cookie;
	newArg->requestType = requestType;
	id = (int *)malloc(sizeof(int));
	TPJobInit(&job, (start_routine) searchExpired, id);
	TPJobSetPriority(&job, MED_PRIORITY);
	TPJobSetFreeFunction(&job, (free_routine) free);
	/* Schedule a timeout event to remove search Arg */
	TimerThreadSchedule(&gTimerThread, timeTillRead,
			    REL_SEC, &job, SHORT_TERM, id);
	newArg->timeoutEventId = *id;
	ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
	HandleUnlock();
	/* End of lock */

	FD_ZERO(&wrSet);
	if (gSsdpReqSocket4 != INVALID_SOCKET) {
		setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF,
			   (char *)&addrv4, sizeof(addrv4));
		FD_SET(gSsdpReqSocket4, &wrSet);
		max_fd = max(max_fd, gSsdpReqSocket4);
	}
#ifdef UPNP_ENABLE_IPV6
	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);
	}
#endif
	ret = select(max_fd + 1, NULL, &wrSet, NULL, NULL);
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
			   "SSDP_LIB: Error in select(): %s\n", errorBuffer);
		shutdown(gSsdpReqSocket4, SD_BOTH);
		UpnpCloseSocket(gSsdpReqSocket4);
#ifdef UPNP_ENABLE_IPV6
		shutdown(gSsdpReqSocket6, SD_BOTH);
		UpnpCloseSocket(gSsdpReqSocket6);
#endif
		return UPNP_E_INTERNAL_ERROR;
	}
#ifdef UPNP_ENABLE_IPV6
	if (gSsdpReqSocket6 != INVALID_SOCKET &&
	    FD_ISSET(gSsdpReqSocket6, &wrSet)) {
		int NumCopy = 0;

		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv6UlaGua);
			sendto(gSsdpReqSocket6,
			       ReqBufv6UlaGua, strlen(ReqBufv6UlaGua), 0,
			       (struct sockaddr *)&__ss_v6,
			       sizeof(struct sockaddr_in6));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
		NumCopy = 0;
		inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr);
		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv6);
			sendto(gSsdpReqSocket6,
			       ReqBufv6, strlen(ReqBufv6), 0,
			       (struct sockaddr *)&__ss_v6,
			       sizeof(struct sockaddr_in6));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
	}
#endif /* IPv6 */
	if (gSsdpReqSocket4 != INVALID_SOCKET &&
	    FD_ISSET(gSsdpReqSocket4, &wrSet)) {
		int NumCopy = 0;
		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv4);
			sendto(gSsdpReqSocket4,
			       ReqBufv4, strlen(ReqBufv4), 0,
			       (struct sockaddr *)&__ss_v4,
			       sizeof(struct sockaddr_in));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
	}

	return 1;
}
コード例 #12
0
ファイル: miniserver.c プロジェクト: hotgloupi/upnp
int StartMiniServer(
	/*! [in,out] Port on which the server listens for incoming IPv4
	 * connections. */
	uint16_t *listen_port4, 
	/*! [in,out] Port on which the server listens for incoming IPv6
	 * connections. */
	uint16_t *listen_port6)
{
	int ret_code;
	int count;
	int max_count = 10000;
	MiniServerSockArray *miniSocket;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	switch (gMServState) {
	case MSERV_IDLE:
		break;
	default:
		/* miniserver running. */
		return UPNP_E_INTERNAL_ERROR;
	}
	miniSocket = (MiniServerSockArray *)malloc(
		sizeof (MiniServerSockArray));
	if (!miniSocket) {
		return UPNP_E_OUTOF_MEMORY;
	}
	InitMiniServerSockArray(miniSocket);
#ifdef INTERNAL_WEB_SERVER
	/* V4 and V6 http listeners. */
	ret_code = get_miniserver_sockets(
		miniSocket, *listen_port4, *listen_port6);
	if (ret_code != UPNP_E_SUCCESS) {
		free(miniSocket);
		return ret_code;
	}
#endif
	/* Stop socket (To end miniserver processing). */
	ret_code = get_miniserver_stopsock(miniSocket);
	if (ret_code != UPNP_E_SUCCESS) {
		sock_close(miniSocket->miniServerSock4);
		sock_close(miniSocket->miniServerSock6);
		free(miniSocket);
		return ret_code;
	}
	/* SSDP socket for discovery/advertising. */
	ret_code = get_ssdp_sockets(miniSocket);
	if (ret_code != UPNP_E_SUCCESS) {
		sock_close(miniSocket->miniServerSock4);
		sock_close(miniSocket->miniServerSock6);
		sock_close(miniSocket->miniServerStopSock);
		free(miniSocket);
		return ret_code;
	}
	TPJobInit(&job, (start_routine)RunMiniServer, (void *)miniSocket);
	TPJobSetPriority(&job, MED_PRIORITY);
	TPJobSetFreeFunction(&job, (free_routine)free);
	ret_code = ThreadPoolAddPersistent(&gMiniServerThreadPool, &job, NULL);
	if (ret_code < 0) {
		sock_close(miniSocket->miniServerSock4);
		sock_close(miniSocket->miniServerSock6);
		sock_close(miniSocket->miniServerStopSock);
		sock_close(miniSocket->ssdpSock4);
		sock_close(miniSocket->ssdpSock6);
		sock_close(miniSocket->ssdpSock6UlaGua);
#ifdef INCLUDE_CLIENT_APIS
		sock_close(miniSocket->ssdpReqSock4);
		sock_close(miniSocket->ssdpReqSock6);
#endif /* INCLUDE_CLIENT_APIS */
		return UPNP_E_OUTOF_MEMORY;
	}
	/* Wait for miniserver to start. */
	count = 0;
	while (gMServState != (MiniServerState)MSERV_RUNNING && count < max_count) {
		/* 0.05s */
		usleep(50u * 1000u);
		count++;
	}
	if (count >= max_count) {
		/* Took it too long to start that thread. */
		sock_close(miniSocket->miniServerSock4);
		sock_close(miniSocket->miniServerSock6);
		sock_close(miniSocket->miniServerStopSock);
		sock_close(miniSocket->ssdpSock4);
		sock_close(miniSocket->ssdpSock6);
		sock_close(miniSocket->ssdpSock6UlaGua);
#ifdef INCLUDE_CLIENT_APIS
		sock_close(miniSocket->ssdpReqSock4);
		sock_close(miniSocket->ssdpReqSock6);
#endif /* INCLUDE_CLIENT_APIS */
		return UPNP_E_INTERNAL_ERROR;
	}
#ifdef INTERNAL_WEB_SERVER
	*listen_port4 = miniSocket->miniServerPort4;
	*listen_port6 = miniSocket->miniServerPort6;
#endif

	return UPNP_E_SUCCESS;
}
コード例 #13
0
ファイル: miniserver.c プロジェクト: mchalain/libdlna
/************************************************************************
 * Function: StartMiniServer
 *
 * Parameters :
 *	unsigned short listen_port - Port on which the server listens for 
 *		incoming connections
 *
 * Description:
 * 	Initialize the sockets functionality for the 
 *	Miniserver. Initialize a thread pool job to run the MiniServer
 *	and the job to the thread pool. If listen port is 0, port is 
 *	dynamically picked
 *
 *	Use timer mechanism to start the MiniServer, failure to meet the 
 *	allowed delay aborts the attempt to launch the MiniServer.
 *
 * Return: int
 *	Actual port socket is bound to - On Success
 *	A negative number DLNA_E_XXX - On Error
 ************************************************************************/
int
StartMiniServer( unsigned short listen_port )
{
    int success;
    int count;
    int max_count = 10000;

    MiniServerSockArray *miniSocket;
    ThreadPoolJob job;

    if( gMServState != MSERV_IDLE ) {
        return DLNA_E_INTERNAL_ERROR;   // miniserver running
    }

    miniSocket =
        ( MiniServerSockArray * ) malloc( sizeof( MiniServerSockArray ) );
    if( miniSocket == NULL )
        return DLNA_E_OUTOF_MEMORY;

    if( ( success = get_miniserver_sockets( miniSocket, listen_port ) )
        != DLNA_E_SUCCESS ) {
        free( miniSocket );
        return success;
    }

    if( ( success = get_ssdp_sockets( miniSocket ) ) != DLNA_E_SUCCESS ) {
        shutdown( miniSocket->miniServerSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerSock );
        shutdown( miniSocket->miniServerStopSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerStopSock );
        free( miniSocket );

        return success;
    }

    TPJobInit( &job, ( start_routine ) RunMiniServer,
               ( void * )miniSocket );
    TPJobSetPriority( &job, MED_PRIORITY );

    TPJobSetFreeFunction( &job, ( free_routine ) free );

    success = ThreadPoolAddPersistent( &gMiniServerThreadPool, &job, NULL );

    if( success < 0 ) {
        shutdown( miniSocket->miniServerSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerSock );
        shutdown( miniSocket->miniServerStopSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerStopSock );
        shutdown( miniSocket->ssdpSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->ssdpSock );
#ifdef INCLUDE_CLIENT_APIS
        shutdown( miniSocket->ssdpReqSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->ssdpReqSock );
#endif

        return DLNA_E_OUTOF_MEMORY;
    }
    // wait for miniserver to start
    count = 0;
    while( gMServState != MSERV_RUNNING && count < max_count ) {
        usleep( 50 * 1000 );    // 0.05s
        count++;
    }

    // taking too long to start that thread
    if( count >= max_count ) {
        shutdown( miniSocket->miniServerSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerSock );
        shutdown( miniSocket->miniServerStopSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->miniServerStopSock );
        shutdown( miniSocket->ssdpSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->ssdpSock );
#ifdef INCLUDE_CLIENT_APIS
        shutdown( miniSocket->ssdpReqSock, SD_BOTH );
        dlnaCloseSocket( miniSocket->ssdpReqSock );
#endif

        return DLNA_E_INTERNAL_ERROR;
    }

    return miniSocket->miniServerPort;
}
コード例 #14
0
ファイル: ssdp_server.c プロジェクト: darkphase/LXiMedia
void readFromSSDPSocket(SOCKET socket)
{
	char *requestBuf = NULL;
	char staticBuf[BUFSIZE];
	struct sockaddr_storage __ss;
	ThreadPoolJob job;
	ssdp_thread_data *data = NULL;
	socklen_t socklen = sizeof(__ss);
	ssize_t byteReceived = 0;
	char ntop_buf[INET6_ADDRSTRLEN];

	memset(&job, 0, sizeof(job));

	requestBuf = staticBuf;
	/* in case memory can't be allocated, still drain the socket using a
	 * static buffer. */
	data = malloc(sizeof(ssdp_thread_data));
	if (data) {
		/* initialize parser */
#ifdef INCLUDE_CLIENT_APIS
		if (socket == gSsdpReqSocket4
	#ifdef UPNP_ENABLE_IPV6
		    || socket == gSsdpReqSocket6
	#endif /* UPNP_ENABLE_IPV6 */
		    )
			parser_response_init(&data->parser, HTTPMETHOD_MSEARCH);
		else
			parser_request_init(&data->parser);
#else /* INCLUDE_CLIENT_APIS */
		parser_request_init(&data->parser);
#endif /* INCLUDE_CLIENT_APIS */
		/* set size of parser buffer */
		if (membuffer_set_size(&data->parser.msg.msg, BUFSIZE) == 0)
			/* use this as the buffer for recv */
			requestBuf = data->parser.msg.msg.buf;
		else {
			free(data);
			data = NULL;
		}
	}
	byteReceived = recvfrom(socket, requestBuf, BUFSIZE - (size_t)1, 0,
				(struct sockaddr *)&__ss, &socklen);
    if ((byteReceived > 0) && IsBoundAddress(((struct sockaddr_in *)&__ss)->sin_addr.s_addr)) {
		requestBuf[byteReceived] = '\0';
		switch (__ss.ss_family) {
		case AF_INET:
			inet_ntop(AF_INET,
				  &((struct sockaddr_in *)&__ss)->sin_addr,
				  ntop_buf, sizeof(ntop_buf));
			break;
#ifdef UPNP_ENABLE_IPV6
		case AF_INET6:
			inet_ntop(AF_INET6,
				  &((struct sockaddr_in6 *)&__ss)->sin6_addr,
				  ntop_buf, sizeof(ntop_buf));
			break;
#endif /* UPNP_ENABLE_IPV6 */
		default:
			memset(ntop_buf, 0, sizeof(ntop_buf));
			strncpy(ntop_buf, "<Invalid address family>",
				sizeof(ntop_buf) - 1);
		}
		UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
			   "Start of received response ----------------------------------------------------\n"
			   "%s\n"
			   "End of received response ------------------------------------------------------\n"
			   "From host %s\n", requestBuf, ntop_buf);
		/* add thread pool job to handle request */
		if (data != NULL) {
			data->parser.msg.msg.length += (size_t) byteReceived;
			/* null-terminate */
			data->parser.msg.msg.buf[byteReceived] = 0;
			memcpy(&data->dest_addr, &__ss, sizeof(__ss));
			TPJobInit(&job, (start_routine)
				  ssdp_event_handler_thread, data);
			TPJobSetFreeFunction(&job,
					     free_ssdp_event_handler_data);
			TPJobSetPriority(&job, MED_PRIORITY);
			if (ThreadPoolAdd(&gRecvThreadPool, &job, NULL) != 0)
				free_ssdp_event_handler_data(data);
		}
	} else
		free_ssdp_event_handler_data(data);
}
コード例 #15
0
ファイル: ssdp_ctrlpt.c プロジェクト: e1z0/sMule
/************************************************************************
* Function : ssdp_handle_ctrlpt_msg											
*																	
* Parameters:														
*	IN http_message_t* hmsg: SSDP message from the device
*	IN struct sockaddr_in* dest_addr: Address of the device
*	IN xboolean timeout: timeout kept by the control point while sending 
*						search message
*	IN void* cookie: Cookie stored by the control point application. 
*					This cookie will be returned to the control point
*					in the callback 
*																	
* Description:														
*	This function handles the ssdp messages from the devices. These 
*	messages includes the search replies, advertisement of device coming 
*	alive and bye byes.
*
* Returns: void
*
***************************************************************************/
void
ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
                        IN struct sockaddr_in *dest_addr,
                        IN xboolean timeout,    // only in search reply

                        IN void *cookie )   // only in search reply
{
    int handle;
    struct Handle_Info *ctrlpt_info = NULL;
    memptr hdr_value;
    xboolean is_byebye;         // byebye or alive
    struct Upnp_Discovery param;
    SsdpEvent event;
    xboolean nt_found,
      usn_found,
      st_found;
    char save_char;
    Upnp_EventType event_type;
    Upnp_FunPtr ctrlpt_callback;
    void *ctrlpt_cookie;
    ListNode *node = NULL;
    SsdpSearchArg *searchArg = NULL;
    int matched = 0;
    ResultData *threadData;
    ThreadPoolJob job;

    // we are assuming that there can be only one client supported at a time

    HandleLock(  );

    if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
        HandleUnlock(  );
        return;
    }
    // copy
    ctrlpt_callback = ctrlpt_info->Callback;
    ctrlpt_cookie = ctrlpt_info->Cookie;
    HandleUnlock(  );

    // search timeout
    if( timeout ) {
        ctrlpt_callback( UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie );
        return;
    }

    param.ErrCode = UPNP_E_SUCCESS;

    // MAX-AGE
    param.Expires = -1;         // assume error
    if( httpmsg_find_hdr( hmsg, HDR_CACHE_CONTROL, &hdr_value ) != NULL ) {
        matchstr( hdr_value.buf, hdr_value.length,
                  "%imax-age = %d%0", &param.Expires );
    }

    // DATE
    param.Date[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_DATE, &hdr_value ) != NULL ) {
        linecopylen( param.Date, hdr_value.buf, hdr_value.length );
    }

    // dest addr
    param.DestAddr = dest_addr;

    // EXT
    param.Ext[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_EXT, &hdr_value ) != NULL ) {
        linecopylen( param.Ext, hdr_value.buf, hdr_value.length );
    }
    // LOCATION
    param.Location[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_LOCATION, &hdr_value ) != NULL ) {
        linecopylen( param.Location, hdr_value.buf, hdr_value.length );
    }
    // SERVER / USER-AGENT
    param.Os[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_SERVER, &hdr_value ) != NULL ||
        httpmsg_find_hdr( hmsg, HDR_USER_AGENT, &hdr_value ) != NULL ) {
        linecopylen( param.Os, hdr_value.buf, hdr_value.length );
    }
    // clear everything
    param.DeviceId[0] = '\0';
    param.DeviceType[0] = '\0';
    param.ServiceType[0] = '\0';

    param.ServiceVer[0] = '\0'; // not used; version is in ServiceType

    event.UDN[0] = '\0';
    event.DeviceType[0] = '\0';
    event.ServiceType[0] = '\0';

    nt_found = FALSE;

    if( httpmsg_find_hdr( hmsg, HDR_NT, &hdr_value ) != NULL ) {
        save_char = hdr_value.buf[hdr_value.length];
        hdr_value.buf[hdr_value.length] = '\0';

        nt_found = ( ssdp_request_type( hdr_value.buf, &event ) == 0 );

        hdr_value.buf[hdr_value.length] = save_char;
    }

    usn_found = FALSE;
    if( httpmsg_find_hdr( hmsg, HDR_USN, &hdr_value ) != NULL ) {
        save_char = hdr_value.buf[hdr_value.length];
        hdr_value.buf[hdr_value.length] = '\0';

        usn_found = ( unique_service_name( hdr_value.buf, &event ) == 0 );

        hdr_value.buf[hdr_value.length] = save_char;
    }

    if( nt_found || usn_found ) {
        strcpy( param.DeviceId, event.UDN );
        strcpy( param.DeviceType, event.DeviceType );
        strcpy( param.ServiceType, event.ServiceType );
    }

    // ADVERT. OR BYEBYE
    if( hmsg->is_request ) {
        // use NTS hdr to determine advert., or byebye
        //
        if( httpmsg_find_hdr( hmsg, HDR_NTS, &hdr_value ) == NULL ) {
            return;             // error; NTS header not found
        }
        if( memptr_cmp( &hdr_value, "ssdp:alive" ) == 0 ) {
            is_byebye = FALSE;
        } else if( memptr_cmp( &hdr_value, "ssdp:byebye" ) == 0 ) {
            is_byebye = TRUE;
        } else {
            return;             // bad value
        }

        if( is_byebye ) {
            // check device byebye
            if( !nt_found || !usn_found ) {
                return;         // bad byebye
            }
            event_type = UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE;
        } else {
            // check advertisement      
            // .Expires is valid if positive. This is for testing
            //  only. Expires should be greater than 1800 (30 mins)
            if( !nt_found ||
                !usn_found ||
                strlen( param.Location ) == 0 || param.Expires <= 0 ) {
                return;         // bad advertisement
            }

            event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
        }

        // call callback
        ctrlpt_callback( event_type, &param, ctrlpt_cookie );

    } else                      // reply (to a SEARCH)
    {
        // only checking to see if there is a valid ST header
        st_found = FALSE;
        if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) != NULL ) {
            save_char = hdr_value.buf[hdr_value.length];
            hdr_value.buf[hdr_value.length] = '\0';
            st_found = ssdp_request_type( hdr_value.buf, &event ) == 0;
            hdr_value.buf[hdr_value.length] = save_char;
        }
        if( hmsg->status_code != HTTP_OK ||
            param.Expires <= 0 ||
            strlen( param.Location ) == 0 || !usn_found || !st_found ) {
            return;             // bad reply
        }
        //check each current search
        HandleLock(  );
        if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
            HandleUnlock(  );
            return;
        }
        node = ListHead( &ctrlpt_info->SsdpSearchList );

        //temporary add null termination
        //save_char = hdr_value.buf[ hdr_value.length ];
        //hdr_value.buf[ hdr_value.length ] = '\0';

        while( node != NULL ) {
            searchArg = node->item;
            matched = 0;
            //check for match of ST header and search target
            switch ( searchArg->requestType ) {
                case SSDP_ALL:
                    {
                        matched = 1;
                        break;
                    }
                case SSDP_ROOTDEVICE:
                    {
                        matched = ( event.RequestType == SSDP_ROOTDEVICE );
                        break;
                    }
                case SSDP_DEVICEUDN:
                    {
                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf,
                                              hdr_value.length ) );
                        break;
                    }
                case SSDP_DEVICETYPE:
                    {
                        int m = min( hdr_value.length,
                                     strlen( searchArg->searchTarget ) );

                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf, m ) );
                        break;
                    }
                case SSDP_SERVICE:
                    {
                        int m = min( hdr_value.length,
                                     strlen( searchArg->searchTarget ) );

                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf, m ) );
                        break;
                    }
                default:
                    {
                        matched = 0;
                        break;
                    }
            }

            if( matched ) {
                //schedule call back
                threadData =
                    ( ResultData * ) malloc( sizeof( ResultData ) );
                if( threadData != NULL ) {
                    threadData->param = param;
                    threadData->cookie = searchArg->cookie;
                    threadData->ctrlpt_callback = ctrlpt_callback;
                    TPJobInit( &job, ( start_routine ) send_search_result,
                               threadData );
                    TPJobSetPriority( &job, MED_PRIORITY );
                    TPJobSetFreeFunction( &job, ( free_routine ) free );
                    ThreadPoolAdd( &gRecvThreadPool, &job, NULL );
                }
            }
            node = ListNext( &ctrlpt_info->SsdpSearchList, node );
        }

        HandleUnlock(  );
        //ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, &param, cookie );
    }
}
コード例 #16
0
/*!
 * \brief Schedules a job to renew the subscription just before time out.
 *
 * \return GENA_E_SUCCESS if successful, otherwise returns the appropriate
 * 	error code.
 */
static int ScheduleGenaAutoRenew(
	/*! [in] Handle that also contains the subscription list. */
	IN int client_handle,
	/*! [in] The time out value of the subscription. */
	IN int TimeOut,
	/*! [in] Subscription being renewed. */
	IN ClientSubscription *sub)
{
	struct Upnp_Event_Subscribe *RenewEventStruct = NULL;
	upnp_timeout *RenewEvent = NULL;
	int return_code = GENA_SUCCESS;
	ThreadPoolJob job;
	const UpnpString *tmpSID = UpnpClientSubscription_get_SID(sub);
	const UpnpString *tmpEventURL = UpnpClientSubscription_get_EventURL(sub);

	memset(&job, 0, sizeof(job));

	if (TimeOut == UPNP_INFINITE) {
		return_code = GENA_SUCCESS;
		goto end_function;
	}

	RenewEventStruct = (struct Upnp_Event_Subscribe *)malloc(sizeof (struct Upnp_Event_Subscribe));
	if (RenewEventStruct == NULL) {
		return_code = UPNP_E_OUTOF_MEMORY;
		goto end_function;
	}
	memset(RenewEventStruct, 0, sizeof(struct Upnp_Event_Subscribe));

	RenewEvent = (upnp_timeout *) malloc(sizeof(upnp_timeout));
	if (RenewEvent == NULL) {
		free(RenewEventStruct);
		return_code = UPNP_E_OUTOF_MEMORY;
		goto end_function;
	}
	memset(RenewEvent, 0, sizeof(upnp_timeout));

	/* schedule expire event */
	RenewEventStruct->ErrCode = UPNP_E_SUCCESS;
	RenewEventStruct->TimeOut = TimeOut;
	strncpy(RenewEventStruct->Sid, UpnpString_get_String(tmpSID),
		sizeof(RenewEventStruct->Sid) - 1);
	strncpy(RenewEventStruct->PublisherUrl,
		UpnpString_get_String(tmpEventURL), NAME_SIZE - 1);

	/* RenewEvent->EventType=UPNP_EVENT_SUBSCRIPTION_EXPIRE; */
	RenewEvent->handle = client_handle;
	RenewEvent->Event = RenewEventStruct;

	TPJobInit(&job, (start_routine) GenaAutoRenewSubscription, RenewEvent);
	TPJobSetFreeFunction(&job, (free_routine)free_upnp_timeout);
	TPJobSetPriority(&job, MED_PRIORITY);

	/* Schedule the job */
	return_code = TimerThreadSchedule(
		&gTimerThread,
		TimeOut - AUTO_RENEW_TIME,
		REL_SEC,
		&job, SHORT_TERM,
		&(RenewEvent->eventId));
	if (return_code != UPNP_E_SUCCESS) {
		free(RenewEvent);
		free(RenewEventStruct);
		goto end_function;
	}

	UpnpClientSubscription_set_RenewEventId(sub, RenewEvent->eventId);

	return_code = GENA_SUCCESS;

end_function:
	return return_code;
}