OSDN Git Service

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