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 / ssdp / ssdp_device.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 #include "config.h"
34
35
36 #ifdef INCLUDE_DEVICE_APIS
37 #if EXCLUDE_SSDP == 0
38
39
40 #include "httpparser.h"
41 #include "httpreadwrite.h"
42 #include "ssdplib.h"
43 #include "statcodes.h"
44 #include "ThreadPool.h"
45 #include "unixutil.h"
46 #include "upnpapi.h"
47 #include "UpnpInet.h"
48
49
50 #include <assert.h>
51 #include <stdio.h>
52 #include <string.h>
53
54
55 #define MSGTYPE_SHUTDOWN        0
56 #define MSGTYPE_ADVERTISEMENT   1
57 #define MSGTYPE_REPLY           2
58
59
60 /************************************************************************
61 * Function : advertiseAndReplyThread
62 *
63 * Parameters:
64 *       IN void *data: Structure containing the search request
65 *
66 * Description:
67 *       This function is a wrapper function to reply the search request
68 *       coming from the control point.
69 *
70 * Returns: void *
71 *       always return NULL
72 ***************************************************************************/
73 void *
74 advertiseAndReplyThread( IN void *data )
75 {
76     SsdpSearchReply *arg = ( SsdpSearchReply * ) data;
77
78     AdvertiseAndReply( 0, arg->handle,
79                        arg->event.RequestType,
80                        &arg->dest_addr,
81                        arg->event.DeviceType,
82                        arg->event.UDN,
83                        arg->event.ServiceType, arg->MaxAge );
84     free( arg );
85
86     return NULL;
87 }
88
89 /************************************************************************
90 * Function : ssdp_handle_device_request
91 *
92 * Parameters:
93 *       IN http_message_t *hmsg: SSDP search request from the control point
94 *       IN struct sockaddr_in* dest_addr: The address info of control point
95 *
96 * Description:
97 *       This function handles the search request. It do the sanity checks of
98 *       the request and then schedules a thread to send a random time reply (
99 *       random within maximum time given by the control point to reply).
100 *
101 * Returns: void *
102 *       1 if successful else appropriate error
103 ***************************************************************************/
104 #ifdef INCLUDE_DEVICE_APIS
105 void
106 ssdp_handle_device_request( IN http_message_t *hmsg,
107                             IN struct sockaddr_in *dest_addr )
108 {
109 #define MX_FUDGE_FACTOR 10
110
111     int handle;
112     struct Handle_Info *dev_info = NULL;
113     memptr hdr_value;
114     int mx;
115     char save_char;
116     SsdpEvent event;
117     int ret_code;
118     SsdpSearchReply *threadArg = NULL;
119     ThreadPoolJob job;
120     int replyTime;
121     int maxAge;
122
123     // check man hdr
124     if( httpmsg_find_hdr( hmsg, HDR_MAN, &hdr_value ) == NULL ||
125         memptr_cmp( &hdr_value, "\"ssdp:discover\"" ) != 0 ) {
126         return;                 // bad or missing hdr
127     }
128     // MX header
129     if( httpmsg_find_hdr( hmsg, HDR_MX, &hdr_value ) == NULL ||
130         ( mx = raw_to_int( &hdr_value, 10 ) ) < 0 ) {
131         return;
132     }
133     // ST header
134     if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) == NULL ) {
135         return;
136     }
137     save_char = hdr_value.buf[hdr_value.length];
138     hdr_value.buf[hdr_value.length] = '\0';
139     ret_code = ssdp_request_type( hdr_value.buf, &event );
140     hdr_value.buf[hdr_value.length] = save_char;    // restore
141     if( ret_code == -1 ) {
142         return;                 // bad ST header
143     }
144
145     HandleLock();
146     // device info
147     if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) {
148         HandleUnlock();
149         return;                 // no info found
150     }
151     maxAge = dev_info->MaxAge;
152     HandleUnlock();
153
154     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
155         "ssdp_handle_device_request with Cmd %d SEARCH\n",
156         event.Cmd );
157     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
158         "MAX-AGE     =  %d\n", maxAge );
159     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
160         "MX     =  %d\n", event.Mx );
161     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
162         "DeviceType   =  %s\n", event.DeviceType );
163     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
164         "DeviceUuid   =  %s\n", event.UDN );
165     UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
166         "ServiceType =  %s\n", event.ServiceType );
167
168     threadArg =
169         ( SsdpSearchReply * ) malloc( sizeof( SsdpSearchReply ) );
170
171     if( threadArg == NULL ) {
172         return;
173     }
174     threadArg->handle = handle;
175     threadArg->dest_addr = ( *dest_addr );
176     threadArg->event = event;
177     threadArg->MaxAge = maxAge;
178
179     TPJobInit( &job, advertiseAndReplyThread, threadArg );
180     TPJobSetFreeFunction( &job, ( free_routine ) free );
181
182     //Subtract a percentage from the mx
183     //to allow for network and processing delays
184     // (i.e. if search is for 30 seconds, 
185     //       respond withing 0 - 27 seconds)
186
187     if( mx >= 2 ) {
188         mx -= MAXVAL( 1, mx / MX_FUDGE_FACTOR );
189     }
190
191     if( mx < 1 ) {
192         mx = 1;
193     }
194
195     replyTime = rand() % mx;
196
197     TimerThreadSchedule( &gTimerThread, replyTime, REL_SEC, &job,
198                          SHORT_TERM, NULL );
199 }
200 #endif
201
202 /************************************************************************
203 * Function : NewRequestHandler
204 *
205 * Parameters:
206 *               IN struct sockaddr_in * DestAddr: Ip address, to send the reply.
207 *               IN int NumPacket: Number of packet to be sent.
208 *               IN char **RqPacket:Number of packet to be sent.
209 *
210 * Description:
211 *       This function works as a request handler which passes the HTTP
212 *       request string to multicast channel then
213 *
214 * Returns: void *
215 *       1 if successful else appropriate error
216 ***************************************************************************/
217 static int
218 NewRequestHandler( IN struct sockaddr_in *DestAddr,
219                    IN int NumPacket,
220                    IN char **RqPacket )
221 {
222     char errorBuffer[ERROR_BUFFER_LEN];
223     int ReplySock;
224     int socklen = sizeof( struct sockaddr_in );
225     int NumCopy;
226     int Index;
227     unsigned long replyAddr = inet_addr( LOCAL_HOST );
228     int ttl = 4; // a/c to UPNP Spec
229
230     ReplySock = socket( AF_INET, SOCK_DGRAM, 0 );
231     if ( ReplySock == -1 ) {
232         strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
233         UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
234             "SSDP_LIB: New Request Handler:"
235             "Error in socket(): %s\n", errorBuffer );
236
237         return UPNP_E_OUTOF_SOCKET;
238     }
239
240     setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
241         (char *)&replyAddr, sizeof (replyAddr) );
242     setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
243         (char *)&ttl, sizeof (int) );
244
245     for( Index = 0; Index < NumPacket; Index++ ) {
246         int rc;
247         // The reason to keep this loop is purely historical/documentation,
248         // according to section 9.2 of HTTPU spec:
249         // 
250         // "If a multicast resource would send a response(s) to any copy of the 
251         //  request, it SHOULD send its response(s) to each copy of the request 
252         //  it receives. It MUST NOT repeat its response(s) per copy of the 
253         //  request."
254         //  
255         // http://www.upnp.org/download/draft-goland-http-udp-04.txt
256         //
257         // So, NUM_COPY has been changed from 2 to 1.
258         NumCopy = 0;
259         while( NumCopy < NUM_COPY ) {
260             UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
261                 ">>> SSDP SEND >>>\n%s\n",
262                 *( RqPacket + Index ) );
263             rc = sendto( ReplySock, *( RqPacket + Index ),
264                          strlen( *( RqPacket + Index ) ),
265                          0, ( struct sockaddr * )DestAddr, socklen );
266             imillisleep( SSDP_PAUSE );
267             ++NumCopy;
268         }
269     }
270
271     shutdown( ReplySock, SD_BOTH );
272     UpnpCloseSocket( ReplySock );
273
274     return UPNP_E_SUCCESS;
275 }
276
277 /************************************************************************
278 * Function : CreateServiceRequestPacket
279 *
280 * Parameters:
281 *       IN int msg_type : type of the message ( Search Reply, Advertisement
282 *               or Shutdown )
283 *       IN char * nt : ssdp type
284 *       IN char * usn : unique service name ( go in the HTTP Header)
285 *       IN char * location :Location URL.
286 *       IN int  duration :Service duration in sec.
287 *       OUT char** packet :Output buffer filled with HTTP statement.
288 *
289 * Description:
290 *       This function creates a HTTP request packet.  Depending
291 *       on the input parameter it either creates a service advertisement
292 *       request or service shutdown request etc.
293 *
294 * Returns: void
295 *
296 ***************************************************************************/
297 void
298 CreateServicePacket( IN int msg_type,
299                      IN char *nt,
300                      IN char *usn,
301                      IN char *location,
302                      IN int duration,
303                      OUT char **packet )
304 {
305     int ret_code;
306     char *nts;
307     membuffer buf;
308
309     //Notf=0 means service shutdown, 
310     //Notf=1 means service advertisement, Notf =2 means reply   
311
312     membuffer_init( &buf );
313     buf.size_inc = 30;
314
315     *packet = NULL;
316
317     if( msg_type == MSGTYPE_REPLY ) {
318         ret_code = http_MakeMessage(
319             &buf, 1, 1,
320             "R" "sdc" "D" "sc" "ssc" "S" "Xc" "ssc" "sscc",
321             HTTP_OK,
322             "CACHE-CONTROL: max-age=", duration,
323             "EXT:",
324             "LOCATION: ", location,
325             X_USER_AGENT,
326             "ST: ", nt,
327             "USN: ", usn);
328         if( ret_code != 0 ) {
329             return;
330         }
331     } else if( msg_type == MSGTYPE_ADVERTISEMENT ||
332                msg_type == MSGTYPE_SHUTDOWN ) {
333         if( msg_type == MSGTYPE_ADVERTISEMENT ) {
334             nts = "ssdp:alive";
335         } else                  // shutdown
336         {
337             nts = "ssdp:byebye";
338         }
339
340         // NOTE: The CACHE-CONTROL and LOCATION headers are not present in
341         //  a shutdown msg, but are present here for MS WinMe interop.
342
343         ret_code = http_MakeMessage(
344             &buf, 1, 1,
345             "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "Xc" "sscc",
346             HTTPMETHOD_NOTIFY, "*", (size_t)1,
347             "HOST: ", SSDP_IP, ":", SSDP_PORT,
348             "CACHE-CONTROL: max-age=", duration,
349             "LOCATION: ", location,
350             "NT: ", nt,
351             "NTS: ", nts,
352             X_USER_AGENT,
353             "USN: ", usn );
354         if( ret_code != 0 ) {
355             return;
356         }
357
358     } else {
359         assert( 0 );            // unknown msg
360     }
361
362     *packet = membuffer_detach( &buf ); // return msg
363
364     membuffer_destroy( &buf );
365
366     return;
367 }
368
369 /************************************************************************
370 * Function : DeviceAdvertisement
371 *
372 * Parameters:
373 *       IN char * DevType : type of the device
374 *       IN int RootDev: flag to indicate if the device is root device
375 *       IN char * nt : ssdp type
376 *       IN char * usn : unique service name
377 *       IN char * location :Location URL.
378 *       IN int  duration :Service duration in sec.
379 *
380 * Description:
381 *       This function creates the device advertisement request based on 
382 *       the input parameter, and send it to the multicast channel.
383 *
384 * Returns: int
385 *       UPNP_E_SUCCESS if successful else appropriate error
386 ***************************************************************************/
387 int
388 DeviceAdvertisement( IN char *DevType,
389                      int RootDev,
390                      char *Udn,
391                      IN char *Location,
392                      IN int Duration )
393 {
394     struct sockaddr_in DestAddr;
395
396     //char Mil_Nt[LINE_SIZE]
397     char Mil_Usn[LINE_SIZE];
398     char *msgs[3];
399     int ret_code;
400
401     UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
402         "In function DeviceAdvertisement\n" );
403
404     DestAddr.sin_family = AF_INET;
405     DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP );
406     DestAddr.sin_port = htons( SSDP_PORT );
407
408     msgs[0] = NULL;
409     msgs[1] = NULL;
410     msgs[2] = NULL;
411
412     //If deviceis a root device , here we need to 
413     //send 3 advertisement or reply
414     if( RootDev ) {
415         sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
416         CreateServicePacket( MSGTYPE_ADVERTISEMENT, "upnp:rootdevice",
417                 Mil_Usn, Location, Duration, &msgs[0] );
418     }
419     // both root and sub-devices need to send these two messages
420     //
421
422     CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn,
423                          Location, Duration, &msgs[1] );
424
425     sprintf( Mil_Usn, "%s::%s", Udn, DevType );
426     CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn,
427                          Location, Duration, &msgs[2] );
428
429     // check error
430     if( ( RootDev && msgs[0] == NULL ) ||
431         msgs[1] == NULL || msgs[2] == NULL ) {
432         free( msgs[0] );
433         free( msgs[1] );
434         free( msgs[2] );
435         return UPNP_E_OUTOF_MEMORY;
436     }
437     // send packets
438     if( RootDev ) {
439         // send 3 msg types
440         ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] );
441     } else                      // sub-device
442     {
443         // send 2 msg types
444         ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] );
445     }
446
447     // free msgs
448     free( msgs[0] );
449     free( msgs[1] );
450     free( msgs[2] );
451
452     return ret_code;
453 }
454
455 /************************************************************************
456 * Function : SendReply
457 *
458 * Parameters:
459 *       IN struct sockaddr_in * DestAddr:destination IP address.
460 *       IN char *DevType: Device type
461 *       IN int RootDev: 1 means root device 0 means embedded device.
462 *       IN char * Udn: Device UDN
463 *       IN char * Location: Location of Device description document.
464 *       IN int  Duration :Life time of this device.
465 *       IN int ByType:
466 *
467 * Description:
468 *       This function creates the reply packet based on the input parameter, 
469 *       and send it to the client addesss given in its input parameter DestAddr.
470 *
471 * Returns: int
472 *       UPNP_E_SUCCESS if successful else appropriate error
473 ***************************************************************************/
474 int
475 SendReply( IN struct sockaddr_in *DestAddr,
476            IN char *DevType,
477            IN int RootDev,
478            IN char *Udn,
479            IN char *Location,
480            IN int Duration,
481            IN int ByType )
482 {
483     int ret_code;
484     char *msgs[2];
485     int num_msgs;
486     char Mil_Usn[LINE_SIZE];
487     int i;
488
489     msgs[0] = NULL;
490     msgs[1] = NULL;
491
492     if( RootDev ) {
493         // one msg for root device
494         num_msgs = 1;
495
496         sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
497         CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice",
498                              Mil_Usn, Location, Duration, &msgs[0] );
499     } else {
500         // two msgs for embedded devices
501         num_msgs = 1;
502
503         //NK: FIX for extra response when someone searches by udn
504         if( !ByType ) {
505             CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location,
506                                  Duration, &msgs[0] );
507         } else {
508             sprintf( Mil_Usn, "%s::%s", Udn, DevType );
509             CreateServicePacket( MSGTYPE_REPLY, DevType, Mil_Usn,
510                                  Location, Duration, &msgs[0] );
511         }
512     }
513
514     // check error
515     for( i = 0; i < num_msgs; i++ ) {
516         if( msgs[i] == NULL ) {
517             free( msgs[0] );
518             return UPNP_E_OUTOF_MEMORY;
519         }
520     }
521
522     // send msgs
523     ret_code = NewRequestHandler( DestAddr, num_msgs, msgs );
524     for( i = 0; i < num_msgs; i++ ) {
525         if( msgs[i] != NULL )
526             free( msgs[i] );
527     }
528
529     return ret_code;
530 }
531
532 /************************************************************************
533 * Function : DeviceReply
534 *
535 * Parameters:
536 *       IN struct sockaddr_in * DestAddr:destination IP address.
537 *       IN char *DevType: Device type
538 *       IN int RootDev: 1 means root device 0 means embedded device.
539 *       IN char * Udn: Device UDN
540 *       IN char * Location: Location of Device description document.
541 *       IN int  Duration :Life time of this device.
542 * Description:
543 *       This function creates the reply packet based on the input parameter, 
544 *       and send it to the client address given in its input parameter DestAddr.
545 *
546 * Returns: int
547 *       UPNP_E_SUCCESS if successful else appropriate error
548 ***************************************************************************/
549 int
550 DeviceReply( IN struct sockaddr_in *DestAddr,
551              IN char *DevType,
552              IN int RootDev,
553              IN char *Udn,
554              IN char *Location,
555              IN int Duration)
556 {
557     char *szReq[3],
558       Mil_Nt[LINE_SIZE],
559       Mil_Usn[LINE_SIZE];
560     int RetVal;
561
562     szReq[0] = NULL;
563     szReq[1] = NULL;
564     szReq[2] = NULL;
565
566     // create 2 or 3 msgs
567
568     if( RootDev ) {
569         // 3 replies for root device
570         strcpy( Mil_Nt, "upnp:rootdevice" );
571         sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
572         CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
573                              Location, Duration, &szReq[0] );
574     }
575
576     sprintf( Mil_Nt, "%s", Udn );
577     sprintf( Mil_Usn, "%s", Udn );
578     CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
579                          Location, Duration, &szReq[1] );
580
581     sprintf( Mil_Nt, "%s", DevType );
582     sprintf( Mil_Usn, "%s::%s", Udn, DevType );
583     CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
584                          Location, Duration, &szReq[2] );
585
586     // check error
587
588     if( ( RootDev && szReq[0] == NULL ) ||
589         szReq[1] == NULL || szReq[2] == NULL ) {
590         free( szReq[0] );
591         free( szReq[1] );
592         free( szReq[2] );
593         return UPNP_E_OUTOF_MEMORY;
594     }
595     // send replies
596     if( RootDev ) {
597         RetVal = NewRequestHandler( DestAddr, 3, szReq );
598     } else {
599         RetVal = NewRequestHandler( DestAddr, 2, &szReq[1] );
600     }
601
602     // free
603     free( szReq[0] );
604     free( szReq[1] );
605     free( szReq[2] );
606
607     return RetVal;
608 }
609
610 /************************************************************************
611 * Function : ServiceAdvertisement
612 *
613 * Parameters:
614 *       IN char * Udn: Device UDN
615 *       IN char *ServType: Service Type.
616 *       IN char * Location: Location of Device description document.
617 *       IN int  Duration :Life time of this device.
618 * Description:
619 *       This function creates the advertisement packet based
620 *       on the input parameter, and send it to the multicast channel.
621 *
622 * Returns: int
623 *       UPNP_E_SUCCESS if successful else appropriate error
624 ***************************************************************************/
625 int
626 ServiceAdvertisement( IN char *Udn,
627                       IN char *ServType,
628                       IN char *Location,
629                       IN int Duration)
630 {
631     char Mil_Usn[LINE_SIZE];
632     char *szReq[1];
633     struct sockaddr_in DestAddr;
634     int RetVal;
635
636     DestAddr.sin_family = AF_INET;
637     DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP );
638     DestAddr.sin_port = htons( SSDP_PORT );
639
640     sprintf( Mil_Usn, "%s::%s", Udn, ServType );
641
642     //CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn,
643     //Server,Location,Duration);
644     CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn,
645                          Location, Duration, &szReq[0] );
646     if( szReq[0] == NULL ) {
647         return UPNP_E_OUTOF_MEMORY;
648     }
649
650     RetVal = NewRequestHandler( &DestAddr, 1, szReq );
651
652     free( szReq[0] );
653     return RetVal;
654 }
655
656 /************************************************************************
657 * Function : ServiceReply
658 *
659 * Parameters:
660 *       IN struct sockaddr_in *DestAddr:
661 *       IN char * Udn: Device UDN
662 *       IN char *ServType: Service Type.
663 *       IN char * Location: Location of Device description document.
664 *       IN int  Duration :Life time of this device.
665 * Description:
666 *       This function creates the advertisement packet based 
667 *       on the input parameter, and send it to the multicast channel.
668 *
669 * Returns: int
670 *       UPNP_E_SUCCESS if successful else appropriate error
671 ***************************************************************************/
672 int
673 ServiceReply( IN struct sockaddr_in *DestAddr,
674               IN char *ServType,
675               IN char *Udn,
676               IN char *Location,
677               IN int Duration )
678 {
679     char Mil_Usn[LINE_SIZE];
680     char *szReq[1];
681     int RetVal;
682
683     szReq[0] = NULL;
684
685     sprintf( Mil_Usn, "%s::%s", Udn, ServType );
686
687     CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn,
688                          Location, Duration, &szReq[0] );
689     if( szReq[0] == NULL ) {
690         return UPNP_E_OUTOF_MEMORY;
691     }
692
693     RetVal = NewRequestHandler( DestAddr, 1, szReq );
694
695     free( szReq[0] );
696     return RetVal;
697 }
698
699 /************************************************************************
700 * Function : ServiceShutdown
701 *
702 * Parameters:
703 *       IN char * Udn: Device UDN
704 *       IN char *ServType: Service Type.
705 *       IN char * Location: Location of Device description document.
706 *       IN int  Duration :Service duration in sec.
707 * Description:
708 *       This function creates a HTTP service shutdown request packet 
709 *       and sent it to the multicast channel through RequestHandler.
710 *
711 * Returns: int
712 *       UPNP_E_SUCCESS if successful else appropriate error
713 ***************************************************************************/
714 int
715 ServiceShutdown( IN char *Udn,
716                  IN char *ServType,
717                  IN char *Location,
718                  IN int Duration)
719 {
720     char Mil_Usn[LINE_SIZE];
721     char *szReq[1];
722     struct sockaddr_in DestAddr;
723     int RetVal;
724
725     DestAddr.sin_family = AF_INET;
726     DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP );
727     DestAddr.sin_port = htons( SSDP_PORT );
728
729     //sprintf(Mil_Nt,"%s",ServType);
730     sprintf( Mil_Usn, "%s::%s", Udn, ServType );
731     //CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn,
732     //Server,Location,Duration);
733     CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn,
734                          Location, Duration, &szReq[0] );
735     if( szReq[0] == NULL ) {
736         return UPNP_E_OUTOF_MEMORY;
737     }
738     RetVal = NewRequestHandler( &DestAddr, 1, szReq );
739
740     free( szReq[0] );
741     return RetVal;
742 }
743
744 /************************************************************************
745 * Function : DeviceShutdown
746 *
747 * Parameters:
748 *       IN char *DevType: Device Type.
749 *       IN int RootDev:1 means root device.
750 *       IN char * Udn: Device UDN
751 *       IN char * Location: Location URL
752 *       IN int  Duration :Device duration in sec.
753 *
754 * Description:
755 *       This function creates a HTTP device shutdown request packet 
756 *       and sent it to the multicast channel through RequestHandler.
757 *
758 * Returns: int
759 *       UPNP_E_SUCCESS if successful else appropriate error
760 ***************************************************************************/
761 int
762 DeviceShutdown( IN char *DevType,
763                 IN int RootDev,
764                 IN char *Udn,
765                 IN char *_Server,
766                 IN char *Location,
767                 IN int Duration)
768 {
769     struct sockaddr_in DestAddr;
770     char *msgs[3];
771     char Mil_Usn[LINE_SIZE];
772     int ret_code;
773
774     msgs[0] = NULL;
775     msgs[1] = NULL;
776     msgs[2] = NULL;
777
778     DestAddr.sin_family = AF_INET;
779     DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP );
780     DestAddr.sin_port = htons( SSDP_PORT );
781
782     // root device has one extra msg
783     if( RootDev ) {
784         sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
785         CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice",
786                              Mil_Usn, Location, Duration, &msgs[0] );
787     }
788
789     UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
790         "In function DeviceShutdown\n" );
791     // both root and sub-devices need to send these two messages
792     CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn,
793                          Location, Duration, &msgs[1] );
794
795     sprintf( Mil_Usn, "%s::%s", Udn, DevType );
796     CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn,
797                          Location, Duration, &msgs[2] );
798
799     // check error
800     if( ( RootDev && msgs[0] == NULL ) ||
801         msgs[1] == NULL || msgs[2] == NULL ) {
802         free( msgs[0] );
803         free( msgs[1] );
804         free( msgs[2] );
805         return UPNP_E_OUTOF_MEMORY;
806     }
807     // send packets
808     if( RootDev ) {
809         // send 3 msg types
810         ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] );
811     } else                      // sub-device
812     {
813         // send 2 msg types
814         ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] );
815     }
816
817     // free msgs
818     free( msgs[0] );
819     free( msgs[1] );
820     free( msgs[2] );
821
822     return ret_code;
823 }
824
825 #endif // EXCLUDE_SSDP
826 #endif // INCLUDE_DEVICE_APIS
827