/************************************************************************ * 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; }
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; }
/************************************************************************ * 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; }
/**************************************************************************** * Function: TimerThreadWorker * * Description: * Implements timer thread. * Waits for next event to occur and schedules * associated job into threadpool. * Internal Only. * Parameters: * void * arg -> is cast to TimerThread * *****************************************************************************/ static void * TimerThreadWorker( void *arg ) { TimerThread *timer = ( TimerThread * ) arg; ListNode *head = NULL; TimerEvent *nextEvent = NULL; time_t currentTime = 0; time_t nextEventTime = 0; struct timespec timeToWait; int tempId; assert( timer != NULL ); ithread_mutex_lock( &timer->mutex ); while( 1 ) { //mutex should always be locked at top of loop //Check for shutdown if( timer->shutdown ) { timer->shutdown = 0; ithread_cond_signal( &timer->condition ); ithread_mutex_unlock( &timer->mutex ); return NULL; } nextEvent = NULL; //Get the next event if possible if( timer->eventQ.size > 0 ) { head = ListHead( &timer->eventQ ); nextEvent = ( TimerEvent * ) head->item; nextEventTime = nextEvent->eventTime; } currentTime = time( NULL ); //If time has elapsed, schedule job if( ( nextEvent != NULL ) && ( currentTime >= nextEventTime ) ) { if( nextEvent->persistent ) { ThreadPoolAddPersistent( timer->tp, &nextEvent->job, &tempId ); } else { ThreadPoolAdd( timer->tp, &nextEvent->job, &tempId ); } ListDelNode( &timer->eventQ, head, 0 ); FreeTimerEvent( timer, nextEvent ); continue; } if( nextEvent != NULL ) { timeToWait.tv_nsec = 0; timeToWait.tv_sec = nextEvent->eventTime; ithread_cond_timedwait( &timer->condition, &timer->mutex, &timeToWait ); } else { ithread_cond_wait( &timer->condition, &timer->mutex ); } } }