miniserver.c

来自「原来由英特尔制定的UPnP SDK的」· C语言 代码 · 共 853 行 · 第 1/2 页

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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?