📄 miniserver.c
字号:
( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in select call !!!\n" ); ) continue; } else { if( FD_ISSET( miniServSock, &rdSet ) ) { clientLen = sizeof( struct sockaddr_in ); connectHnd = accept( miniServSock, ( struct sockaddr * )&clientAddr, &clientLen ); if( connectHnd == UPNP_INVALID_SOCKET ) { DBGONLY( UpnpPrintf ( UPNP_INFO, MSERV, __FILE__, __LINE__, "miniserver: Error" " in accepting connection\n" ); ) continue; } schedule_request_job( connectHnd, &clientAddr ); } //ssdp CLIENTONLY( if( FD_ISSET( ssdpReqSock, &rdSet ) ) { readFromSSDPSocket( ssdpReqSock );} ) if( FD_ISSET( ssdpSock, &rdSet ) ) { readFromSSDPSocket( ssdpSock ); } if( FD_ISSET( miniServStopSock, &rdSet ) ) { clientLen = sizeof( struct sockaddr_in ); memset( ( char * )&clientAddr, 0, sizeof( struct sockaddr_in ) ); byteReceived = recvfrom( miniServStopSock, requestBuf, 25, 0, ( struct sockaddr * )&clientAddr, &clientLen ); if( byteReceived > 0 ) { requestBuf[byteReceived] = '\0'; DBGONLY( UpnpPrintf ( UPNP_INFO, MSERV, __FILE__, __LINE__, "Received response !!! %s From host %s \n", requestBuf, inet_ntoa( clientAddr.sin_addr ) ); ) DBGONLY( UpnpPrintf ( UPNP_PACKET, MSERV, __FILE__, __LINE__, "Received multicast packet: \n %s\n", requestBuf ); ) if( NULL != strstr( requestBuf, "ShutDown" ) ) break; } } } } shutdown( miniServSock, SD_BOTH ); UpnpCloseSocket( miniServSock ); shutdown( miniServStopSock, SD_BOTH ); UpnpCloseSocket( miniServStopSock ); shutdown( ssdpSock, SD_BOTH ); UpnpCloseSocket( ssdpSock ); CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) ); CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) ); free( miniSock ); gMServState = MSERV_IDLE; return;}/************************************************************************* Function : get_port** Parameters :* int sockfd ; Socket Descriptor ** Description : Returns port to which socket, sockfd, is bound.** Return : int, * -1 on error; check errno* > 0 means port number** Note :************************************************************************/static intget_port( int sockfd ){ struct sockaddr_in sockinfo; int len; int code; int port; len = sizeof( struct sockaddr_in ); code = getsockname( sockfd, ( struct sockaddr * )&sockinfo, &len ); if( code == -1 ) { return -1; } port = ntohs( sockinfo.sin_port ); DBGONLY( UpnpPrintf ( UPNP_INFO, MSERV, __FILE__, __LINE__, "sockfd = %d, .... port = %d\n", sockfd, port ); ) return port;}/************************************************************************* Function : get_miniserver_sockets** Parameters :* MiniServerSockArray *out ; Socket Array* unsigned short listen_port ; port on which the server is listening * for incoming connections ** Description : Creates a STREAM socket, binds to INADDR_ANY and * listens for incoming connecttions. Returns the actual port which * the sockets sub-system returned. * Also creates a DGRAM socket, binds to the loop back address and * returns the port allocated by the socket sub-system.** Return : int : * UPNP_E_OUTOF_SOCKET - Failed to create a socket* UPNP_E_SOCKET_BIND - Bind() failed* UPNP_E_LISTEN - Listen() failed * UPNP_E_INTERNAL_ERROR - Port returned by the socket layer is < 0* UPNP_E_SUCCESS - Success* * Note :************************************************************************/intget_miniserver_sockets( MiniServerSockArray * out, unsigned short listen_port ){ struct sockaddr_in serverAddr; int listenfd; int success; unsigned short actual_port; int reuseaddr_on = 0; int sockError = UPNP_E_SUCCESS; int errCode = 0; int miniServerStopSock; listenfd = socket( AF_INET, SOCK_STREAM, 0 ); if( listenfd <= 0 ) { return UPNP_E_OUTOF_SOCKET; // error creating socket } // As per the IANA specifications for the use of ports by applications // override the listen port passed in with the first available if( listen_port < APPLICATION_LISTENING_PORT ) listen_port = APPLICATION_LISTENING_PORT; memset( &serverAddr, 0, sizeof( serverAddr ) ); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl( INADDR_ANY ); // Getting away with implementation of re-using address:port and instead // choosing to increment port numbers. // Keeping the re-use address code as an optional behaviour that can be // turned on if necessary. // TURN ON the reuseaddr_on option to use the option. if( reuseaddr_on ) { //THIS IS ALLOWS US TO BIND AGAIN IMMEDIATELY //AFTER OUR SERVER HAS BEEN CLOSED //THIS MAY CAUSE TCP TO BECOME LESS RELIABLE //HOWEVER IT HAS BEEN SUGESTED FOR TCP SERVERS DBGONLY( UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, "mserv start: resuseaddr set\n" ); ) sockError = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, ( const char * )&reuseaddr_on, sizeof( int ) ); if( sockError == UPNP_SOCKETERROR ) { shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); return UPNP_E_SOCKET_BIND; } sockError = bind( listenfd, ( struct sockaddr * )&serverAddr, sizeof( struct sockaddr_in ) ); } else { do { serverAddr.sin_port = htons( listen_port++ ); sockError = bind( listenfd, ( struct sockaddr * )&serverAddr, sizeof( struct sockaddr_in ) ); if( sockError == UPNP_SOCKETERROR ) { if( errno == EADDRINUSE ) errCode = 1; } else errCode = 0; } while( errCode != 0 ); } if( sockError == UPNP_SOCKETERROR ) { DBGONLY( perror( "mserv start: bind failed" ); ) shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); return UPNP_E_SOCKET_BIND; // bind failed } DBGONLY( UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, "mserv start: bind success\n" ); ) success = listen( listenfd, SOMAXCONN ); if( success == UPNP_SOCKETERROR ) { shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); return UPNP_E_LISTEN; // listen failed } actual_port = get_port( listenfd ); if( actual_port <= 0 ) { shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); return UPNP_E_INTERNAL_ERROR; } out->miniServerPort = actual_port; if( ( miniServerStopSock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == UPNP_INVALID_SOCKET ) { DBGONLY( UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__, "Error in socket operation !!!\n" ); ) shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); return UPNP_E_OUTOF_SOCKET; } // bind to local socket memset( ( char * )&serverAddr, 0, sizeof( struct sockaddr_in ) ); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); if( bind( miniServerStopSock, ( struct sockaddr * )&serverAddr, sizeof( serverAddr ) ) == UPNP_SOCKETERROR ) { DBGONLY( UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__, "Error in binding localhost!!!\n" ); ) shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( listenfd ); shutdown( miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniServerStopSock ); return UPNP_E_SOCKET_BIND; } miniStopSockPort = get_port( miniServerStopSock ); if( miniStopSockPort <= 0 ) { shutdown( miniServerStopSock, SD_BOTH ); shutdown( listenfd, SD_BOTH ); UpnpCloseSocket( miniServerStopSock ); UpnpCloseSocket( listenfd ); return UPNP_E_INTERNAL_ERROR; } out->stopPort = miniStopSockPort; out->miniServerSock = listenfd; out->miniServerStopSock = miniServerStopSock; return UPNP_E_SUCCESS;}/************************************************************************* Function : StartMiniServer** Parameters :* unsigned short listen_port ; Port on which the server listens for * incoming connections** Description : Initialize the sockets functionality for the * Miniserver. Initialize a thread pool job to run the MiniServer* and the job to the thread pool. If listen port is 0, port is * dynamically picked** Use timer mechanism to start the MiniServer, failure to meet the * allowed delay aborts the attempt to launch the MiniServer.** Return : int ;* Actual port socket is bound to - On Success: * A negative number UPNP_E_XXX - On Error * Note :************************************************************************/intStartMiniServer( unsigned short listen_port ){ int success; int count; int max_count = 10000; MiniServerSockArray *miniSocket; ThreadPoolJob job; if( gMServState != MSERV_IDLE ) { return UPNP_E_INTERNAL_ERROR; // miniserver running } miniSocket = ( MiniServerSockArray * ) malloc( sizeof( MiniServerSockArray ) ); if( miniSocket == NULL ) return UPNP_E_OUTOF_MEMORY; if( ( success = get_miniserver_sockets( miniSocket, listen_port ) ) != UPNP_E_SUCCESS ) { free( miniSocket ); return success; } if( ( success = get_ssdp_sockets( miniSocket ) ) != UPNP_E_SUCCESS ) { free( miniSocket ); shutdown( miniSocket->miniServerSock, SD_BOTH ); UpnpCloseSocket( miniSocket->miniServerSock ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniSocket->miniServerStopSock ); return success; } TPJobInit( &job, ( start_routine ) RunMiniServer, ( void * )miniSocket ); TPJobSetPriority( &job, MED_PRIORITY ); TPJobSetFreeFunction( &job, ( free_routine ) free ); success = ThreadPoolAddPersistent( &gRecvThreadPool, &job, NULL ); if( success < 0 ) { shutdown( miniSocket->miniServerSock, SD_BOTH ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); shutdown( miniSocket->ssdpSock, SD_BOTH ); CLIENTONLY( shutdown( miniSocket->ssdpReqSock, SD_BOTH ) ); UpnpCloseSocket( miniSocket->miniServerSock ); UpnpCloseSocket( miniSocket->miniServerStopSock ); UpnpCloseSocket( miniSocket->ssdpSock ); CLIENTONLY( UpnpCloseSocket( miniSocket->ssdpReqSock ) ); return UPNP_E_OUTOF_MEMORY; } // wait for miniserver to start count = 0; while( gMServState != MSERV_RUNNING && count < max_count ) { usleep( 50 * 1000 ); // 0.05s count++; } // taking too long to start that thread if( count >= max_count ) { shutdown( miniSocket->miniServerSock, SD_BOTH ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); shutdown( miniSocket->ssdpSock, SD_BOTH ); CLIENTONLY( shutdown( miniSocket->ssdpReqSock, SD_BOTH ) ); UpnpCloseSocket( miniSocket->miniServerSock ); UpnpCloseSocket( miniSocket->miniServerStopSock ); UpnpCloseSocket( miniSocket->ssdpSock ); CLIENTONLY( UpnpCloseSocket( miniSocket->ssdpReqSock ) ); return UPNP_E_INTERNAL_ERROR; } return miniSocket->miniServerPort;}/************************************************************************* Function : StopMiniServer** Parameters :* void ; ** Description : Stop and Shutdown the MiniServer and free socket * resources.** Return : int ;* Always returns 0 ** Note :************************************************************************/intStopMiniServer( void ){ int socklen = sizeof( struct sockaddr_in ), sock; struct sockaddr_in ssdpAddr; char buf[256] = "ShutDown"; int bufLen = strlen( buf ); if( gMServState == MSERV_RUNNING ) gMServState = MSERV_STOPPING; else return 0; sock = socket( AF_INET, SOCK_DGRAM, 0 ); if( sock == UPNP_INVALID_SOCKET ) { DBGONLY( UpnpPrintf ( UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_SERVER:StopSSDPServer: Error in socket operation !!!\n" ); ) return 0; } while( gMServState != MSERV_IDLE ) { ssdpAddr.sin_family = AF_INET; ssdpAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); ssdpAddr.sin_port = htons( miniStopSockPort ); sendto( sock, buf, bufLen, 0, ( struct sockaddr * )&ssdpAddr, socklen ); usleep( 1000 ); if( gMServState == MSERV_IDLE ) break; isleep( 1 ); } shutdown( sock, SD_BOTH ); UpnpCloseSocket( sock ); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -