OSDN Git Service

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