OSDN Git Service

backup
[mimic/MiMicSDK.git] / projects / example / sample.net.simplehttpd / src / sketch.c
1 /**\r
2  * httpdサーバのサンプルです。\r
3  * ROMにある定義済みファイルの入出力と、クロスドメインRESTが確認できます。\r
4  */\r
5 #include "boot/sketch.h"\r
6 #include "NyLPC_uipService.h"\r
7 #include "NyLPC_httpService.h"\r
8 #include "NyLPC_utils.h"\r
9 #include <stdio.h>\r
10 \r
11 #include "../api/NyLPC_cNet.h"\r
12 #include "../api/NyLPC_cHttpd.h"\r
13 #include "../api/NyLPC_cModShortUrl.h"\r
14 \r
15 NyLPC_TcNet_t net;\r
16 struct MyHttpd{\r
17         NyLPC_TcHttpd_t super;\r
18 }httpd;\r
19 \r
20 NyLPC_TcModShortUrl_t mod_surl;\r
21 \r
22 void handler(NyLPC_TcHttpdConnection_t* i_connection)\r
23 {\r
24         NyLPC_THttpMethodType m;\r
25         NyLPC_cModShortUrl_parse(&mod_surl,i_connection);\r
26         m=NyLPC_cModShortUrl_getMethod(&mod_surl);\r
27         if(m!=NyLPC_THttpMethodType_HEAD || m!=NyLPC_THttpMethodType_GET){\r
28                 NyLPC_cHttpdConnection_sendResponseHeader(i_connection,200,"text/html",NULL);\r
29         }\r
30         if(m==NyLPC_THttpMethodType_GET){\r
31                 NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"<html><body>");\r
32                 NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"your request is %s",NyLPC_cModShortUrl_getPath(&mod_surl));\r
33 \r
34                 NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"</body></html>");\r
35         }\r
36         return;\r
37 }\r
38 void setup(void)\r
39 {\r
40         //uipサービス初期化。いろいろ利用可能に。\r
41         NyLPC_cNet_initialize(&net);\r
42         NyLPC_cHttpd_initialize(&httpd.super,80);\r
43         httpd.super.function._handler=handler;\r
44         NyLPC_cModShortUrl_initialize(&mod_surl);\r
45 }\r
46 \r
47 \r
48 void loop(void)\r
49 {\r
50         NyLPC_TcNetConfig_t c2;\r
51         NyLPC_cNetConfig_initialize(&c2);\r
52         NyLPC_cNet_start(&net,&c2);\r
53         NyLPC_cHttpd_loop(&httpd.super);\r
54         for(;;);\r
55 }\r
56 \r
57 \r
58 #ifdef COMMENT\r
59 \r
60 \r
61 //イーサネット用の初期化情報\r
62 const struct NyLPC_TEthAddr ethaddr=NyLPC_TEthAddr_pack(0x02,0x01,0x02,0x03,0x04,0x05);\r
63 const struct NyLPC_TIPv4Addr ipaddr=NyLPC_TIPv4Addr_pack(192,168,0,39);\r
64 const struct NyLPC_TIPv4Addr netmask=NyLPC_TIPv4Addr_pack(255,255,255,0);\r
65 const struct NyLPC_TIPv4Addr gateway=NyLPC_TIPv4Addr_pack(192,168,0,254);\r
66 \r
67 //TCP処理スレッドの定義\r
68 #define SIZE_OF_RX 256\r
69 #define NUM_OF_TH 7\r
70 struct TProc{\r
71         NyLPC_TcThread_t th;\r
72         NyLPC_TcTcpSocket_t socket;\r
73         char rbuf[SIZE_OF_RX];\r
74 }proc[NUM_OF_TH];\r
75 \r
76 //ROMFSの定義\r
77 extern struct NyLPC_TRomFileData file_cat_jpg;\r
78 extern struct NyLPC_TRomFileData file_index_html;\r
79 NyLPC_TcRomFileSet_t rfs;\r
80 const struct NyLPC_TRomFileData* rfsd[]={\r
81                 &file_index_html,\r
82                 &file_cat_jpg};\r
83 \r
84 //private 関数\r
85 \r
86 static NyLPC_TUInt16 parseReqHeader(NyLPC_TcHttpStream_t* i_st,struct NyLPC_THttpShortRequestHeader* o_reqh);\r
87 static NyLPC_TBool writeError(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh,NyLPC_TUInt16 i_status);\r
88 static NyLPC_TBool writeFile(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh,const struct NyLPC_TRomFileData* i_file);\r
89 static NyLPC_TBool writeJson(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh);\r
90 \r
91 \r
92 //スケッチ\r
93 \r
94 void setup(void)\r
95 {\r
96         int i;\r
97         //uipサービス初期化。いろいろ利用可能に。\r
98         NyLPC_cUipService_initialize();\r
99 //      for(i=0;i<NUM_OF_TH;i++){\r
100 //              NyLPC_cThread_initialize(&(proc[i].th),200,NyLPC_TcThread_PRIORITY_IDLE);\r
101 //              NyLPC_cTcpSocket_initialize(&(proc[i].socket),proc[i].rbuf,SIZE_OF_RX);\r
102 //      }\r
103 //      //ROMのファイルシステムを初期化\r
104 //      NyLPC_cRomFileSet_initialize(&rfs,rfsd,2);\r
105 \r
106 }\r
107 \r
108 //ステータス用。\r
109 static int num_of_reqest=0;\r
110 static int num_of_error=0;\r
111 static int num_of_connect=0;\r
112 static int num_of_tx=0;\r
113 \r
114 //Httpのセッション関数\r
115 static int server(void* p)\r
116 {\r
117         struct TProc* proc=(struct TProc*)p;\r
118         NyLPC_TUInt16 ret;\r
119         const struct NyLPC_TRomFileData* rf;\r
120         NyLPC_TcHttpStream_t st;\r
121         struct NyLPC_THttpShortRequestHeader reqheader;\r
122         if(!NyLPC_cTcpSocket_accept(&(proc->socket),3000)){\r
123                 return -1;\r
124         }\r
125         num_of_connect++;\r
126 \r
127         //TCPのオープン\r
128         if(NyLPC_cHttpStream_initialize(&st,&(proc->socket))){\r
129                 for(;;){\r
130                         ret=parseReqHeader(&st,&reqheader);\r
131                         num_of_reqest++;\r
132                         //コネクションが増えすぎたら持続性接続を停止するために上書き。\r
133                         if(num_of_connect>5){\r
134                                 reqheader.super.connection=NyLPC_THttpMessgeHeader_Connection_CLOSE;\r
135                         }\r
136                         if(ret!=200){\r
137                                 //エラーならエラーレスポンスを生成。持続性接続しない。\r
138                                 writeError(&st,&(reqheader.super),ret);\r
139                                 num_of_error++;\r
140                                 break;\r
141                         }\r
142                         //URLから判定。\r
143                         if(strncmp("/rf.api?",reqheader.url,8)==0){\r
144                                 //ファイル検索\r
145                                 rf=NyLPC_cRomFileSet_getFilaData(&rfs,reqheader.url+8);\r
146                                 if(rf==NULL){\r
147                                         num_of_error++;\r
148                                         if(!writeError(&st,&(reqheader.super),404)){\r
149                                                 break;\r
150                                         }\r
151                                 }else{\r
152                                         if(!writeFile(&st,&(reqheader.super),rf)){\r
153                                                 num_of_error++;\r
154                                                 break;\r
155                                         }\r
156                                 }\r
157                         }else if(strncmp("/status.json",reqheader.url,8)==0){\r
158                                 if(!writeJson(&st,&(reqheader.super))){\r
159                                         break;\r
160                                 }\r
161                                 //httpdの状態を返す。\r
162                         }else{\r
163                                 if(!writeFile(&st,&(reqheader.super),NyLPC_cRomFileSet_getFilaData(&rfs,"index.html"))){\r
164                                         num_of_error++;\r
165                                         break;\r
166                                 }\r
167                         }\r
168 \r
169                 }\r
170                 NyLPC_cHttpStream_finalize(&st);\r
171         }\r
172         //5秒以内に切断\r
173         NyLPC_cTcpSocket_close(&(proc->socket),5000);\r
174         num_of_connect--;\r
175         return 0;\r
176 }\r
177 \r
178 \r
179 void loop(void)\r
180 {\r
181         NyLPC_TcIPv4Config_t config;\r
182         NyLPC_TcTcpListener_t listener;\r
183         int i;\r
184 \r
185 \r
186         NyLPC_cIPv4Config_initialzeForEthernet(&config,&ethaddr,1480);\r
187         NyLPC_cIPv4Config_setDefaultRoute(&config,&gateway);\r
188         NyLPC_cIPv4Config_setIp(&config,&ipaddr,&netmask);\r
189 \r
190 \r
191 //      NyLPC_cTcpListener_initialize(&listener,80);\r
192         NyLPC_cUipService_start(&config);\r
193 /*      for(;;){\r
194                 //ターミネイト状態のタスクを検索\r
195                 for(i=0;i<NUM_OF_TH;i++){\r
196                         if(NyLPC_cThread_isTerminated(&(proc[i].th))){\r
197                                 //リスニング\r
198                                 if(!NyLPC_cTcpListener_listen(&listener,&(proc[i].socket),5000)){\r
199                                         continue;\r
200                                 }\r
201                                 //タスク起動\r
202                                 NyLPC_cThread_start(&(proc[i].th),server,&(proc[i]));\r
203                         }\r
204                 }\r
205         }*/\r
206         for(;;){}\r
207 }\r
208 \r
209 \r
210 \r
211 /**\r
212  * リクエストヘッダのパーサ\r
213  */\r
214 static NyLPC_TUInt16 parseReqHeader(NyLPC_TcHttpStream_t* i_st,struct NyLPC_THttpShortRequestHeader* o_reqh)\r
215 {\r
216         NyLPC_TUInt16 ret=200;\r
217         NyLPC_TcHttpShortRequestHeaderParser_t hp;\r
218         NyLPC_cHttpShortRequestHeaderParser_initialize(&hp);\r
219 \r
220         //ヘッダ解析\r
221         if(!NyLPC_cHttpShortRequestHeaderParser_parse(&hp,i_st,o_reqh)){\r
222                 ret=NyLPC_cHttpBasicHeaderParser_getStatusCode(&hp.super);\r
223         }\r
224         //ヘッダの内容確認\r
225         if(o_reqh->super.type!=NyLPC_THttpHeaderType_REQUEST){\r
226                 ret=400;\r
227         }\r
228         //GETだけネ\r
229         if(o_reqh->super.startline.req.method!=NyLPC_THttpMethodType_GET){\r
230                 ret=405;\r
231         }\r
232         NyLPC_cHttpBasicHeaderParser_finalize(&hp);\r
233         return ret;\r
234 }\r
235 /**\r
236  * エラーレスポンスのライタ。\r
237  * 戻り値はpersistentConnectionが有効かどうか。\r
238  */\r
239 static NyLPC_TBool writeError(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh,NyLPC_TUInt16 i_status)\r
240 {\r
241         static const char* HTML_FORMAT="<html><h1>STATUS %d</h1><hr/>"NyLPC_cHttpdConfig_SERVER"</html>";\r
242         NyLPC_TcHttpHeaderWriter_t hw;\r
243         NyLPC_TcHttpBodyWriter_t bw;\r
244         //ヘッダライタの生成\r
245         if(!NyLPC_cHttpHeaderWriter_initialize(&hw,i_st,i_rqh)){\r
246                 return NyLPC_TBool_FALSE;\r
247         }\r
248         //ヘッダ書込み\r
249         if(!NyLPC_THttpBasicHeader_isPersistent(i_rqh)){\r
250                 NyLPC_cHttpHeaderWriter_setClose(&hw);\r
251         }\r
252         //@bug HTTP/1.1未満のクライアントを考慮していない。\r
253         NyLPC_cHttpHeaderWriter_setChunked(&hw);\r
254         //ヘッダの基本情報出力\r
255         NyLPC_cHttpHeaderWriter_writeHeader(&hw,i_status);\r
256         //拡張メッセージヘッダの出力\r
257         NyLPC_cHttpHeaderWriter_writeMessage(&hw,"Content-type","text/html");\r
258 \r
259         //ヘッダ書込み終わり。(最後だけチェック)\r
260         if(!NyLPC_cHttpHeaderWriter_close(&hw)){\r
261                 NyLPC_cHttpHeaderWriter_finalize(&hw);\r
262                 return NyLPC_TBool_FALSE;\r
263         }\r
264         NyLPC_cHttpHeaderWriter_finalize(&hw);\r
265 \r
266         //Bodyの書込み\r
267         NyLPC_cHttpBodyWriter_initialize(&bw,i_st);\r
268         //チャンク転送設定\r
269         NyLPC_cHttpBodyWriter_setChunked(&bw);\r
270         NyLPC_cHttpBodyWriter_format(&bw,HTML_FORMAT,(NyLPC_TInt32)i_status);\r
271         //エラーチェック\r
272         if(!NyLPC_cHttpBodyWriter_close(&bw)){\r
273                 NyLPC_cHttpBodyWriter_finalize(&hw);\r
274                 return NyLPC_TBool_FALSE;\r
275         }\r
276         NyLPC_cHttpBodyWriter_finalize(&hw);\r
277         return NyLPC_THttpBasicHeader_isPersistent(i_rqh);\r
278 }\r
279 \r
280 /**\r
281  * エラーレスポンスのライタ。\r
282  * 戻り値はpersistentConnectionが有効かどうか。\r
283  */\r
284 static NyLPC_TBool writeJson(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh)\r
285 {\r
286         static const char* JSON_FORMAT="{nr:%d,ne:%d,ac:%d,er:\"%d/%d/%d\",tx:%d}";\r
287         NyLPC_TcHttpHeaderWriter_t hw;\r
288         NyLPC_TcHttpBodyWriter_t bw;\r
289         //ヘッダライタの生成\r
290         if(!NyLPC_cHttpHeaderWriter_initialize(&hw,i_st,i_rqh)){\r
291                 return NyLPC_TBool_FALSE;\r
292         }\r
293         //ヘッダ書込み\r
294         if(!NyLPC_THttpBasicHeader_isPersistent(i_rqh)){\r
295                 NyLPC_cHttpHeaderWriter_setClose(&hw);\r
296         }\r
297         //@bug HTTP/1.1未満のクライアントを考慮していない。\r
298         NyLPC_cHttpHeaderWriter_setChunked(&hw);\r
299         //ヘッダの基本情報出力\r
300         NyLPC_cHttpHeaderWriter_writeHeader(&hw,200);\r
301         //拡張メッセージヘッダの出力\r
302         NyLPC_cHttpHeaderWriter_writeMessage(&hw,"Content-type","application/json");\r
303         NyLPC_cHttpHeaderWriter_writeMessage(&hw,"Access-Control-Allow-Origin","*");\r
304 \r
305         //ヘッダ書込み終わり。(最後だけチェック)\r
306         if(!NyLPC_cHttpHeaderWriter_close(&hw)){\r
307                 NyLPC_cHttpHeaderWriter_finalize(&hw);\r
308                 return NyLPC_TBool_FALSE;\r
309         }\r
310         NyLPC_cHttpHeaderWriter_finalize(&hw);\r
311 \r
312         //Bodyの書込み\r
313         NyLPC_cHttpBodyWriter_initialize(&bw,i_st);\r
314         //チャンク転送設定\r
315         NyLPC_cHttpBodyWriter_setChunked(&bw);\r
316         NyLPC_cHttpBodyWriter_format(&bw,JSON_FORMAT,\r
317                 (NyLPC_TInt32)num_of_reqest,(NyLPC_TInt32)num_of_error,(NyLPC_TInt32)num_of_connect,\r
318                 NyLPC_assert_counter,NyLPC_abort_counter,NyLPC_debug_counter,dbg_getNumofUsedTx());\r
319         //エラーチェック\r
320         if(!NyLPC_cHttpBodyWriter_close(&bw)){\r
321                 NyLPC_cHttpBodyWriter_finalize(&hw);\r
322                 return NyLPC_TBool_FALSE;\r
323         }\r
324         NyLPC_cHttpBodyWriter_finalize(&hw);\r
325         return NyLPC_THttpBasicHeader_isPersistent(i_rqh);\r
326 }\r
327 /**\r
328  * ROMファイルのレスポンスライタ。\r
329  * 戻り値はpersistentConnectionが有効かどうか。\r
330  */\r
331 static NyLPC_TBool writeFile(NyLPC_TcHttpStream_t* i_st,const struct NyLPC_THttpBasicHeader* i_rqh,const struct NyLPC_TRomFileData* i_file)\r
332 {\r
333         NyLPC_TcHttpHeaderWriter_t hw;\r
334         NyLPC_TcHttpBodyWriter_t bw;\r
335         //ヘッダライタの生成\r
336         if(!NyLPC_cHttpHeaderWriter_initialize(&hw,i_st,i_rqh)){\r
337                 return NyLPC_TBool_FALSE;\r
338         }\r
339         //ヘッダ書込み\r
340         if(!NyLPC_THttpBasicHeader_isPersistent(i_rqh)){\r
341                 NyLPC_cHttpHeaderWriter_setClose(&hw);\r
342         }\r
343         NyLPC_cHttpHeaderWriter_setContentLength(&hw,i_file->size);\r
344         //ヘッダの基本情報出力\r
345         NyLPC_cHttpHeaderWriter_writeHeader(&hw,200);\r
346         //拡張メッセージヘッダの出力\r
347         NyLPC_cHttpHeaderWriter_writeMessage(&hw,"Content-type",i_file->content_type);\r
348 \r
349         //ヘッダ書込み終わり。(最後だけチェック)\r
350         if(!NyLPC_cHttpHeaderWriter_close(&hw)){\r
351                 NyLPC_cHttpHeaderWriter_finalize(&hw);\r
352                 return NyLPC_TBool_FALSE;\r
353         }\r
354         NyLPC_cHttpHeaderWriter_finalize(&hw);\r
355 \r
356         //Bodyの書込み\r
357         NyLPC_cHttpBodyWriter_initialize(&bw,i_st);\r
358         NyLPC_cHttpBodyWriter_write(&bw,i_file->data,i_file->size);\r
359         //エラーチェック\r
360         if(!NyLPC_cHttpBodyWriter_close(&bw)){\r
361                 NyLPC_cHttpBodyWriter_finalize(&hw);\r
362                 return NyLPC_TBool_FALSE;\r
363         }\r
364         NyLPC_cHttpBodyWriter_finalize(&hw);\r
365         return NyLPC_THttpBasicHeader_isPersistent(i_rqh);\r
366 }\r
367 #endif\r