OSDN Git Service

update libMiMic
[mimic/MiMicSDK.git] / lib / src / net / upnp / NyLPC_cSsdpSocket.c
1 /*********************************************************************************\r
2  * PROJECT: MiMic\r
3  * --------------------------------------------------------------------------------\r
4  *\r
5  * This file is part of MiMic\r
6  * Copyright (C)2011 Ryo Iizuka\r
7  *\r
8  * MiMic is free software: you can redistribute it and/or modify\r
9  * it under the terms of the GNU Lesser General Public License as published\r
10  * by the Free Software Foundation, either version 3 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU Lesser General Public License\r
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
20  *\r
21  * For further information please contact.\r
22  *      http://nyatla.jp/\r
23  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
24  *\r
25  *********************************************************************************/\r
26 #include "NyLPC_cSsdpSocket.h"\r
27 #include "NyLPC_http.h"\r
28 #include "NyLPC_netif.h"\r
29 \r
30 \r
31 #include <stdio.h>\r
32 #include <string.h>\r
33 \r
34 \r
35 \r
36 \r
37 \r
38 #define HTTP_SP 0x20\r
39 \r
40 #define PARSE_NULL  0\r
41 #define PARSE_ST        0x01\r
42 #define PARSE_MAN       0x11\r
43 #define PARSE_UNKNOWN 0xff\r
44 \r
45 static const struct NyLPC_TIPv4Addr SSDP_MCAST_IPADDR=NyLPC_TIPv4Addr_pack(239,255,255,250);\r
46 static const char* STR_UPNP_ROOT_DEVICE="upnp:rootdevice";\r
47 \r
48 struct TMSearchHeader\r
49 {\r
50         struct NyLPC_THttpBasicHeader super;\r
51 \r
52         const struct NyLPC_TUPnPDeviceRecord* _ref_devices;\r
53         /**\r
54          * パーサのステータス\r
55          */\r
56         NyLPC_TUInt8 st;\r
57         /**\r
58          * メモリ位置\r
59          */\r
60         const NyLPC_TChar* _rpos;\r
61         struct{\r
62                 const NyLPC_TChar* st_str;\r
63                 const NyLPC_TChar* man_str;\r
64                 NyLPC_TUInt16 st_len;\r
65                 NyLPC_TUInt16 man_len;\r
66         }result;\r
67 };\r
68 \r
69 //とりあえずprivate\r
70 void NyLPC_cSsdpSocket_notify(NyLPC_TcSsdpSocket_t* i_inst);\r
71 \r
72 \r
73 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)\r
74 {\r
75 // *であるかを確認 未実装\r
76         return NyLPC_TBool_TRUE;\r
77 }\r
78 \r
79 #define TIMEOUT_IN_MS 100\r
80 \r
81 /**\r
82  * SERVER MessageHeaderの値\r
83  * 40文字以内であること。\r
84  */\r
85 #define SERVER_MESSAGE_HEADER "MiMic/1.4 UPnP/1.0 MiMicUPnP/0.2"\r
86 \r
87 \r
88 /**\r
89  * MsearchResponseを格納したTxパケットをAllocする。\r
90  * @param i_st\r
91  * ST値\r
92  * @param i_udn\r
93  * DDESCのUDNの値\r
94  * @param i_usn\r
95  * USNのサフィックスパラメータ\r
96  * @return\r
97  * MsearchResponseを格納したTXメモリ\r
98  */\r
99 static void* allocMsearchResponeTx(\r
100         NyLPC_TcSsdpSocket_t* i_inst,\r
101         const NyLPC_TChar* i_st,\r
102         const NyLPC_TChar* i_udn,\r
103         const NyLPC_TChar* i_usn,\r
104         NyLPC_TUInt16 i_st_len,\r
105         NyLPC_TInt16* o_len)\r
106 {\r
107         NyLPC_TChar* obuf;\r
108         NyLPC_TUInt16 l;\r
109         NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)((i_usn!=NULL)?strlen(i_usn):0);\r
110         NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);\r
111         NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);\r
112 \r
113         //      //161Byte\r
114         //      "HTTP/1.1 200 OK\r\n"                                                   //15+2=17\r
115         //      "CACHE-CONTROL: max-age = nnnn\r\n"                     //29+2=31\r
116         //      "SERVER: [:40byte:]\r\n"                                                //8+40+2=50\r
117         //      "EXT: \r\n"                                                                     //5+2 = 7\r
118         //      "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"   //34+2=46\r
119         //      "USN: %s%s\r\n"                                                                 //5+2=7\r
120         //      "ST: %s\r\n\r\n"                                                                //4+4=8\r
121         l=166+len_location+len_usn+len_udn+i_st_len;\r
122         obuf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,l,&l,TIMEOUT_IN_MS);\r
123 \r
124         if(obuf==NULL){\r
125                 return NULL;\r
126         }\r
127         //必要なメモリサイズを確保できた?\r
128         if(l<161+len_location+len_usn+len_udn+i_st_len)\r
129         {\r
130                 NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,obuf);\r
131                 return NULL;\r
132         }\r
133         //ワーク変数lの再初期化\r
134         l=0;\r
135         strcpy(obuf,\r
136                 "HTTP/1.1 200 OK\r\n"\r
137                 "CACHE-CONTROL: max-age = 300\r\n"\r
138                 "SERVER: "SERVER_MESSAGE_HEADER"\r\n"\r
139                 "EXT: \r\n"\r
140                 "LOCATION: http://");\r
141         l+=strlen(obuf);\r
142         //IP addr:port\r\n\r
143         l+=NyLPC_TIPv4Addr_toString(NyLPC_iUdpSocket_getSockIP(i_inst->_socket),obuf+l);\r
144         *(obuf+l)=':';\r
145         l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);\r
146         *(obuf+l)='/';l++;\r
147         memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;\r
148         memcpy(obuf+l,"/d.xml",6);l+=6;\r
149         *(obuf+l+0)='\r';\r
150         *(obuf+l+1)='\n';\r
151         l+=2;\r
152         //USN: uuid:xxx\r
153         memcpy(obuf+l,"USN: ",5);               l+=5;\r
154         memcpy(obuf+l,i_udn,len_udn);   l+=len_udn;     //uuid:xxx\r
155         if(i_usn!=NULL){\r
156                 *(obuf+l+0)=':';\r
157                 *(obuf+l+1)=':';\r
158                 l+=2;\r
159                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;        //usn:xxx\r
160         }\r
161         *(obuf+l+0)='\r';\r
162         *(obuf+l+1)='\n';\r
163         l+=2;\r
164         //ST\r
165         memcpy(obuf+l,"ST: ",4);        l+=4;\r
166         memcpy(obuf+l,i_st,i_st_len);l+=i_st_len;\r
167         memcpy(obuf+l,"\r\n\r\n",4);    l+=4;\r
168         *o_len=l;\r
169         return obuf;\r
170 }\r
171 \r
172 \r
173 /**\r
174  * MsearchResponseを格納したTxパケットをAllocする。\r
175  * @param i_udn\r
176  * udn\r
177  * @param i_udn\r
178  * DDESCのUDNの値\r
179  * @param i_usn\r
180  * USNのサフィックスパラメータ\r
181  * @return\r
182  * MsearchResponseを格納したTXメモリ\r
183  */\r
184 static void* allocNotifyTx(\r
185         NyLPC_TcSsdpSocket_t* i_inst,\r
186         const NyLPC_TChar* i_udn,\r
187         const NyLPC_TChar* i_usn,\r
188         NyLPC_TInt16* o_len)\r
189 {\r
190         NyLPC_TChar* obuf;\r
191         NyLPC_TUInt16 l,l2;\r
192         NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)((i_usn!=NULL)?strlen(i_usn):0);\r
193         NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);\r
194         NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);\r
195 \r
196         //      //193Byte\r
197         //      "NOTIFY * HTTP/1.1\r\n"                                                 //15+2=17\r
198         //      "HOST: 239.255.255.250:1900\r\n"                                //26+2=28\r
199         //      "CACHE-CONTROL: max-age = 1800\r\n"                     //29+2=31\r
200         //      "SERVER: [:40byte:]\r\n"                                                //8+40+2=50\r
201         //      "NTS: ssdp:alive\r\n"                                                   //14+2 =17\r
202         //      "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"//44+2=46\r
203         //      "USN: %s%s\r\n"                                                                 //5+2=7\r
204         //      "NT: %s\r\n\r\n"                                                                //4+4=8\r
205         l2=204+len_location+len_usn+len_udn+((len_usn>0)?len_usn:len_udn);\r
206         obuf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,l2,&l,TIMEOUT_IN_MS);\r
207         if(obuf==NULL){\r
208                 return NULL;\r
209         }\r
210         //必要なメモリサイズを確保できた?\r
211         if(l<l2)\r
212         {\r
213                 NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,obuf);\r
214                 return NULL;\r
215         }\r
216         //ワーク変数lの再初期化\r
217         l=0;\r
218         strcpy(obuf,\r
219                 "NOTIFY * HTTP/1.1\r\n"\r
220                 "HOST: 239.255.255.250:1900\r\n"\r
221                 "CACHE-CONTROL: max-age = 300\r\n"\r
222                 "SERVER: "SERVER_MESSAGE_HEADER"\r\n"\r
223                 "NTS: ssdp:alive\r\n"\r
224                 "LOCATION: http://");\r
225         l+=strlen(obuf);\r
226         //IP addr:port\r\n\r
227         l+=NyLPC_TIPv4Addr_toString(NyLPC_iUdpSocket_getSockIP(i_inst->_socket),obuf+l);\r
228         *(obuf+l)=':';\r
229         l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);\r
230         *(obuf+l)='/';l++;\r
231         memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;\r
232         memcpy(obuf+l,"/d.xml",6);l+=6;\r
233         *(obuf+l+0)='\r';\r
234         *(obuf+l+1)='\n';\r
235         l+=2;\r
236         //USN: uuid:xxx\r
237         memcpy(obuf+l,"USN: ",5);       l+=5;\r
238         memcpy(obuf+l,i_udn,len_udn);   l+=len_udn;     //uuid:xxx\r
239         if(i_usn!=NULL){\r
240                 *(obuf+l+0)=':';\r
241                 *(obuf+l+1)=':';\r
242                 l+=2;\r
243                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;        //usn:xxx\r
244         }\r
245         *(obuf+l+0)='\r';\r
246         *(obuf+l+1)='\n';\r
247         l+=2;\r
248         //NT\r
249         memcpy(obuf+l,"NT: ",4);        l+=4;\r
250         if(len_usn>0){\r
251                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;\r
252         }else{\r
253                 memcpy(obuf+l,i_udn,len_udn);l+=len_udn;\r
254         }\r
255         memcpy(obuf+l,"\r\n\r\n",4);    l+=4;\r
256         *o_len=l;\r
257         return obuf;\r
258 }\r
259 \r
260 \r
261 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)\r
262 {\r
263         struct TMSearchHeader* header=(struct TMSearchHeader*)o_out;\r
264         switch(header->st)\r
265         {\r
266                 case PARSE_NULL:\r
267                         if(NyLPC_stricmp(i_name,"ST")==0){\r
268                                 //mode==ST\r
269                                 header->st=PARSE_ST;\r
270                                 header->result.st_str=NULL;\r
271                         }else if(NyLPC_stricmp(i_name,"MAN")==0){\r
272                                 //mode=MAN\r
273                                 header->st=PARSE_MAN;\r
274                                 header->result.man_str=NULL;\r
275                         }else{\r
276                                 header->st=PARSE_UNKNOWN;\r
277                                 //無視\r
278                         }\r
279                         break;\r
280                 case PARSE_ST:\r
281                         if((header->result.st_str==NULL) && (i_c!=HTTP_SP)){\r
282                                 header->result.st_str=header->_rpos;\r
283                         }\r
284                         if(i_c=='\0')\r
285                         {\r
286                                 header->result.st_len=header->_rpos-header->result.st_str-1;\r
287                                 header->st=PARSE_NULL;\r
288                         }\r
289                         break;\r
290                 case PARSE_MAN:\r
291                         if((header->result.man_str==NULL) && (i_c!=HTTP_SP)){\r
292                                 header->result.man_str=header->_rpos;\r
293                         }\r
294                         if(i_c=='\0'){\r
295                                 header->result.man_len=header->_rpos-header->result.man_str-1;\r
296                                 header->st=PARSE_NULL;\r
297                         }\r
298                         break;\r
299                 case PARSE_UNKNOWN:\r
300                 default:\r
301                         if(i_c=='\0'){\r
302                                 header->st=PARSE_NULL;\r
303                         }\r
304                         break;\r
305         }\r
306         return NyLPC_TBool_TRUE;\r
307 }\r
308 \r
309 /**\r
310  * デフォルトハンドラ\r
311  */\r
312 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=\r
313 {\r
314         messageHandler,\r
315         urlHandler\r
316 };\r
317 \r
318 static NyLPC_TBool parseHeader(struct TMSearchHeader* i_out,const void* i_rx,NyLPC_TInt16 i_rx_size)\r
319 {\r
320         NyLPC_TInt16 i;\r
321         NyLPC_TcHttpBasicHeaderParser_t parser;\r
322         //headerの初期化\r
323         i_out->st=PARSE_NULL;\r
324         i_out->result.st_str=NULL;\r
325         i_out->result.man_str=NULL;\r
326         NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);\r
327         NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(i_out->super));\r
328         for(i=0;i<i_rx_size;i++){\r
329                 i_out->_rpos=((const char*)(i_rx))+i;\r
330                 if(NyLPC_cHttpBasicHeaderParser_parseChar(&parser,i_out->_rpos,1,&(i_out->super))<0){\r
331                         NyLPC_cHttpBasicHeaderParser_finalize(&parser);\r
332                         return NyLPC_TBool_FALSE;//ERROR\r
333                 }\r
334         }\r
335         NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(i_out->super));\r
336         NyLPC_cHttpBasicHeaderParser_finalize(&parser);\r
337         return NyLPC_TBool_TRUE;//OK\r
338 }\r
339 \r
340 static NyLPC_TBool onPacket(NyLPC_TiUdpSocket_t* i_sock,const void* i_buf,const struct NyLPC_TIPv4RxInfo* i_info)\r
341 {\r
342         //パケット解析\r
343         void* tx;\r
344         struct TMSearchHeader header;\r
345         NyLPC_TInt16 tx_len;\r
346         NyLPC_TInt8 i,i2;\r
347         NyLPC_TcSsdpSocket_t* inst=((NyLPC_TcSsdpSocket_t*)i_sock->_tag);\r
348         if(!parseHeader(&header,i_buf,i_info->size)){\r
349                 NyLPC_OnErrorGoto(ERROR1);\r
350         }\r
351         //resultチェック\r
352         if(header.result.man_str==NULL || header.result.st_str==NULL){\r
353                 NyLPC_OnErrorGoto(ERROR1);\r
354         }\r
355         //Methodチェック\r
356         if(header.super.startline.req.method!=NyLPC_THttpMethodType_M_SEARCH){\r
357                 NyLPC_OnErrorGoto(ERROR1);\r
358         }\r
359 \r
360         //MANチェック\r
361         if(strncmp("\"ssdp:discover\"",header.result.man_str,15)!=0){\r
362                 NyLPC_OnErrorGoto(ERROR1);\r
363         }\r
364         //STによる処理分岐\r
365         if(strncmp("ssdp:all",header.result.st_str,8)==0){\r
366                 tx=allocMsearchResponeTx(\r
367                         inst,header.result.st_str,\r
368                         inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,\r
369                         header.result.st_len,\r
370                         &tx_len);\r
371                 if(tx==NULL){\r
372                         NyLPC_OnErrorGoto(ERROR1);\r
373                 }\r
374                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
375                         NyLPC_OnErrorGoto(ERROR2);\r
376                 }\r
377                 //全デバイスの送信\r
378                 for(i=0;i<inst->number_of_device;i++){\r
379                         tx=allocMsearchResponeTx(\r
380                                 inst,header.result.st_str,\r
381                                 inst->ref_device_record[i]->udn,inst->ref_device_record[i]->device_type,\r
382                                 header.result.st_len,\r
383                                 &tx_len);\r
384                         if(tx==NULL){\r
385                                 NyLPC_OnErrorGoto(ERROR1);\r
386                         }\r
387                         if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
388                                 NyLPC_OnErrorGoto(ERROR2);\r
389                         }\r
390                         for(i2=0;i2<inst->ref_device_record[i]->number_of_service;i2++){\r
391                                 //serviceに一致\r
392                                 tx=allocMsearchResponeTx(\r
393                                         inst,header.result.st_str,\r
394                                         inst->ref_device_record[i]->udn,inst->ref_device_record[i]->services[i2].service_type,\r
395                                         header.result.st_len,\r
396                                         &tx_len);\r
397                                 if(tx==NULL){\r
398                                         NyLPC_OnErrorGoto(ERROR1);\r
399                                 }\r
400                                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
401                                         NyLPC_OnErrorGoto(ERROR2);\r
402                                 }\r
403                         }\r
404                 }\r
405         }else if(strncmp("uuid:",header.result.st_str,5)==0){\r
406                 //UDNの一致するデバイスの送信\r
407                 NyLPC_TInt16 i;\r
408                 for(i=inst->number_of_device-1;i>=0;i--){\r
409                         if(strncmp(header.result.st_str,inst->ref_device_record[i]->udn,header.result.st_len)==0){\r
410                                 //UDN一致\r
411                                 tx=allocMsearchResponeTx(\r
412                                         inst,header.result.st_str,\r
413                                         inst->ref_device_record[i]->udn,NULL,\r
414                                         header.result.st_len,\r
415                                         &tx_len);\r
416                                 if(tx==NULL){\r
417                                         NyLPC_OnErrorGoto(ERROR1);\r
418                                 }\r
419                                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
420                                         NyLPC_OnErrorGoto(ERROR2);\r
421                                 }\r
422                                 break;//送信処理終了\r
423                         }\r
424                 }\r
425         }else if(strncmp(STR_UPNP_ROOT_DEVICE,header.result.st_str,15)==0){\r
426                 //rootDeviceはSTR_UPNP_ROOT_DEVICE\r
427                 tx=allocMsearchResponeTx(\r
428                         inst,header.result.st_str,\r
429                         inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,\r
430                         header.result.st_len,\r
431                         &tx_len);\r
432                 if(tx==NULL){\r
433                         NyLPC_OnErrorGoto(ERROR1);\r
434                 }\r
435                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
436                         NyLPC_OnErrorGoto(ERROR2);\r
437                 }\r
438         }else if(strncmp("urn:",header.result.st_str,4)==0){\r
439                 for(i=0;i<inst->number_of_device;i++){\r
440                         //urn一致チェック\r
441                         if(strncmp(inst->ref_device_record[i]->device_type,header.result.st_str,header.result.st_len)==0){\r
442                                 //deviceに一致\r
443                                 tx=allocMsearchResponeTx(\r
444                                         inst,header.result.st_str,\r
445                                         inst->ref_device_record[i]->udn,inst->ref_device_record[i]->device_type,\r
446                                         header.result.st_len,\r
447                                         &tx_len);\r
448                                 if(tx==NULL){\r
449                                         NyLPC_OnErrorGoto(ERROR1);\r
450                                 }\r
451                                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
452                                         NyLPC_OnErrorGoto(ERROR2);\r
453                                 }\r
454                                 continue;\r
455                         }\r
456                         for(i2=0;i2<inst->ref_device_record[i]->number_of_service;i2++){\r
457                                 if(strncmp(inst->ref_device_record[i]->services[i2].service_type,header.result.st_str,header.result.st_len)==0){\r
458                                         //serviceに一致\r
459                                         tx=allocMsearchResponeTx(\r
460                                                 inst,header.result.st_str,\r
461                                                 inst->ref_device_record[i]->udn,inst->ref_device_record[i]->services[i2].service_type,\r
462                                                 header.result.st_len,\r
463                                                 &tx_len);\r
464                                         if(tx==NULL){\r
465                                                 NyLPC_OnErrorGoto(ERROR1);\r
466                                         }\r
467                                         if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
468                                                 NyLPC_OnErrorGoto(ERROR2);\r
469                                         }\r
470                                 }\r
471                         }\r
472                 }\r
473         }\r
474         //正常終了\r
475         return NyLPC_TBool_FALSE;\r
476 ERROR2:\r
477         NyLPC_iUdpSocket_releaseSendBuf(i_sock,tx);\r
478 ERROR1:\r
479         return NyLPC_TBool_FALSE;\r
480 }\r
481 \r
482 #define SSDP_NOTIFY_INTERVAL 150*1000   //300*0.5*1000\r
483 #define FLAG_ORDER_START_SERVICE        0\r
484 #define FLAG_ORDER_STOP_SERVICE         1\r
485 #define FLAG_IS_SERVICE_RUNNING         2\r
486 \r
487 static void onPeriodic(NyLPC_TiUdpSocket_t* i_sock)\r
488 {\r
489         NyLPC_TcSsdpSocket_t* inst=(NyLPC_TcSsdpSocket_t*)i_sock->_tag;\r
490         if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_IS_SERVICE_RUNNING)){\r
491         //実行中\r
492                 //停止要求着てる?\r
493                 if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_ORDER_STOP_SERVICE))\r
494                 {\r
495                         //状態変更\r
496                         NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_IS_SERVICE_RUNNING);\r
497                         //要求フラグクリア\r
498                         NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_ORDER_STOP_SERVICE);\r
499                         //@bug ByeBye送信しろ\r
500                 }else if(NyLPC_cStopwatch_isExpired(&inst->_periodic_sw)){\r
501                         //Notify送信\r
502                         NyLPC_cSsdpSocket_notify(inst);\r
503                         //タイマ再始動\r
504                         NyLPC_cStopwatch_startExpire(&inst->_periodic_sw,SSDP_NOTIFY_INTERVAL);\r
505                 }\r
506         }else{\r
507         //停止中\r
508                 //開始要求着てる?\r
509                 if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_ORDER_START_SERVICE))\r
510                 {\r
511                         //状態変更\r
512                         NyLPC_TUInt8_setBit(inst->_flags,FLAG_IS_SERVICE_RUNNING);\r
513                         //要求フラグクリア\r
514                         NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_ORDER_START_SERVICE);\r
515                         //次回expireするように\r
516                         NyLPC_cStopwatch_startExpire(&inst->_periodic_sw,SSDP_NOTIFY_INTERVAL);\r
517                 }\r
518         }\r
519 }\r
520 \r
521 /**\r
522  * デバイスツリーを展開する。\r
523  */\r
524 static void expandDeviceTree(NyLPC_TcSsdpSocket_t* i_inst,const struct NyLPC_TUPnPDevDescDevice* i_dev)\r
525 {\r
526         NyLPC_TUInt16 i;\r
527         if(i_inst->number_of_device>=NyLPC_TcSsdpSocket_MAX_DEVICES){\r
528                 NyLPC_Warning();//\r
529         }\r
530         i_inst->ref_device_record[i_inst->number_of_device]=i_dev;\r
531         i_inst->number_of_device++;\r
532         for(i=0;i<i_dev->number_of_devices;i++){\r
533                 expandDeviceTree(i_inst,i_dev->devices[i]);\r
534         }\r
535         return;\r
536 }\r
537 \r
538 void NyLPC_cSsdpSocket_initialize(\r
539                 NyLPC_TcSsdpSocket_t* i_inst,\r
540                 const struct NyLPC_TUPnPDevDescDevice* i_ref_dev_record,\r
541                 NyLPC_TUInt16 i_server_port,const NyLPC_TChar* i_ref_location_path)\r
542 {\r
543         i_inst->_socket=NyLPC_cNet_createUdpSocketEx(1900,NyLPC_TSocketType_UDP_NOBUF);\r
544     i_inst->_socket->_tag=i_inst;\r
545 \r
546         NyLPC_iUdpSocket_setOnRxHandler(i_inst->_socket,onPacket);\r
547         NyLPC_iUdpSocket_setOnPeriodicHandler(i_inst->_socket,onPeriodic);\r
548 \r
549         NyLPC_iUdpSocket_joinMulticast(i_inst->_socket,&SSDP_MCAST_IPADDR);\r
550         i_inst->_flags=0;\r
551         NyLPC_cStopwatch_initialize(&(i_inst->_periodic_sw));\r
552         i_inst->number_of_device=0;\r
553         expandDeviceTree(i_inst,i_ref_dev_record);\r
554         i_inst->location_port=i_server_port;\r
555         i_inst->location_path=i_ref_location_path;\r
556 }\r
557 void NyLPC_cSsdpSocket_finalize(NyLPC_TcSsdpSocket_t* i_inst)\r
558 {\r
559         NyLPC_cStopwatch_finalize(&(i_inst->_periodic_sw));\r
560         NyLPC_iUdpSocket_finalize(i_inst->_socket);\r
561 }\r
562 \r
563 void NyLPC_cSsdpSocket_start(NyLPC_TcSsdpSocket_t* i_inst)\r
564 {\r
565         //Notifyを3回送信\r
566         NyLPC_TInt16 i;\r
567         NyLPC_cSsdpSocket_notify(i_inst);\r
568         for(i=0;i<2;i++){\r
569                 NyLPC_cThread_sleep(800);\r
570                 NyLPC_cSsdpSocket_notify(i_inst);\r
571         }\r
572 \r
573         //ストップウォッチの開始要求\r
574         NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_START_SERVICE);\r
575         do{\r
576                 NyLPC_cThread_sleep(10);\r
577                 //開始フラグがクリアされるまでループ\r
578         }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_START_SERVICE));\r
579 }\r
580 void NyLPC_cSsdpSocket_stop(NyLPC_TcSsdpSocket_t* i_inst)\r
581 {\r
582         //今は使えない。\r
583         NyLPC_Abort();\r
584         NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_STOP_SERVICE);\r
585         do{\r
586                 NyLPC_cThread_sleep(10);\r
587                 //開始フラグがクリアされるまでループ\r
588         }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_STOP_SERVICE));\r
589 }\r
590 void NyLPC_cSsdpSocket_notify(NyLPC_TcSsdpSocket_t* i_inst)\r
591 {\r
592         void* tx;\r
593         NyLPC_TInt16 tx_len;\r
594         NyLPC_TUInt8 i,i2;\r
595         //rootdevice\r
596         tx=allocNotifyTx(\r
597                 i_inst,\r
598                 i_inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,\r
599                 &tx_len);\r
600         if(tx==NULL){\r
601                 NyLPC_OnErrorGoto(ERROR1);\r
602         }\r
603         if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
604                 NyLPC_OnErrorGoto(ERROR2);\r
605         }\r
606         //all device\r
607         for(i=0;i<i_inst->number_of_device;i++){\r
608                 //uuid\r
609                 tx=allocNotifyTx(\r
610                         i_inst,\r
611                         i_inst->ref_device_record[i]->udn,NULL,\r
612                         &tx_len);\r
613                 if(tx==NULL){\r
614                         NyLPC_OnErrorGoto(ERROR1);\r
615                 }\r
616                 if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
617                         NyLPC_OnErrorGoto(ERROR2);\r
618                 }\r
619                 //devicatype\r
620                 tx=allocNotifyTx(\r
621                         i_inst,\r
622                         i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->device_type,\r
623                         &tx_len);\r
624                 if(tx==NULL){\r
625                         NyLPC_OnErrorGoto(ERROR1);\r
626                 }\r
627                 if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
628                         NyLPC_OnErrorGoto(ERROR2);\r
629                 }\r
630                 for(i2=0;i2<i_inst->ref_device_record[i]->number_of_service;i2++){\r
631                         tx=allocNotifyTx(\r
632                                 i_inst,\r
633                                 i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->services[i2].service_type,\r
634                                 &tx_len);\r
635                         if(tx==NULL){\r
636                                 NyLPC_OnErrorGoto(ERROR1);\r
637                         }\r
638                         if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
639                                 NyLPC_OnErrorGoto(ERROR2);\r
640                         }\r
641                 }\r
642         }\r
643         return;\r
644 ERROR2:\r
645         NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,tx);\r
646 ERROR1:\r
647         return;\r
648 }\r
649 \r