OSDN Git Service

update version and ssdp
[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_uipService.h"\r
29 #include "../uip/NyLPC_cUipService_protected.h"\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 static NyLPC_TInt16 printIpAddr(const struct NyLPC_TIPv4Addr* i_ip,NyLPC_TChar* i_buf)\r
79 {\r
80         NyLPC_TUInt32 ip;\r
81         NyLPC_TUInt8 v;\r
82         NyLPC_TInt8 l;\r
83         NyLPC_TChar* p=i_buf;\r
84         //IPをホストオーダーにする。\r
85         ip=NyLPC_NTOHL(i_ip->v);\r
86         for(l=3;l>=0;l--){\r
87                 v=(ip>>(8*l))&0xff;\r
88                 if(v<10){\r
89                         //1桁\r
90                         *(p+0)=v+'0';\r
91                         *(p+1)='.';\r
92                         p+=2;\r
93                 }else if(v<100){\r
94                         //2桁\r
95                         *(p+0)=(v/10)+'0';\r
96                         *(p+1)=(v%10)+'0';\r
97                         *(p+2)='.';\r
98                         p+=3;\r
99                 }else{\r
100                         //3桁\r
101                         *(p+0)=(v/100)+'0';\r
102                         *(p+1)=((v/10)%10)+'0';\r
103                         *(p+2)=(v%10)+'0';\r
104                         *(p+3)='.';\r
105                         p+=4;\r
106                 }\r
107         }\r
108         return p-i_buf-1;\r
109 }\r
110 #define TIMEOUT_IN_MS 100\r
111 \r
112 /**\r
113  * SERVER MessageHeaderの値\r
114  * 40文字以内であること。\r
115  */\r
116 #define SERVER_MESSAGE_HEADER "MiMic/1.4;UPnP/1.0;MiMicUPnP/0.1"\r
117 \r
118 \r
119 /**\r
120  * MsearchResponseを格納したTxパケットをAllocする。\r
121  * @param i_st\r
122  * ST値\r
123  * @param i_udn\r
124  * DDESCのUDNの値\r
125  * @param i_usn\r
126  * USNのサフィックスパラメータ\r
127  * @return\r
128  * MsearchResponseを格納したTXメモリ\r
129  */\r
130 static void* allocMsearchResponeTx(\r
131         NyLPC_TcSsdpSocket_t* i_inst,\r
132         const NyLPC_TChar* i_st,\r
133         const NyLPC_TChar* i_udn,\r
134         const NyLPC_TChar* i_usn,\r
135         NyLPC_TUInt16 i_st_len,\r
136         NyLPC_TInt16* o_len)\r
137 {\r
138         NyLPC_TChar* obuf;\r
139         NyLPC_TUInt16 l;\r
140         NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)(i_usn!=NULL?strlen(i_usn):0);\r
141         NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);\r
142         NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);\r
143 \r
144         //      //161Byte\r
145         //      "HTTP/1.1 200 OK\r\n"                                                   //15+2=17\r
146         //      "CACHE-CONTROL: max-age = nnnn\r\n"                     //29+2=31\r
147         //      "SERVER: [:40byte:]\r\n"                                                //8+40+2=50\r
148         //      "EXT: \r\n"                                                                     //5+2 = 7\r
149         //      "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"   //34+2=46\r
150         //      "USN: %s%s\r\n"                                                                 //5+2=7\r
151         //      "ST: %s\r\n\r\n"                                                                //4+4=8\r
152         l=166+len_location+len_usn+len_udn+i_st_len;\r
153         obuf=NyLPC_cUdpSocket_allocSendBuf(&(i_inst->super),l,&l,TIMEOUT_IN_MS);\r
154 \r
155         if(obuf==NULL){\r
156                 return NULL;\r
157         }\r
158         //必要なメモリサイズを確保できた?\r
159         if(l<161+len_location+len_usn+len_udn+i_st_len)\r
160         {\r
161                 NyLPC_cUdpSocket_releaseSendBuf(&i_inst->super,obuf);\r
162                 return NULL;\r
163         }\r
164         //ワーク変数lの再初期化\r
165         l=0;\r
166         strcpy(obuf,\r
167                 "HTTP/1.1 200 OK\r\n"\r
168                 "CACHE-CONTROL: max-age = 300\r\n"\r
169                 "SERVER: "SERVER_MESSAGE_HEADER"\r\n"\r
170                 "EXT: \r\n"\r
171                 "LOCATION: http://");\r
172         l+=strlen(obuf);\r
173         //IP addr:port\r\n\r
174         l+=printIpAddr(NyLPC_cUdpSocket_getSockIP(&i_inst->super),obuf+l);\r
175         *(obuf+l)=':';\r
176         l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);\r
177         *(obuf+l)='/';l++;\r
178         memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;\r
179         memcpy(obuf+l,"/d.xml",6);l+=6;\r
180         *(obuf+l+0)='\r';\r
181         *(obuf+l+1)='\n';\r
182         l+=2;\r
183         //USN: uuid:xxx\r
184         memcpy(obuf+l,"USN: ",5);               l+=5;\r
185         memcpy(obuf+l,i_udn,len_udn);   l+=len_udn;     //uuid:xxx\r
186         if(i_usn!=NULL){\r
187                 *(obuf+l+0)=':';\r
188                 *(obuf+l+1)=':';\r
189                 l+=2;\r
190                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;        //usn:xxx\r
191         }\r
192         *(obuf+l+0)='\r';\r
193         *(obuf+l+1)='\n';\r
194         l+=2;\r
195         //ST\r
196         memcpy(obuf+l,"ST: ",4);        l+=4;\r
197         memcpy(obuf+l,i_st,i_st_len);l+=i_st_len;\r
198         memcpy(obuf+l,"\r\n\r\n",4);    l+=4;\r
199         *o_len=l;\r
200         return obuf;\r
201 }\r
202 \r
203 \r
204 /**\r
205  * MsearchResponseを格納したTxパケットをAllocする。\r
206  * @param i_udn\r
207  * udn\r
208  * @param i_udn\r
209  * DDESCのUDNの値\r
210  * @param i_usn\r
211  * USNのサフィックスパラメータ\r
212  * @return\r
213  * MsearchResponseを格納したTXメモリ\r
214  */\r
215 static void* allocNotifyTx(\r
216         NyLPC_TcSsdpSocket_t* i_inst,\r
217         const NyLPC_TChar* i_udn,\r
218         const NyLPC_TChar* i_usn,\r
219         NyLPC_TInt16* o_len)\r
220 {\r
221         NyLPC_TChar* obuf;\r
222         NyLPC_TUInt16 l,l2;\r
223         NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)(i_usn!=NULL?strlen(i_usn):0);\r
224         NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);\r
225         NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);\r
226 \r
227         //      //193Byte\r
228         //      "NOTIFY * HTTP/1.1\r\n"                                                 //15+2=17\r
229         //      "HOST: 239.255.255.250:1900\r\n"                                //26+2=28\r
230         //      "CACHE-CONTROL: max-age = 1800\r\n"                     //29+2=31\r
231         //      "SERVER: [:40byte:]\r\n"                                                //8+40+2=50\r
232         //      "NTS: ssdp:alive\r\n"                                                   //14+2 =17\r
233         //      "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"//44+2=46\r
234         //      "USN: %s%s\r\n"                                                                 //5+2=7\r
235         //      "NT: %s\r\n\r\n"                                                                //4+4=8\r
236         l2=204+len_location+len_usn+len_udn+(len_usn>0?len_usn:len_udn);\r
237         obuf=NyLPC_cUdpSocket_allocSendBuf(&(i_inst->super),l2,&l,TIMEOUT_IN_MS);\r
238         if(obuf==NULL){\r
239                 return NULL;\r
240         }\r
241         //必要なメモリサイズを確保できた?\r
242         if(l<l2)\r
243         {\r
244                 NyLPC_cUdpSocket_releaseSendBuf(&i_inst->super,obuf);\r
245                 return NULL;\r
246         }\r
247         //ワーク変数lの再初期化\r
248         l=0;\r
249         strcpy(obuf,\r
250                 "NOTIFY * HTTP/1.1\r\n"\r
251                 "HOST: 239.255.255.250:1900\r\n"\r
252                 "CACHE-CONTROL: max-age = 300\r\n"\r
253                 "SERVER: "SERVER_MESSAGE_HEADER"\r\n"\r
254                 "NTS: ssdp:alive\r\n"\r
255                 "LOCATION: http://");\r
256         l+=strlen(obuf);\r
257         //IP addr:port\r\n\r
258         l+=printIpAddr(NyLPC_cUdpSocket_getSockIP(&i_inst->super),obuf+l);\r
259         *(obuf+l)=':';\r
260         l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);\r
261         *(obuf+l)='/';l++;\r
262         memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;\r
263         memcpy(obuf+l,"/d.xml",6);l+=6;\r
264         *(obuf+l+0)='\r';\r
265         *(obuf+l+1)='\n';\r
266         l+=2;\r
267         //USN: uuid:xxx\r
268         memcpy(obuf+l,"USN: ",5);       l+=5;\r
269         memcpy(obuf+l,i_udn,len_udn);   l+=len_udn;     //uuid:xxx\r
270         if(i_usn!=NULL){\r
271                 *(obuf+l+0)=':';\r
272                 *(obuf+l+1)=':';\r
273                 l+=2;\r
274                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;        //usn:xxx\r
275         }\r
276         *(obuf+l+0)='\r';\r
277         *(obuf+l+1)='\n';\r
278         l+=2;\r
279         //NT\r
280         memcpy(obuf+l,"NT: ",4);        l+=4;\r
281         if(len_usn>0){\r
282                 memcpy(obuf+l,i_usn,len_usn);l+=len_usn;\r
283         }else{\r
284                 memcpy(obuf+l,i_udn,len_udn);l+=len_udn;\r
285         }\r
286         memcpy(obuf+l,"\r\n\r\n",4);    l+=4;\r
287         *o_len=l;\r
288         return obuf;\r
289 }\r
290 \r
291 \r
292 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)\r
293 {\r
294         struct TMSearchHeader* header=(struct TMSearchHeader*)o_out;\r
295         switch(header->st)\r
296         {\r
297                 case PARSE_NULL:\r
298                         if(NyLPC_stricmp(i_name,"ST")==0){\r
299                                 //mode==ST\r
300                                 header->st=PARSE_ST;\r
301                                 header->result.st_str=NULL;\r
302                         }else if(NyLPC_stricmp(i_name,"MAN")==0){\r
303                                 //mode=MAN\r
304                                 header->st=PARSE_MAN;\r
305                                 header->result.man_str=NULL;\r
306                         }else{\r
307                                 header->st=PARSE_UNKNOWN;\r
308                                 //無視\r
309                         }\r
310                         break;\r
311                 case PARSE_ST:\r
312                         if((header->result.st_str==NULL) && (i_c!=HTTP_SP)){\r
313                                 header->result.st_str=header->_rpos;\r
314                         }\r
315                         if(i_c=='\0')\r
316                         {\r
317                                 header->result.st_len=header->_rpos-header->result.st_str-1;\r
318                                 header->st=PARSE_NULL;\r
319                         }\r
320                         break;\r
321                 case PARSE_MAN:\r
322                         if((header->result.man_str==NULL) && (i_c!=HTTP_SP)){\r
323                                 header->result.man_str=header->_rpos;\r
324                         }\r
325                         if(i_c=='\0'){\r
326                                 header->result.man_len=header->_rpos-header->result.man_str-1;\r
327                                 header->st=PARSE_NULL;\r
328                         }\r
329                         break;\r
330                 case PARSE_UNKNOWN:\r
331                 default:\r
332                         if(i_c=='\0'){\r
333                                 header->st=PARSE_NULL;\r
334                         }\r
335                         break;\r
336         }\r
337         return NyLPC_TBool_TRUE;\r
338 }\r
339 \r
340 /**\r
341  * デフォルトハンドラ\r
342  */\r
343 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=\r
344 {\r
345         messageHandler,\r
346         urlHandler\r
347 };\r
348 \r
349 static NyLPC_TBool parseHeader(struct TMSearchHeader* i_out,const void* i_rx,NyLPC_TInt16 i_rx_size)\r
350 {\r
351         NyLPC_TInt16 i;\r
352         NyLPC_TcHttpBasicHeaderParser_t parser;\r
353         //headerの初期化\r
354         i_out->st=PARSE_NULL;\r
355         i_out->result.st_str=NULL;\r
356         i_out->result.man_str=NULL;\r
357         NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);\r
358         NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(i_out->super));\r
359         for(i=0;i<i_rx_size;i++){\r
360                 i_out->_rpos=((const char*)(i_rx))+i;\r
361                 if(NyLPC_cHttpBasicHeaderParser_parseChar(&parser,i_out->_rpos,1,&(i_out->super))<0){\r
362                         NyLPC_cHttpBasicHeaderParser_finalize(&parser);\r
363                         return NyLPC_TBool_FALSE;//ERROR\r
364                 }\r
365         }\r
366         NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(i_out->super));\r
367         NyLPC_cHttpBasicHeaderParser_finalize(&parser);\r
368         return NyLPC_TBool_TRUE;//OK\r
369 }\r
370 \r
371 static NyLPC_TBool onPacket(NyLPC_TcUdpSocket_t* i_inst,const void* i_buf,const struct NyLPC_TIPv4RxInfo* i_info)\r
372 {\r
373         //パケット解析\r
374         void* tx;\r
375         struct TMSearchHeader header;\r
376         NyLPC_TInt16 tx_len;\r
377         NyLPC_TInt8 i,i2;\r
378         NyLPC_TcSsdpSocket_t* sock=(NyLPC_TcSsdpSocket_t*)i_inst;\r
379         if(!parseHeader(&header,i_buf,i_info->size)){\r
380                 NyLPC_OnErrorGoto(ERROR1);\r
381         }\r
382         //resultチェック\r
383         if(header.result.man_str==NULL || header.result.st_str==NULL){\r
384                 NyLPC_OnErrorGoto(ERROR1);\r
385         }\r
386         //Methodチェック\r
387         if(header.super.startline.req.method!=NyLPC_THttpMethodType_M_SEARCH){\r
388                 NyLPC_OnErrorGoto(ERROR1);\r
389         }\r
390 \r
391         //MANチェック\r
392         if(strncmp("\"ssdp:discover\"",header.result.man_str,15)!=0){\r
393                 NyLPC_OnErrorGoto(ERROR1);\r
394         }\r
395         //STによる処理分岐\r
396         if(strncmp("ssdp:all",header.result.st_str,8)==0){\r
397                 tx=allocMsearchResponeTx(\r
398                         sock,header.result.st_str,\r
399                         sock->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,\r
400                         header.result.st_len,\r
401                         &tx_len);\r
402                 if(tx==NULL){\r
403                         NyLPC_OnErrorGoto(ERROR1);\r
404                 }\r
405                 if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
406                         NyLPC_OnErrorGoto(ERROR2);\r
407                 }\r
408                 //全デバイスの送信\r
409                 for(i=0;i<sock->number_of_device;i++){\r
410                         tx=allocMsearchResponeTx(\r
411                                 sock,header.result.st_str,\r
412                                 sock->ref_device_record[i]->udn,sock->ref_device_record[i]->device_type,\r
413                                 header.result.st_len,\r
414                                 &tx_len);\r
415                         if(tx==NULL){\r
416                                 NyLPC_OnErrorGoto(ERROR1);\r
417                         }\r
418                         if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
419                                 NyLPC_OnErrorGoto(ERROR2);\r
420                         }\r
421                         for(i2=0;i2<sock->ref_device_record[i]->number_of_service;i2++){\r
422                                 //serviceに一致\r
423                                 tx=allocMsearchResponeTx(\r
424                                         sock,header.result.st_str,\r
425                                         sock->ref_device_record[i]->udn,sock->ref_device_record[i]->services[i2].service_type,\r
426                                         header.result.st_len,\r
427                                         &tx_len);\r
428                                 if(tx==NULL){\r
429                                         NyLPC_OnErrorGoto(ERROR1);\r
430                                 }\r
431                                 if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
432                                         NyLPC_OnErrorGoto(ERROR2);\r
433                                 }\r
434                         }\r
435                 }\r
436         }else if(strncmp("uuid:",header.result.st_str,5)==0){\r
437                 //UDNの一致するデバイスの送信\r
438                 NyLPC_TInt16 i;\r
439                 for(i=sock->number_of_device-1;i>=0;i--){\r
440                         if(strncmp(header.result.st_str,sock->ref_device_record[i]->udn,header.result.st_len)==0){\r
441                                 //UDN一致\r
442                                 tx=allocMsearchResponeTx(\r
443                                         sock,header.result.st_str,\r
444                                         sock->ref_device_record[i]->udn,NULL,\r
445                                         header.result.st_len,\r
446                                         &tx_len);\r
447                                 if(tx==NULL){\r
448                                         NyLPC_OnErrorGoto(ERROR1);\r
449                                 }\r
450                                 if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
451                                         NyLPC_OnErrorGoto(ERROR2);\r
452                                 }\r
453                                 break;//送信処理終了\r
454                         }\r
455                 }\r
456         }else if(strncmp(STR_UPNP_ROOT_DEVICE,header.result.st_str,15)==0){\r
457                 //rootDeviceはdevice0\r
458                 tx=allocMsearchResponeTx(\r
459                         sock,header.result.st_str,\r
460                         sock->ref_device_record[0]->udn,sock->ref_device_record[0]->device_type,\r
461                         header.result.st_len,\r
462                         &tx_len);\r
463                 if(tx==NULL){\r
464                         NyLPC_OnErrorGoto(ERROR1);\r
465                 }\r
466                 if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
467                         NyLPC_OnErrorGoto(ERROR2);\r
468                 }\r
469         }else if(strncmp("urn:",header.result.st_str,4)==0){\r
470                 for(i=0;i<sock->number_of_device;i++){\r
471                         //urn一致チェック\r
472                         if(strncmp(sock->ref_device_record[i]->device_type,header.result.st_str,header.result.st_len)==0){\r
473                                 //deviceに一致\r
474                                 tx=allocMsearchResponeTx(\r
475                                         sock,header.result.st_str,\r
476                                         sock->ref_device_record[i]->udn,sock->ref_device_record[i]->device_type,\r
477                                         header.result.st_len,\r
478                                         &tx_len);\r
479                                 if(tx==NULL){\r
480                                         NyLPC_OnErrorGoto(ERROR1);\r
481                                 }\r
482                                 if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
483                                         NyLPC_OnErrorGoto(ERROR2);\r
484                                 }\r
485                                 continue;\r
486                         }\r
487                         for(i2=0;i2<sock->ref_device_record[i]->number_of_service;i2++){\r
488                                 if(strncmp(sock->ref_device_record[i]->services[i2].service_type,header.result.st_str,header.result.st_len)==0){\r
489                                         //serviceに一致\r
490                                         tx=allocMsearchResponeTx(\r
491                                                 sock,header.result.st_str,\r
492                                                 sock->ref_device_record[i]->udn,sock->ref_device_record[i]->services[i2].service_type,\r
493                                                 header.result.st_len,\r
494                                                 &tx_len);\r
495                                         if(tx==NULL){\r
496                                                 NyLPC_OnErrorGoto(ERROR1);\r
497                                         }\r
498                                         if(!NyLPC_cUdpSocket_psend(i_inst,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){\r
499                                                 NyLPC_OnErrorGoto(ERROR2);\r
500                                         }\r
501                                 }\r
502                         }\r
503                 }\r
504         }\r
505         //正常終了\r
506         return NyLPC_TBool_FALSE;\r
507 ERROR2:\r
508         NyLPC_cUdpSocket_releaseSendBuf(i_inst,tx);\r
509 ERROR1:\r
510         return NyLPC_TBool_FALSE;\r
511 }\r
512 \r
513 #define SSDP_NOTIFY_INTERVAL 240*1000   //300*0.8*1000\r
514 #define FLAG_ORDER_START_SERVICE        0\r
515 #define FLAG_ORDER_STOP_SERVICE         1\r
516 #define FLAG_IS_SERVICE_RUNNING         2\r
517 \r
518 static void onPeriodic(NyLPC_TcUdpSocket_t* i_inst)\r
519 {\r
520         NyLPC_TcSsdpSocket_t* sock=(NyLPC_TcSsdpSocket_t*)i_inst;\r
521         if(NyLPC_TUInt8_isBitOn(sock->_flags,FLAG_IS_SERVICE_RUNNING)){\r
522         //実行中\r
523                 //停止要求着てる?\r
524                 if(NyLPC_TUInt8_isBitOn(sock->_flags,FLAG_ORDER_STOP_SERVICE))\r
525                 {\r
526                         //状態変更\r
527                         NyLPC_TUInt8_unsetBit(sock->_flags,FLAG_IS_SERVICE_RUNNING);\r
528                         //要求フラグクリア\r
529                         NyLPC_TUInt8_unsetBit(sock->_flags,FLAG_ORDER_STOP_SERVICE);\r
530                         //@bug ByeBye送信しろ\r
531                 }else if(NyLPC_cStopwatch_isExpired(&sock->_periodic_sw)){\r
532                         //Notify送信\r
533                         NyLPC_cSsdpSocket_notify(sock);\r
534                         //タイマ再始動\r
535                         NyLPC_cStopwatch_startExpire(&sock->_periodic_sw,SSDP_NOTIFY_INTERVAL);\r
536                 }\r
537         }else{\r
538         //停止中\r
539                 //開始要求着てる?\r
540                 if(NyLPC_TUInt8_isBitOn(sock->_flags,FLAG_ORDER_START_SERVICE))\r
541                 {\r
542                         //状態変更\r
543                         NyLPC_TUInt8_setBit(sock->_flags,FLAG_IS_SERVICE_RUNNING);\r
544                         //要求フラグクリア\r
545                         NyLPC_TUInt8_unsetBit(sock->_flags,FLAG_ORDER_START_SERVICE);\r
546                         //次回expireするように\r
547                         NyLPC_cStopwatch_startExpire(&sock->_periodic_sw,SSDP_NOTIFY_INTERVAL);\r
548                 }\r
549         }\r
550 }\r
551 \r
552 /**\r
553  * デバイスツリーを展開する。\r
554  */\r
555 static void expandDeviceTree(NyLPC_TcSsdpSocket_t* i_inst,const struct NyLPC_TUPnPDevDescDevice* i_dev)\r
556 {\r
557         NyLPC_TUInt16 i;\r
558         if(i_inst->number_of_device>=NyLPC_TcSsdpSocket_MAX_DEVICES){\r
559                 NyLPC_Warning();//\r
560         }\r
561         i_inst->ref_device_record[i_inst->number_of_device]=i_dev;\r
562         i_inst->number_of_device++;\r
563         for(i=0;i<i_dev->number_of_devices;i++){\r
564                 expandDeviceTree(i_inst,i_dev->devices[i]);\r
565         }\r
566         return;\r
567 }\r
568 \r
569 void NyLPC_cSsdpSocket_initialize(\r
570                 NyLPC_TcSsdpSocket_t* i_inst,\r
571                 const struct NyLPC_TUPnPDevDescDevice* i_ref_dev_record,\r
572                 NyLPC_TUInt16 i_server_port,const NyLPC_TChar* i_ref_location_path)\r
573 {\r
574         NyLPC_cUdpSocket_initialize(&(i_inst->super),1900,NULL,0);\r
575         NyLPC_cUdpSocket_setOnRxHandler(&(i_inst->super),onPacket);\r
576         NyLPC_cUdpSocket_setOnPeriodicHandler(&(i_inst->super),onPeriodic);\r
577 \r
578         NyLPC_cUdpSocket_joinMulticast(&(i_inst->super),&SSDP_MCAST_IPADDR);\r
579         i_inst->_flags=0;\r
580         NyLPC_cStopwatch_initialize(&(i_inst->_periodic_sw));\r
581         i_inst->number_of_device=0;\r
582         expandDeviceTree(i_inst,i_ref_dev_record);\r
583         i_inst->location_port=i_server_port;\r
584         i_inst->location_path=i_ref_location_path;\r
585 }\r
586 void NyLPC_cSsdpSocket_finalize(NyLPC_TcSsdpSocket_t* i_inst)\r
587 {\r
588         NyLPC_cStopwatch_finalize(&(i_inst->_periodic_sw));\r
589         NyLPC_cUdpSocket_finalize(&(i_inst->super));\r
590 }\r
591 \r
592 void NyLPC_cSsdpSocket_start(NyLPC_TcSsdpSocket_t* i_inst)\r
593 {\r
594         //Notifyを3回送信\r
595         NyLPC_TInt16 i;\r
596         NyLPC_cSsdpSocket_notify(i_inst);\r
597         for(i=0;i<2;i++){\r
598                 NyLPC_cThread_sleep(800);\r
599                 NyLPC_cSsdpSocket_notify(i_inst);\r
600         }\r
601 \r
602         //ストップウォッチの開始要求\r
603         NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_START_SERVICE);\r
604         do{\r
605                 NyLPC_cThread_sleep(10);\r
606                 //開始フラグがクリアされるまでループ\r
607         }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_START_SERVICE));\r
608 }\r
609 void NyLPC_cSsdpSocket_stop(NyLPC_TcSsdpSocket_t* i_inst)\r
610 {\r
611         //今は使えない。\r
612         NyLPC_Abort();\r
613         NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_STOP_SERVICE);\r
614         do{\r
615                 NyLPC_cThread_sleep(10);\r
616                 //開始フラグがクリアされるまでループ\r
617         }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_STOP_SERVICE));\r
618 }\r
619 void NyLPC_cSsdpSocket_notify(NyLPC_TcSsdpSocket_t* i_inst)\r
620 {\r
621         void* tx;\r
622         NyLPC_TInt16 tx_len;\r
623         NyLPC_TUInt8 i,i2;\r
624         //rootdevice\r
625         tx=allocNotifyTx(\r
626                 i_inst,\r
627                 i_inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,\r
628                 &tx_len);\r
629         if(tx==NULL){\r
630                 NyLPC_OnErrorGoto(ERROR1);\r
631         }\r
632         if(!NyLPC_cUdpSocket_psend(&i_inst->super,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
633                 NyLPC_OnErrorGoto(ERROR2);\r
634         }\r
635         //all device\r
636         for(i=0;i<i_inst->number_of_device;i++){\r
637                 //uuid\r
638                 tx=allocNotifyTx(\r
639                         i_inst,\r
640                         i_inst->ref_device_record[i]->udn,NULL,\r
641                         &tx_len);\r
642                 if(tx==NULL){\r
643                         NyLPC_OnErrorGoto(ERROR1);\r
644                 }\r
645                 if(!NyLPC_cUdpSocket_psend(&i_inst->super,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
646                         NyLPC_OnErrorGoto(ERROR2);\r
647                 }\r
648                 //devicatype\r
649                 tx=allocNotifyTx(\r
650                         i_inst,\r
651                         i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->device_type,\r
652                         &tx_len);\r
653                 if(tx==NULL){\r
654                         NyLPC_OnErrorGoto(ERROR1);\r
655                 }\r
656                 if(!NyLPC_cUdpSocket_psend(&i_inst->super,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
657                         NyLPC_OnErrorGoto(ERROR2);\r
658                 }\r
659                 for(i2=0;i2<i_inst->ref_device_record[i]->number_of_service;i2++){\r
660                         tx=allocNotifyTx(\r
661                                 i_inst,\r
662                                 i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->services[i2].service_type,\r
663                                 &tx_len);\r
664                         if(tx==NULL){\r
665                                 NyLPC_OnErrorGoto(ERROR1);\r
666                         }\r
667                         if(!NyLPC_cUdpSocket_psend(&i_inst->super,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){\r
668                                 NyLPC_OnErrorGoto(ERROR2);\r
669                         }\r
670                 }\r
671         }\r
672         return;\r
673 ERROR2:\r
674         NyLPC_cUdpSocket_releaseSendBuf(&i_inst->super,tx);\r
675 ERROR1:\r
676         return;\r
677 }\r
678 \r