pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / genlib / miniserver / miniserver.c
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000-2003 Intel Corporation 
4 // All rights reserved. 
5 //
6 // Redistribution and use in source and binary forms, with or without 
7 // modification, are permitted provided that the following conditions are met: 
8 //
9 // * Redistributions of source code must retain the above copyright notice, 
10 // this list of conditions and the following disclaimer. 
11 // * Redistributions in binary form must reproduce the above copyright notice, 
12 // this list of conditions and the following disclaimer in the documentation 
13 // and/or other materials provided with the distribution. 
14 // * Neither name of Intel Corporation nor the names of its contributors 
15 // may be used to endorse or promote products derived from this software 
16 // without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 ///////////////////////////////////////////////////////////////////////////
31
32 /************************************************************************
33 * Purpose: This file implements the functionality and utility functions
34 * used by the Miniserver module.
35 ************************************************************************/
36
37 #include "config.h"
38
39 #ifndef WIN32
40         #include <arpa/inet.h>
41         #include <netinet/in.h>
42         #include <sys/socket.h>
43         #include <sys/wait.h>
44         #include <unistd.h>
45         #include <sys/time.h>
46 #else /* WIN32 */
47         #include <winsock2.h>
48
49         typedef int socklen_t;
50         #define EAFNOSUPPORT 97
51 #endif /* WIN32 */
52
53 #include "unixutil.h"
54 #include "ithread.h"
55
56 #include <assert.h>
57 #include <errno.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <sys/types.h>
62
63 #include "ssdplib.h"
64
65 #include "util.h"
66 #include "miniserver.h"
67 #include "ThreadPool.h"
68 #include "httpreadwrite.h"
69 #include "statcodes.h"
70 #include "upnpapi.h"
71
72 #define APPLICATION_LISTENING_PORT 49152
73
74 struct mserv_request_t {
75     int connfd;                 // connection handle
76     struct in_addr foreign_ip_addr;
77     unsigned short foreign_ip_port;
78 };
79
80 typedef enum { MSERV_IDLE, MSERV_RUNNING, MSERV_STOPPING } MiniServerState;
81
82 unsigned short miniStopSockPort;
83
84 ////////////////////////////////////////////////////////////////////////////
85 // module vars
86 static MiniServerCallback gGetCallback = NULL;
87 static MiniServerCallback gSoapCallback = NULL;
88 static MiniServerCallback gGenaCallback = NULL;
89 static MiniServerState gMServState = MSERV_IDLE;
90
91 /************************************************************************
92  * Function: SetHTTPGetCallback
93  *
94  * Parameters :
95  *      MiniServerCallback callback - HTTP Callback to be invoked 
96  *
97  * Description:
98  *      Set HTTP Get Callback
99  *
100  * Return: void
101  ************************************************************************/
102 void
103 SetHTTPGetCallback( MiniServerCallback callback )
104 {
105     gGetCallback = callback;
106 }
107
108 /************************************************************************
109  * Function: SetSoapCallback
110  *
111  * Parameters:
112  *      MiniServerCallback callback - SOAP Callback to be invoked 
113  *
114  * Description:
115  *      Set SOAP Callback
116  *
117  * Return: void
118  ************************************************************************/
119 #ifdef INCLUDE_DEVICE_APIS
120 void
121 SetSoapCallback( MiniServerCallback callback )
122 {
123     gSoapCallback = callback;
124 }
125 #endif /* INCLUDE_DEVICE_APIS */
126
127 /************************************************************************
128  * Function: SetGenaCallback
129  *
130  * Parameters:
131  *      MiniServerCallback callback - GENA Callback to be invoked
132  *
133  * Description:
134  *      Set GENA Callback
135  *
136  * Return: void
137  ************************************************************************/
138 void
139 SetGenaCallback( MiniServerCallback callback )
140 {
141     gGenaCallback = callback;
142 }
143
144 /************************************************************************
145  * Function :   dispatch_request
146  *
147  * Parameters :
148  *      IN SOCKINFO *info       - Socket Information object.
149  *      http_parser_t* hparser  - HTTP parser object.
150  *
151  * Description :
152  *      Based on the type pf message, appropriate callback is issued
153  *
154  * Return: int
155  *      0 - On Success
156  *      HTTP_INTERNAL_SERVER_ERROR - Callback is NULL
157  ************************************************************************/
158 static int
159 dispatch_request( IN SOCKINFO * info,
160                   http_parser_t * hparser )
161 {
162     MiniServerCallback callback;
163
164     switch ( hparser->msg.method ) {
165             //Soap Call
166         case SOAPMETHOD_POST:
167         case HTTPMETHOD_MPOST:
168             callback = gSoapCallback;
169             break;
170
171             //Gena Call
172         case HTTPMETHOD_NOTIFY:
173         case HTTPMETHOD_SUBSCRIBE:
174         case HTTPMETHOD_UNSUBSCRIBE:
175             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
176                 "miniserver %d: got GENA msg\n", info->socket );
177             callback = gGenaCallback;
178             break;
179
180             //HTTP server call
181         case HTTPMETHOD_GET:
182         case HTTPMETHOD_POST:
183         case HTTPMETHOD_HEAD:
184         case HTTPMETHOD_SIMPLEGET:
185             callback = gGetCallback;
186             break;
187
188         default:
189             callback = NULL;
190     }
191
192     if( callback == NULL ) {
193         return HTTP_INTERNAL_SERVER_ERROR;
194     }
195
196     callback( hparser, &hparser->msg, info );
197     return 0;
198 }
199
200 /************************************************************************
201  * Function: handle_error
202  *
203  * Parameters:
204  *      IN SOCKINFO *info       - Socket Inforamtion Object
205  *      int http_error_code     - HTTP Error Code
206  *      int major               - Major Version Number
207  *      int minor               - Minor Version Number
208  *
209  * Description:
210  *      Send Error Message
211  *
212  * Return: void
213  ************************************************************************/
214 static UPNP_INLINE void
215 handle_error( IN SOCKINFO * info,
216               int http_error_code,
217               int major,
218               int minor )
219 {
220     http_SendStatusResponse( info, http_error_code, major, minor );
221 }
222
223 /************************************************************************
224  * Function: free_handle_request_arg
225  *
226  * Parameters:
227  *      void *args ; Request Message to be freed
228  *
229  * Description:
230  *      Free memory assigned for handling request and unitialize socket
231  *      functionality
232  *
233  * Return: void
234  ************************************************************************/
235 static void
236 free_handle_request_arg( void *args )
237 {
238     struct mserv_request_t *request = ( struct mserv_request_t * )args;
239
240     shutdown( request->connfd, SD_BOTH );
241     UpnpCloseSocket( request->connfd );
242     free( request );
243 }
244
245 /************************************************************************
246  * Function: handle_request
247  *
248  * Parameters:
249  *      void *args - Request Message to be handled
250  *
251  * Description:
252  *      Receive the request and dispatch it for handling
253  *
254  * Return: void
255  ************************************************************************/
256 static void
257 handle_request( void *args )
258 {
259     SOCKINFO info;
260     int http_error_code;
261     int ret_code;
262     int major = 1;
263     int minor = 1;
264     http_parser_t parser;
265     http_message_t *hmsg = NULL;
266     int timeout = HTTP_DEFAULT_TIMEOUT;
267     struct mserv_request_t *request = ( struct mserv_request_t * )args;
268     int connfd = request->connfd;
269
270     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
271         "miniserver %d: READING\n", connfd );
272     //parser_request_init( &parser ); ////LEAK_FIX_MK
273     hmsg = &parser.msg;
274
275     if( sock_init_with_ip( &info, connfd, request->foreign_ip_addr,
276                            request->foreign_ip_port ) != UPNP_E_SUCCESS ) {
277         free( request );
278         httpmsg_destroy( hmsg );
279         return;
280     }
281     // read
282     ret_code = http_RecvMessage( &info, &parser, HTTPMETHOD_UNKNOWN,
283                                  &timeout, &http_error_code );
284     if( ret_code != 0 ) {
285         goto error_handler;
286     }
287
288     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
289         "miniserver %d: PROCESSING...\n", connfd );
290     // dispatch
291     http_error_code = dispatch_request( &info, &parser );
292     if( http_error_code != 0 ) {
293         goto error_handler;
294     }
295
296     http_error_code = 0;
297
298   error_handler:
299     if( http_error_code > 0 ) {
300         if( hmsg ) {
301             major = hmsg->major_version;
302             minor = hmsg->minor_version;
303         }
304         handle_error( &info, http_error_code, major, minor );
305     }
306
307     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
308         "miniserver %d: COMPLETE\n", connfd );
309     sock_destroy( &info, SD_BOTH ); //should shutdown completely
310
311     httpmsg_destroy( hmsg );
312     free( request );
313 }
314
315 /************************************************************************
316  * Function: schedule_request_job
317  *
318  * Parameters:
319  *      IN int connfd - Socket Descriptor on which connection is accepted
320  *      IN struct sockaddr_in* clientAddr - Clients Address information
321  *
322  * Description:
323  *      Initilize the thread pool to handle a request.
324  *      Sets priority for the job and adds the job to the thread pool
325  *
326  * Return: void
327  ************************************************************************/
328 static UPNP_INLINE void
329 schedule_request_job( IN int connfd,
330                       IN struct sockaddr_in *clientAddr )
331 {
332     struct mserv_request_t *request;
333     ThreadPoolJob job;
334
335     request =
336         ( struct mserv_request_t * )
337         malloc( sizeof( struct mserv_request_t ) );
338     if( request == NULL ) {
339         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
340             "mserv %d: out of memory\n", connfd );
341         shutdown( request->connfd, SD_BOTH );
342         UpnpCloseSocket( connfd );
343         return;
344     }
345
346     request->connfd = connfd;
347     request->foreign_ip_addr = clientAddr->sin_addr;
348     request->foreign_ip_port = ntohs( clientAddr->sin_port );
349
350     TPJobInit( &job, ( start_routine ) handle_request, ( void * )request );
351     TPJobSetFreeFunction( &job, free_handle_request_arg );
352     TPJobSetPriority( &job, MED_PRIORITY );
353
354     if( ThreadPoolAdd( &gMiniServerThreadPool, &job, NULL ) != 0 ) {
355         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
356             "mserv %d: cannot schedule request\n", connfd );
357             free( request );
358         shutdown( connfd, SD_BOTH );
359         UpnpCloseSocket( connfd );
360         return;
361     }
362
363 }
364
365 /************************************************************************
366  * Function: RunMiniServer
367  *
368  * Parameters:
369  *      MiniServerSockArray *miniSock - Socket Array
370  *
371  * Description:
372  *      Function runs the miniserver. The MiniServer accepts a 
373  *      new request and schedules a thread to handle the new request.
374  *      Checks for socket state and invokes appropriate read and shutdown 
375  *      actions for the Miniserver and SSDP sockets 
376  *
377  * Return: void
378  ************************************************************************/
379 static void
380 RunMiniServer( MiniServerSockArray *miniSock )
381 {
382     char errorBuffer[ERROR_BUFFER_LEN];
383     struct sockaddr_in clientAddr;
384     socklen_t clientLen;
385     SOCKET connectHnd;
386     SOCKET miniServSock = miniSock->miniServerSock;
387     SOCKET miniServStopSock =  miniSock->miniServerStopSock;
388     SOCKET ssdpSock = miniSock->ssdpSock;
389 #ifdef INCLUDE_CLIENT_APIS
390     SOCKET ssdpReqSock = miniSock->ssdpReqSock;
391 #endif
392
393     fd_set expSet;
394     fd_set rdSet;
395     unsigned int maxMiniSock;
396     int byteReceived;
397     char requestBuf[256];
398     int ret = 0;
399
400     maxMiniSock = max( miniServSock, miniServStopSock) ;
401     maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpSock) );
402 #ifdef INCLUDE_CLIENT_APIS
403     maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpReqSock) );
404 #endif
405     ++maxMiniSock;
406
407     gMServState = MSERV_RUNNING;
408     while( TRUE ) {
409         FD_ZERO( &rdSet );
410         FD_ZERO( &expSet );
411
412         FD_SET( miniServStopSock, &expSet );
413         FD_SET( miniServSock, &rdSet );
414         FD_SET( miniServStopSock, &rdSet );
415         FD_SET( ssdpSock, &rdSet );
416 #ifdef INCLUDE_CLIENT_APIS
417         FD_SET( ssdpReqSock, &rdSet );
418 #endif
419
420         ret = select( maxMiniSock, &rdSet, NULL, &expSet, NULL );
421         if ( ret == -1 ) {
422             strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
423             UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
424                 "Error in select(): %s\n", errorBuffer );
425             /* Avoid 100% CPU in case of repeated error in select() */
426             isleep( 1 );
427             continue;
428         } else {
429             if( FD_ISSET( miniServSock, &rdSet ) ) {
430                 clientLen = sizeof( struct sockaddr_in );
431                 connectHnd = accept( miniServSock,
432                     ( struct sockaddr * )&clientAddr, &clientLen );
433                 if( connectHnd == -1 ) {
434                     strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
435                     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
436                         "miniserver: Error in accept(): %s\n", errorBuffer );
437                     continue;
438                 }
439                 schedule_request_job( connectHnd, &clientAddr );
440             }
441 #ifdef INCLUDE_CLIENT_APIS
442             // ssdp
443             if( FD_ISSET( ssdpReqSock, &rdSet ) ) {
444                 readFromSSDPSocket( ssdpReqSock );
445             }
446 #endif
447             if( FD_ISSET( ssdpSock, &rdSet ) ) {
448                     readFromSSDPSocket( ssdpSock );
449             }
450             if( FD_ISSET( miniServStopSock, &rdSet ) ) {
451                 clientLen = sizeof( struct sockaddr_in );
452                 memset( (char *)&clientAddr, 0, sizeof (struct sockaddr_in) );
453                 byteReceived =
454                     recvfrom( miniServStopSock, requestBuf, 25, 0,
455                               ( struct sockaddr * )&clientAddr,
456                               &clientLen );
457                 if( byteReceived > 0 ) {
458                     requestBuf[byteReceived] = '\0';
459                     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
460                         "Received response: %s From host %s \n",
461                         requestBuf, inet_ntoa( clientAddr.sin_addr ) );
462                     UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__,
463                         "Received multicast packet: \n %s\n",
464                         requestBuf );
465                     if( NULL != strstr( requestBuf, "ShutDown" ) ) {
466                         break;
467                     }
468                 }
469             }
470         }
471     }
472
473     shutdown( miniServSock, SD_BOTH );
474     UpnpCloseSocket( miniServSock );
475     shutdown( miniServStopSock, SD_BOTH );
476     UpnpCloseSocket( miniServStopSock );
477     shutdown( ssdpSock, SD_BOTH );
478     UpnpCloseSocket( ssdpSock );
479 #ifdef INCLUDE_CLIENT_APIS
480     shutdown( ssdpReqSock, SD_BOTH );
481     UpnpCloseSocket( ssdpReqSock );
482 #endif
483
484     free( miniSock );
485     gMServState = MSERV_IDLE;
486
487     return;
488 }
489
490 /************************************************************************
491  * Function: get_port
492  *
493  * Parameters:
494  *      int sockfd - Socket Descriptor 
495  *
496  * Description:
497  *      Returns port to which socket, sockfd, is bound.
498  *
499  * Return: int
500  *      -1 on error; check errno
501  *       > 0 means port number
502  ************************************************************************/
503 static int
504 get_port( int sockfd )
505 {
506     struct sockaddr_in sockinfo;
507     socklen_t len;
508     int code;
509     int port;
510
511     len = sizeof( struct sockaddr_in );
512     code = getsockname( sockfd, ( struct sockaddr * )&sockinfo, &len );
513     if( code == -1 ) {
514         return -1;
515     }
516
517     port = ntohs( sockinfo.sin_port );
518     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
519         "sockfd = %d, .... port = %d\n", sockfd, port );
520
521     return port;
522 }
523
524 /************************************************************************
525  * Function: get_miniserver_sockets
526  *
527  * Parameters:
528  *      MiniServerSockArray *out   - Socket Array
529  *      unsigned short listen_port - port on which the server is
530  *              listening for incoming connections      
531  *
532  * Description:
533  *      Creates a STREAM socket, binds to INADDR_ANY and listens for
534  *      incoming connecttions. Returns the actual port which the sockets
535  *      sub-system returned. 
536  *
537  *      Also creates a DGRAM socket, binds to the loop back address and 
538  *      returns the port allocated by the socket sub-system.
539  *
540  * Return: int 
541  *      UPNP_E_OUTOF_SOCKET - Failed to create a socket
542  *      UPNP_E_SOCKET_BIND - Bind() failed
543  *      UPNP_E_LISTEN   - Listen() failed       
544  *      UPNP_E_INTERNAL_ERROR - Port returned by the socket layer is < 0
545  *      UPNP_E_SUCCESS  - Success
546  ************************************************************************/
547 int
548 get_miniserver_sockets( MiniServerSockArray * out,
549                         unsigned short listen_port )
550 {
551     char errorBuffer[ERROR_BUFFER_LEN];
552     struct sockaddr_in serverAddr;
553     int listenfd;
554     int success;
555     unsigned short actual_port;
556     int reuseaddr_on = 0;
557     int sockError = UPNP_E_SUCCESS;
558     int errCode = 0;
559     int miniServerStopSock;
560     int ret = 0;
561
562     listenfd = socket( AF_INET, SOCK_STREAM, 0 );
563     if ( listenfd == -1 ) {
564         return UPNP_E_OUTOF_SOCKET; // error creating socket
565     }
566     // As per the IANA specifications for the use of ports by applications
567     // override the listen port passed in with the first available 
568     if( listen_port < APPLICATION_LISTENING_PORT )
569         listen_port = APPLICATION_LISTENING_PORT;
570
571     memset( &serverAddr, 0, sizeof( serverAddr ) );
572     serverAddr.sin_family = AF_INET;
573     serverAddr.sin_addr.s_addr = htonl( INADDR_ANY );
574
575     // Getting away with implementation of re-using address:port and instead 
576     // choosing to increment port numbers.
577     // Keeping the re-use address code as an optional behaviour that can be 
578     // turned on if necessary. 
579     // TURN ON the reuseaddr_on option to use the option.
580     if ( reuseaddr_on ) {
581         // THIS IS ALLOWS US TO BIND AGAIN IMMEDIATELY
582         // AFTER OUR SERVER HAS BEEN CLOSED
583         // THIS MAY CAUSE TCP TO BECOME LESS RELIABLE
584         // HOWEVER IT HAS BEEN SUGESTED FOR TCP SERVERS
585         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
586             "mserv start: resuseaddr set\n" );
587         sockError = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR,
588             (const char *)&reuseaddr_on, sizeof (int) );
589         if ( sockError == -1 ) {
590             shutdown( listenfd, SD_BOTH );
591             UpnpCloseSocket( listenfd );
592
593             return UPNP_E_SOCKET_BIND;
594         }
595
596         sockError = bind( listenfd, (struct sockaddr *)&serverAddr,
597             sizeof (struct sockaddr_in) );
598     } else {
599         do {
600             serverAddr.sin_port = htons( listen_port++ );
601             sockError = bind( listenfd, (struct sockaddr *)&serverAddr,
602                 sizeof (struct sockaddr_in) );
603             if ( sockError == -1 ) {
604 #ifdef WIN32
605                 errCode = WSAGetLastError();
606 #else
607                 errCode = errno; 
608 #endif
609                 if( errno == EADDRINUSE ) {
610                     errCode = 1;
611                 }
612             } else
613                 errCode = 0;
614
615         } while ( errCode != 0 );
616     }
617
618     if ( sockError == -1 ) {
619         strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
620         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
621             "mserv start: Error in bind(): %s\n", errorBuffer );
622         shutdown( listenfd, SD_BOTH );
623         UpnpCloseSocket( listenfd );
624
625         return UPNP_E_SOCKET_BIND;  // bind failed
626     }
627
628     UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
629         "mserv start: bind success\n" );
630
631     success = listen( listenfd, SOMAXCONN );
632     if ( success == -1 ) {
633         strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
634         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
635             "mserv start: Error in listen(): %s\n", errorBuffer );
636         shutdown( listenfd, SD_BOTH );
637         UpnpCloseSocket( listenfd );
638
639         return UPNP_E_LISTEN;
640     }
641
642     actual_port = get_port( listenfd );
643     if( actual_port <= 0 ) {
644         shutdown( listenfd, SD_BOTH );
645         UpnpCloseSocket( listenfd );
646
647         return UPNP_E_INTERNAL_ERROR;
648     }
649
650     out->miniServerPort = actual_port;
651
652     miniServerStopSock = socket( AF_INET, SOCK_DGRAM, 0 );
653     if ( miniServerStopSock == -1 ) {
654         strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
655         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
656             "Error in socket(): %s\n", errorBuffer );
657         shutdown( listenfd, SD_BOTH );
658         UpnpCloseSocket( listenfd );
659
660         return UPNP_E_OUTOF_SOCKET;
661     }
662
663     // bind to local socket
664     memset( ( char * )&serverAddr, 0, sizeof( struct sockaddr_in ) );
665     serverAddr.sin_family = AF_INET;
666     serverAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
667     ret = bind( miniServerStopSock, (struct sockaddr *)&serverAddr,
668         sizeof (serverAddr) );
669     if ( ret == -1 ) {
670         UpnpPrintf( UPNP_CRITICAL,
671             MSERV, __FILE__, __LINE__,
672             "Error in binding localhost!!!\n" );
673         shutdown( listenfd, SD_BOTH );
674         UpnpCloseSocket( listenfd );
675         shutdown( miniServerStopSock, SD_BOTH );
676         UpnpCloseSocket( miniServerStopSock );
677
678         return UPNP_E_SOCKET_BIND;
679     }
680
681     miniStopSockPort = get_port( miniServerStopSock );
682     if ( miniStopSockPort <= 0 ) {
683         shutdown( miniServerStopSock, SD_BOTH );
684         UpnpCloseSocket( miniServerStopSock );
685         shutdown( listenfd, SD_BOTH );
686         UpnpCloseSocket( listenfd );
687
688         return UPNP_E_INTERNAL_ERROR;
689     }
690
691     out->stopPort = miniStopSockPort;
692     out->miniServerSock = listenfd;
693     out->miniServerStopSock = miniServerStopSock;
694
695     return UPNP_E_SUCCESS;
696 }
697
698 /************************************************************************
699  * Function: StartMiniServer
700  *
701  * Parameters :
702  *      unsigned short listen_port - Port on which the server listens for 
703  *              incoming connections
704  *
705  * Description:
706  *      Initialize the sockets functionality for the 
707  *      Miniserver. Initialize a thread pool job to run the MiniServer
708  *      and the job to the thread pool. If listen port is 0, port is 
709  *      dynamically picked
710  *
711  *      Use timer mechanism to start the MiniServer, failure to meet the 
712  *      allowed delay aborts the attempt to launch the MiniServer.
713  *
714  * Return: int
715  *      Actual port socket is bound to - On Success
716  *      A negative number UPNP_E_XXX - On Error
717  ************************************************************************/
718 int
719 StartMiniServer( unsigned short listen_port )
720 {
721     int success;
722     int count;
723     int max_count = 10000;
724
725     MiniServerSockArray *miniSocket;
726     ThreadPoolJob job;
727
728     if( gMServState != MSERV_IDLE ) {
729         return UPNP_E_INTERNAL_ERROR;   // miniserver running
730     }
731
732     miniSocket = (MiniServerSockArray *) malloc( sizeof (MiniServerSockArray) );
733     if( miniSocket == NULL ) {
734         return UPNP_E_OUTOF_MEMORY;
735     }
736
737     success = get_miniserver_sockets( miniSocket, listen_port );
738     if( success != UPNP_E_SUCCESS ) {
739         free( miniSocket );
740         return success;
741     }
742
743     success = get_ssdp_sockets( miniSocket );
744     if( success != UPNP_E_SUCCESS ) {
745         shutdown( miniSocket->miniServerSock, SD_BOTH );
746         UpnpCloseSocket( miniSocket->miniServerSock );
747         shutdown( miniSocket->miniServerStopSock, SD_BOTH );
748         UpnpCloseSocket( miniSocket->miniServerStopSock );
749         free( miniSocket );
750
751         return success;
752     }
753
754     TPJobInit( &job, (start_routine)RunMiniServer, (void *)miniSocket );
755     TPJobSetPriority( &job, MED_PRIORITY );
756     TPJobSetFreeFunction( &job, ( free_routine ) free );
757
758     success = ThreadPoolAddPersistent( &gMiniServerThreadPool, &job, NULL );
759     if ( success < 0 ) {
760         shutdown( miniSocket->miniServerSock, SD_BOTH );
761         UpnpCloseSocket( miniSocket->miniServerSock );
762         shutdown( miniSocket->miniServerStopSock, SD_BOTH );
763         UpnpCloseSocket( miniSocket->miniServerStopSock );
764         shutdown( miniSocket->ssdpSock, SD_BOTH );
765         UpnpCloseSocket( miniSocket->ssdpSock );
766 #ifdef INCLUDE_CLIENT_APIS
767         shutdown( miniSocket->ssdpReqSock, SD_BOTH );
768         UpnpCloseSocket( miniSocket->ssdpReqSock );
769 #endif
770
771         return UPNP_E_OUTOF_MEMORY;
772     }
773     // wait for miniserver to start
774     count = 0;
775     while ( gMServState != MSERV_RUNNING && count < max_count ) {
776         usleep( 50 * 1000 );    // 0.05s
777         count++;
778     }
779
780     // taking too long to start that thread
781     if ( count >= max_count ) {
782         shutdown( miniSocket->miniServerSock, SD_BOTH );
783         UpnpCloseSocket( miniSocket->miniServerSock );
784         shutdown( miniSocket->miniServerStopSock, SD_BOTH );
785         UpnpCloseSocket( miniSocket->miniServerStopSock );
786         shutdown( miniSocket->ssdpSock, SD_BOTH );
787         UpnpCloseSocket( miniSocket->ssdpSock );
788 #ifdef INCLUDE_CLIENT_APIS
789         shutdown( miniSocket->ssdpReqSock, SD_BOTH );
790         UpnpCloseSocket( miniSocket->ssdpReqSock );
791 #endif
792
793         return UPNP_E_INTERNAL_ERROR;
794     }
795
796     return miniSocket->miniServerPort;
797 }
798
799 /************************************************************************
800  * Function: StopMiniServer
801  *
802  * Parameters:
803  *      void
804  *
805  * Description:
806  *      Stop and Shutdown the MiniServer and free socket 
807  *      resources.
808  *
809  * Return: int
810  *              Always returns 0 
811  ************************************************************************/
812 int
813 StopMiniServer()
814 {
815     char errorBuffer[ERROR_BUFFER_LEN];
816     int socklen = sizeof( struct sockaddr_in );
817     int sock;
818     struct sockaddr_in ssdpAddr;
819     char buf[256] = "ShutDown";
820     int bufLen = strlen( buf );
821
822     if( gMServState == MSERV_RUNNING ) {
823         gMServState = MSERV_STOPPING;
824     } else {
825         return 0;
826     }
827
828     sock = socket( AF_INET, SOCK_DGRAM, 0 );
829     if ( sock == -1 ) {
830         strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
831         UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
832             "SSDP_SERVER: StopSSDPServer: Error in socket() %s\n", errorBuffer );
833         return 0;
834     }
835
836     while( gMServState != MSERV_IDLE ) {
837         ssdpAddr.sin_family = AF_INET;
838         ssdpAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
839         ssdpAddr.sin_port = htons( miniStopSockPort );
840         sendto( sock, buf, bufLen, 0, (struct sockaddr *)&ssdpAddr, socklen );
841         usleep( 1000 );
842         if( gMServState == MSERV_IDLE ) {
843             break;
844         }
845         isleep( 1 );
846     }
847     shutdown( sock, SD_BOTH );
848     UpnpCloseSocket( sock );
849
850     return 0;
851 }
852