1 /*********************************************************************************
\r
3 * --------------------------------------------------------------------------------
\r
5 * This file is part of MiMic
\r
6 * Copyright (C)2011 Ryo Iizuka
\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
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
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
21 * For further information please contact.
\r
23 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
\r
25 *********************************************************************************/
\r
26 #include "NyLPC_cModRemoteMcu.h"
\r
27 #include "NyLPC_stdlib.h"
\r
28 #include "NyLPC_http.h"
\r
29 #include "NyLPC_mimicVm.h"
\r
30 #include "../NyLPC_cHttpdConnection_protected.h"
\r
31 #include "../NyLPC_cHttpdUtils.h"
\r
32 #include "NyLPC_net.h"
\r
34 #define MVM_VERSION "ModRemoteMcu/1.0;Json/1.0"
\r
35 #define SIZE_OF_IBUF 256
\r
36 struct TModMiMicRemoteMcuHeader
\r
38 struct NyLPC_THttpBasicHeader super;
\r
39 NyLPC_TUInt8 _content_id;
\r
41 NyLPC_TUInt8 _qery_name_id;
\r
42 NyLPC_TUInt8 _astate;
\r
43 NyLPC_TInt16 _prefix_len;
\r
44 NyLPC_TcStr_t _tstr;
\r
45 NyLPC_TChar _tstr_buf[16];
\r
46 struct NyLPC_TUInt32ArrayPtr _binarray;
\r
48 NyLPC_TcMiMicDbCompiler_t _binparser;
\r
49 NyLPC_TcMiMicTxtCompiler_t _txtcmp;
\r
52 NyLPC_TUInt8 v;//バージョン
\r
53 NyLPC_TUInt8 o;//outputスタイル
\r
55 * il_bufはbcとdbの2パートのデータを格納します。
\r
56 * 先頭からbc_lenの長さのBCパートと、db_partからdb_lenの長さのデータです。
\r
59 /** MiMicVMインストラクションの蓄積用。前半にTXT,後半にDBを格納する。 */
\r
60 NyLPC_TUInt32 bc_buf[SIZE_OF_IBUF];
\r
61 /** MiMicVM入力ストリーム(MimicDB)の開始位置(bufの一部を指す) */
\r
62 const NyLPC_TUInt32* db_part;
\r
63 /** MiMicTXTのワード長(1ワード32bit)*/
\r
64 NyLPC_TUInt16 txt_len;
\r
65 /** MiMicDBのワード長(1ワード32bit)*/
\r
66 NyLPC_TUInt16 db_len;
\r
71 * 不明な名前の場合は、ここに名前をコピー
\r
73 NyLPC_TChar path[32];
\r
79 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh);
\r
80 static void status(NyLPC_TcHttpdConnection_t* i_connection);
\r
85 #define ST_PARSE_PATH 1
\r
86 #define ST_PARSE_QUERY_NAME 2
\r
87 #define ST_PARSE_QUERY_VALUE 3 //Query読み出し中
\r
88 #define ST_PARSE_QUERY_VALUE_V 4
\r
89 #define ST_PARSE_QUERY_VALUE_O 5
\r
90 #define ST_PARSE_QUERY_VALUE_BC 6
\r
91 #define ST_PARSE_QUERY_VALUE_DB 7
\r
93 * コンテンツID定義(コンテンツ名に対応)
\r
95 #define CONTENT_ID_MVM 2
\r
96 #define CONTENT_ID_STATUS 3
\r
97 #define CONTENT_ID_UNKNOWN 0
\r
100 #define QNAME_ID_V 1
\r
101 #define QNAME_ID_O 2
\r
102 #define QNAME_ID_BC 3
\r
103 #define QNAME_ID_UNKNOWN 0
\r
106 * TRemoteMcuRequest.content.mvm.oの値
\r
108 #define QVAL_O_UNKNOWN 0 //default
\r
109 #define QVAL_O_XML 1
\r
110 #define QVAL_O_JSON 2
\r
112 #define QVAL_V_UNKNOWN 0
\r
116 static const struct NyLPC_TTextIdTbl url_tbl[]=
\r
118 {"mvm.api",CONTENT_ID_MVM},
\r
119 {"status.api",CONTENT_ID_STATUS},
\r
120 {NULL,CONTENT_ID_UNKNOWN}
\r
123 static const struct NyLPC_TTextIdTbl qname_id_table[]=
\r
126 {"bc",QNAME_ID_BC},
\r
128 {NULL,QNAME_ID_UNKNOWN}
\r
133 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
\r
136 struct TModMiMicRemoteMcuHeader* out=(struct TModMiMicRemoteMcuHeader*)o_out;
\r
138 if(out->_prefix_len<0){
\r
139 out->_prefix_len++;
\r
140 return NyLPC_TBool_TRUE;//読み飛ばし
\r
142 if(out->_astate==ST_PARSE_PATH){
\r
143 if(i_c!='\0' && i_c!='?'){
\r
144 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
146 NyLPC_OnErrorGoto(ERROR);
\r
149 out->_content_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),url_tbl);
\r
150 switch(out->_content_id)
\r
152 case CONTENT_ID_MVM:
\r
153 out->content.mvm.vm_instruction.txt_len=0;
\r
154 out->content.mvm.vm_instruction.db_len=0;
\r
155 out->content.mvm.vm_instruction.db_part=NULL;
\r
156 NyLPC_TUInt32ArrayPtr_setBuf(&out->_binarray,out->content.mvm.vm_instruction.bc_buf,SIZE_OF_IBUF);
\r
157 out->content.mvm.o=QVAL_O_JSON;
\r
158 out->content.mvm.v=QVAL_V_UNKNOWN;
\r
163 NyLPC_cStr_clear(&(out->_tstr));
\r
164 out->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ
\r
166 return NyLPC_TBool_TRUE;
\r
168 switch(out->_content_id)
\r
170 case CONTENT_ID_MVM:
\r
171 switch(out->_astate){
\r
172 case ST_PARSE_QUERY_NAME:
\r
173 if(i_c!='\0' && i_c!='&' && i_c!='='){
\r
174 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
175 NyLPC_OnErrorGoto(ERROR);
\r
179 out->_qery_name_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),qname_id_table);
\r
180 NyLPC_cStr_clear(&(out->_tstr));
\r
182 switch(out->_qery_name_id){
\r
184 out->_astate=ST_PARSE_QUERY_VALUE_O;//MIMICBCのDBパラメータパーサを借用。
\r
187 out->_astate=ST_PARSE_QUERY_VALUE_V;
\r
190 out->_astate=ST_PARSE_QUERY_VALUE_BC;
\r
193 out->_astate=ST_PARSE_QUERY_VALUE;
\r
197 return NyLPC_TBool_TRUE;
\r
198 case ST_PARSE_QUERY_VALUE:
\r
200 if(i_c!='\0' && i_c!='&'){
\r
203 out->_astate=ST_PARSE_QUERY_NAME;
\r
205 return NyLPC_TBool_TRUE;
\r
206 case ST_PARSE_QUERY_VALUE_O:
\r
207 if(i_c!='\0' && i_c!='&'){
\r
208 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
209 NyLPC_OnErrorGoto(ERROR);
\r
212 if(NyLPC_cStr_isEqual(&(out->_tstr),"j")){
\r
213 out->content.mvm.o=QVAL_O_JSON;
\r
214 }else if(NyLPC_cStr_isEqual(&(out->_tstr),"x")){
\r
215 out->content.mvm.o=QVAL_O_XML;
\r
217 out->_astate=ST_PARSE_QUERY_NAME;
\r
218 NyLPC_cStr_clear(&(out->_tstr));
\r
220 return NyLPC_TBool_TRUE;
\r
221 case ST_PARSE_QUERY_VALUE_V:
\r
222 if(i_c!='\0' && i_c!='&'){
\r
223 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
224 NyLPC_OnErrorGoto(ERROR);
\r
227 if(NyLPC_cStr_isEqual(&(out->_tstr),"1")){
\r
228 out->content.mvm.v=QVAL_V_1;
\r
230 out->_astate=ST_PARSE_QUERY_NAME;
\r
231 NyLPC_cStr_clear(&(out->_tstr));
\r
233 return NyLPC_TBool_TRUE;
\r
234 case ST_PARSE_QUERY_VALUE_BC:
\r
235 if(i_c!='\0' && i_c!='&'){
\r
237 switch(NyLPC_cMiMicTxtCompiler_compileFragment2(&(out->_txtcmp),i_c,&(out->_binarray),&ol))
\r
239 case NyLPC_TcMiMicTxtCompiler_RET_OK:
\r
242 case NyLPC_TcMiMicTxtCompiler_RET_OK_END:
\r
244 out->content.mvm.vm_instruction.txt_len=SIZE_OF_IBUF-out->_binarray.len+ol;
\r
245 out->content.mvm.vm_instruction.db_part=out->content.mvm.vm_instruction.bc_buf+out->content.mvm.vm_instruction.txt_len;
\r
246 out->_astate=ST_PARSE_QUERY_VALUE_DB;
\r
248 case NyLPC_TcMiMicTxtCompiler_RET_CONTINUE:
\r
251 case NyLPC_TcMiMicTxtCompiler_RET_NG:
\r
254 NyLPC_OnErrorGoto(ERROR);
\r
257 return NyLPC_TBool_TRUE;
\r
258 // //フラグメント終端が検出できない終了はエラー
\r
259 // NyLPC_OnErrorGoto(ERROR);
\r
260 case ST_PARSE_QUERY_VALUE_DB:
\r
261 if(i_c!='\0' && i_c!='&'){
\r
262 switch(NyLPC_cMiMicDbCompiler_compileFragment2(&(out->_binparser),i_c,out->_binarray.ptr))
\r
264 case NyLPC_TcMiMicDbCompiler_RET_CONTINUE:
\r
266 case NyLPC_TcMiMicDbCompiler_RET_OK:
\r
268 if(!NyLPC_TUInt32ArrayPtr_seek(&(out->_binarray),1)){
\r
270 NyLPC_OnErrorGoto(ERROR);
\r
273 case NyLPC_TcMiMicDbCompiler_RET_ERROR:
\r
276 NyLPC_OnErrorGoto(ERROR);
\r
280 if(NyLPC_cMiMicDbCompiler_hasFragment(&(out->_binparser))){
\r
282 NyLPC_OnErrorGoto(ERROR);
\r
284 out->content.mvm.vm_instruction.db_len=((NyLPC_TUInt8*)(out->_binarray.ptr)-(NyLPC_TUInt8*)(out->content.mvm.vm_instruction.db_part))/sizeof(NyLPC_TUInt32);
\r
287 out->_astate=ST_PARSE_QUERY_NAME;
\r
289 return NyLPC_TBool_TRUE;
\r
293 NyLPC_OnErrorGoto(ERROR);
\r
295 NyLPC_OnErrorGoto(ERROR);
\r
297 return NyLPC_TBool_TRUE;
\r
299 return NyLPC_TBool_FALSE;
\r
304 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=
\r
314 void NyLPC_cModRemoteMcu_initialize(NyLPC_TcModRemoteMcu_t* i_inst,const NyLPC_TChar* i_ref_root_path)
\r
316 NyLPC_cModRomFiles_initialize(&i_inst->super,i_ref_root_path,NULL,0);
\r
318 void NyLPC_cModRemoteMcu_finalize(NyLPC_TcModRemoteMcu_t* i_inst)
\r
320 NyLPC_cModRomFiles_finalize(&i_inst->super);
\r
323 * モジュールがコネクションをハンドリングできるかを返します。
\r
325 NyLPC_TBool NyLPC_cModRemoteMcu_canHandle(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
\r
327 return NyLPC_cModRomFiles_canHandle(&i_inst->super,i_connection);
\r
330 static struct TModMiMicRemoteMcuHeader single_header;
\r
335 NyLPC_TBool NyLPC_cModRemoteMcu_execute(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
\r
337 NyLPC_TcHttpBasicHeaderParser_t parser;
\r
338 NyLPC_TUInt8 method_type;
\r
339 //リクエストParse済へ遷移(この関数の後はModが責任を持ってリクエストを返却)
\r
340 NyLPC_cHttpdConnection_setReqStatusParsed(i_connection);
\r
344 NyLPC_cHttpdConnection_lock(i_connection);
\r
348 single_header._prefix_len=-((NyLPC_TInt16)strlen(i_inst->super._ref_root_path)+2);
\r
349 single_header._astate=ST_PARSE_PATH;
\r
350 NyLPC_cStr_initialize(&single_header._tstr,single_header._tstr_buf,16);
\r
351 NyLPC_cMiMicDbCompiler_initialize(&single_header._binparser);
\r
352 NyLPC_cMiMicTxtCompiler_initialize(&single_header._txtcmp);
\r
354 NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);
\r
358 NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(single_header.super));
\r
359 NyLPC_cHttpdConnection_pushPrefetchInfo(i_connection,&parser,&single_header.super);
\r
361 if(!NyLPC_cHttpBasicHeaderParser_parseStream(&parser,NyLPC_cHttpdConnection_refStream(i_connection),&(single_header.super))){
\r
362 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500);
\r
363 NyLPC_OnErrorGoto(Error1);
\r
365 if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(single_header.super))){
\r
366 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500);
\r
367 NyLPC_OnErrorGoto(Error1);
\r
370 method_type=NyLPC_cHttpdConnection_getMethod(i_connection);
\r
371 if(method_type!=NyLPC_THttpMethodType_GET && method_type!=NyLPC_THttpMethodType_HEAD)
\r
373 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,405);
\r
374 NyLPC_OnErrorGoto(Error1);
\r
376 //Request::ConnectionがClose設定,又はHTTP1.1では無い場合,CLOSE
\r
377 if(single_header.super.connection==NyLPC_THttpMessgeHeader_Connection_CLOSE || single_header.super.startline.req.version!=NyLPC_THttpVersion_11)
\r
379 NyLPC_cHttpdConnection_setConnectionMode(i_connection,NyLPC_TcHttpdConnection_CONNECTION_MODE_CLOSE);
\r
382 switch(single_header._content_id)
\r
384 case CONTENT_ID_MVM:
\r
385 mvm(i_connection,&single_header);
\r
387 case CONTENT_ID_STATUS:
\r
388 status(i_connection);
\r
391 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,400);
\r
392 NyLPC_OnErrorGoto(Error1);
\r
394 NyLPC_cStr_finalize(&single_header._tstr);
\r
395 NyLPC_cMiMicDbCompiler_finalize(&single_header._binparser);
\r
396 NyLPC_cMiMicTxtCompiler_finalize(&single_header._txtcmp);
\r
397 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
399 NyLPC_cHttpdConnection_unlock(i_connection);
\r
400 return NyLPC_TBool_TRUE;
\r
402 NyLPC_cStr_finalize(&single_header._tstr);
\r
403 NyLPC_cMiMicDbCompiler_finalize(&single_header._binparser);
\r
404 NyLPC_cMiMicTxtCompiler_finalize(&single_header._txtcmp);
\r
405 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
407 NyLPC_cHttpdConnection_unlock(i_connection);
\r
408 return NyLPC_TBool_FALSE;
\r
415 struct TVmEventHandler
\r
417 struct NyLPC_TcMiMicVM_TEvent super;
\r
418 const struct TModMiMicRemoteMcuHeader* req;
\r
419 NyLPC_TcHttpdConnection_t* connection;
\r
420 NyLPC_TUInt16 db_pos;
\r
421 /** ストリームへ出力したデータの数*/
\r
422 NyLPC_TUInt16 st_len;
\r
423 /** Bodyを送信するかのフラグ*/
\r
424 NyLPC_TBool is_send_body;
\r
430 static NyLPC_TBool mvmputs_json(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_val)
\r
432 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
433 if(eh->is_send_body){
\r
436 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,",%u",i_val);
\r
439 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,"%u",i_val);
\r
442 return NyLPC_TBool_TRUE;
\r
448 static NyLPC_TBool mvmgets(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32* o_val)
\r
450 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
452 if(eh->req->content.mvm.vm_instruction.db_len<=eh->db_pos){
\r
454 return NyLPC_TBool_FALSE;
\r
456 *o_val=eh->req->content.mvm.vm_instruction.db_part[eh->db_pos];
\r
458 return NyLPC_TBool_TRUE;
\r
463 static NyLPC_TUInt32 nativeCall(struct NyLPC_TcMiMicVM_TEvent* i_evh,NyLPC_TUInt32 i_id,NyLPC_TcMiMicVM_t* i_vm)
\r
466 // NyLPC_TNativeFunction f=getNativeFunctionById(i_id);
\r
468 // return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_UNKNOWN_CALL;
\r
470 // return f(i_vm)?NyLPC_cMiMicVM_RESULT_OK:NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
471 return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
475 static void mvmsleep(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_sleep_in_msec)
\r
478 NyLPC_cThread_sleep(i_sleep_in_msec);
\r
482 * RemoteMCUのステータスを返す。基本的にjson
\r
484 * application:"[VERSION]"
\r
487 static void status(NyLPC_TcHttpdConnection_t* i_connection)
\r
489 if(!NyLPC_cHttpdUtils_sendJsonHeader(i_connection)){
\r
493 if(NyLPC_cHttpdConnection_getMethod(i_connection)==NyLPC_THttpMethodType_GET){
\r
494 NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"{\"application\":\""MVM_VERSION"\"}");
\r
499 * MimicVMの起動と,ResponseJSONの起動
\r
503 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh)
\r
505 struct TVmEventHandler he;
\r
506 NyLPC_TcMiMicVM_t vm;
\r
507 NyLPC_TUInt32 vmret;
\r
508 if(i_rqh->content.mvm.v!=QVAL_V_1 || i_rqh->content.mvm.o!=QVAL_O_JSON)
\r
510 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,400);
\r
516 if(!NyLPC_cHttpdUtils_sendJsonHeader(i_connection)){
\r
517 NyLPC_OnErrorGoto(Error1);
\r
520 he.super.get_stream=mvmgets;
\r
521 he.super.put_stream=mvmputs_json;
\r
522 he.super.native_call=nativeCall;
\r
523 he.super.sleep=mvmsleep;
\r
526 he.connection=i_connection;
\r
528 he.is_send_body=(NyLPC_cHttpdConnection_getMethod(i_connection)==NyLPC_THttpMethodType_GET);
\r
531 NyLPC_cMiMicVM_initialize(&vm,(struct NyLPC_TcMiMicVM_TEvent*)&(he.super));
\r
534 if(he.is_send_body){
\r
535 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"{\"version\":\""MVM_VERSION"\",\"stream\":[")){
\r
536 NyLPC_OnErrorGoto(Error1);
\r
540 vmret=NyLPC_cMiMicVM_run(&(vm),i_rqh->content.mvm.vm_instruction.bc_buf,i_rqh->content.mvm.vm_instruction.txt_len);
\r
542 if(he.is_send_body){
\r
543 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"],\"result\":%u}",vmret)){
\r
544 NyLPC_OnErrorGoto(Error1);
\r
547 NyLPC_cMiMicVM_finalize(&vm);
\r
550 NyLPC_cMiMicVM_finalize(&vm);
\r