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 "../http/NyLPC_cHttpShortRequestHeaderParser.h"
\r
29 #include "../NyLPC_cHttpdConnection_protected.h"
\r
30 #include "../../../mimicvm/NyLPC_cMiMicDbCompiler.h"
\r
31 #include "../../../mimicvm/NyLPC_cMiMicTxtCompiler.h"
\r
32 #include "NyLPC_cHttpmodUtils_protected.h"
\r
33 #include "../../../mimicvm/NyLPC_cMiMicVM_protected.h"
\r
34 #include "../../../net/NyLPC_cNet.h"
\r
36 #define MVM_VERSION "ModRemoteMcu/1.0;Json/1.0"
\r
37 #define SIZE_OF_IBUF 256
\r
38 struct TModMiMicRemoteMcuHeader
\r
40 struct NyLPC_THttpBasicHeader super;
\r
41 NyLPC_TUInt8 _content_id;
\r
43 NyLPC_TUInt8 _qery_name_id;
\r
44 NyLPC_TUInt8 _astate;
\r
45 NyLPC_TInt16 _prefix_len;
\r
46 NyLPC_TcStr_t _tstr;
\r
47 NyLPC_TChar _tstr_buf[16];
\r
48 struct NyLPC_TUInt32ArrayPtr _binarray;
\r
50 NyLPC_TcMiMicDbCompiler_t _binparser;
\r
51 NyLPC_TcMiMicTxtCompiler_t _txtcmp;
\r
54 NyLPC_TUInt8 v;//バージョン
\r
55 NyLPC_TUInt8 o;//outputスタイル
\r
57 * il_bufはbcとdbの2パートのデータを格納します。
\r
58 * 先頭からbc_lenの長さのBCパートと、db_partからdb_lenの長さのデータです。
\r
61 /** MiMicVMインストラクションの蓄積用。前半にTXT,後半にDBを格納する。 */
\r
62 NyLPC_TUInt32 bc_buf[SIZE_OF_IBUF];
\r
63 /** MiMicVM入力ストリーム(MimicDB)の開始位置(bufの一部を指す) */
\r
64 const NyLPC_TUInt32* db_part;
\r
65 /** MiMicTXTのワード長(1ワード32bit)*/
\r
66 NyLPC_TUInt16 txt_len;
\r
67 /** MiMicDBのワード長(1ワード32bit)*/
\r
68 NyLPC_TUInt16 db_len;
\r
73 * 不明な名前の場合は、ここに名前をコピー
\r
75 NyLPC_TChar path[32];
\r
81 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh);
\r
82 static void status(NyLPC_TcHttpdConnection_t* i_connection);
\r
85 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
\r
90 return NyLPC_TBool_TRUE;
\r
93 #define ST_PARSE_PATH 1
\r
94 #define ST_PARSE_QUERY_NAME 2
\r
95 #define ST_PARSE_QUERY_VALUE 3 //Query読み出し中
\r
96 #define ST_PARSE_QUERY_VALUE_V 4
\r
97 #define ST_PARSE_QUERY_VALUE_O 5
\r
98 #define ST_PARSE_QUERY_VALUE_BC 6
\r
99 #define ST_PARSE_QUERY_VALUE_DB 7
\r
101 * コンテンツID定義(コンテンツ名に対応)
\r
103 #define CONTENT_ID_MVM 2
\r
104 #define CONTENT_ID_STATUS 3
\r
105 #define CONTENT_ID_UNKNOWN 0
\r
108 #define QNAME_ID_V 1
\r
109 #define QNAME_ID_O 2
\r
110 #define QNAME_ID_BC 3
\r
111 #define QNAME_ID_UNKNOWN 0
\r
114 * TRemoteMcuRequest.content.mvm.oの値
\r
116 #define QVAL_O_UNKNOWN 0 //default
\r
117 #define QVAL_O_XML 1
\r
118 #define QVAL_O_JSON 2
\r
120 #define QVAL_V_UNKNOWN 0
\r
124 static const struct NyLPC_TTextIdTbl url_tbl[]=
\r
126 {"mvm.api",CONTENT_ID_MVM},
\r
127 {"status.api",CONTENT_ID_STATUS},
\r
128 {NULL,CONTENT_ID_UNKNOWN}
\r
131 static const struct NyLPC_TTextIdTbl qname_id_table[]=
\r
134 {"bc",QNAME_ID_BC},
\r
136 {NULL,QNAME_ID_UNKNOWN}
\r
141 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
\r
144 struct TModMiMicRemoteMcuHeader* out=(struct TModMiMicRemoteMcuHeader*)o_out;
\r
146 if(out->_prefix_len<0){
\r
147 out->_prefix_len++;
\r
148 return NyLPC_TBool_TRUE;//読み飛ばし
\r
150 if(out->_astate==ST_PARSE_PATH){
\r
151 if(i_c!='\0' && i_c!='?'){
\r
152 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
154 NyLPC_OnErrorGoto(ERROR);
\r
157 out->_content_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),url_tbl);
\r
158 switch(out->_content_id)
\r
160 case CONTENT_ID_MVM:
\r
161 out->content.mvm.vm_instruction.txt_len=0;
\r
162 out->content.mvm.vm_instruction.db_len=0;
\r
163 out->content.mvm.vm_instruction.db_part=NULL;
\r
164 NyLPC_TUInt32ArrayPtr_setBuf(&out->_binarray,out->content.mvm.vm_instruction.bc_buf,SIZE_OF_IBUF);
\r
165 out->content.mvm.o=QVAL_O_JSON;
\r
166 out->content.mvm.v=QVAL_V_UNKNOWN;
\r
171 NyLPC_cStr_clear(&(out->_tstr));
\r
172 out->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ
\r
174 return NyLPC_TBool_TRUE;
\r
176 switch(out->_content_id)
\r
178 case CONTENT_ID_MVM:
\r
179 switch(out->_astate){
\r
180 case ST_PARSE_QUERY_NAME:
\r
181 if(i_c!='\0' && i_c!='&' && i_c!='='){
\r
182 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
183 NyLPC_OnErrorGoto(ERROR);
\r
187 out->_qery_name_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),qname_id_table);
\r
188 NyLPC_cStr_clear(&(out->_tstr));
\r
190 switch(out->_qery_name_id){
\r
192 out->_astate=ST_PARSE_QUERY_VALUE_O;//MIMICBCのDBパラメータパーサを借用。
\r
195 out->_astate=ST_PARSE_QUERY_VALUE_V;
\r
198 out->_astate=ST_PARSE_QUERY_VALUE_BC;
\r
201 out->_astate=ST_PARSE_QUERY_VALUE;
\r
205 return NyLPC_TBool_TRUE;
\r
206 case ST_PARSE_QUERY_VALUE:
\r
208 if(i_c!='\0' && i_c!='&'){
\r
211 out->_astate=ST_PARSE_QUERY_NAME;
\r
213 return NyLPC_TBool_TRUE;
\r
214 case ST_PARSE_QUERY_VALUE_O:
\r
215 if(i_c!='\0' && i_c!='&'){
\r
216 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
217 NyLPC_OnErrorGoto(ERROR);
\r
220 if(NyLPC_cStr_isEqual(&(out->_tstr),"j")){
\r
221 out->content.mvm.o=QVAL_O_JSON;
\r
222 }else if(NyLPC_cStr_isEqual(&(out->_tstr),"x")){
\r
223 out->content.mvm.o=QVAL_O_XML;
\r
225 out->_astate=ST_PARSE_QUERY_NAME;
\r
226 NyLPC_cStr_clear(&(out->_tstr));
\r
228 return NyLPC_TBool_TRUE;
\r
229 case ST_PARSE_QUERY_VALUE_V:
\r
230 if(i_c!='\0' && i_c!='&'){
\r
231 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
232 NyLPC_OnErrorGoto(ERROR);
\r
235 if(NyLPC_cStr_isEqual(&(out->_tstr),"1")){
\r
236 out->content.mvm.v=QVAL_V_1;
\r
238 out->_astate=ST_PARSE_QUERY_NAME;
\r
239 NyLPC_cStr_clear(&(out->_tstr));
\r
241 return NyLPC_TBool_TRUE;
\r
242 case ST_PARSE_QUERY_VALUE_BC:
\r
243 if(i_c!='\0' && i_c!='&'){
\r
245 switch(NyLPC_cMiMicTxtCompiler_compileFragment2(&(out->_txtcmp),i_c,&(out->_binarray),&ol))
\r
247 case NyLPC_TcMiMicTxtCompiler_RET_OK:
\r
250 case NyLPC_TcMiMicTxtCompiler_RET_OK_END:
\r
252 out->content.mvm.vm_instruction.txt_len=SIZE_OF_IBUF-out->_binarray.len+ol;
\r
253 out->content.mvm.vm_instruction.db_part=out->content.mvm.vm_instruction.bc_buf+out->content.mvm.vm_instruction.txt_len;
\r
254 out->_astate=ST_PARSE_QUERY_VALUE_DB;
\r
256 case NyLPC_TcMiMicTxtCompiler_RET_CONTINUE:
\r
259 case NyLPC_TcMiMicTxtCompiler_RET_NG:
\r
262 NyLPC_OnErrorGoto(ERROR);
\r
265 return NyLPC_TBool_TRUE;
\r
266 // //フラグメント終端が検出できない終了はエラー
\r
267 // NyLPC_OnErrorGoto(ERROR);
\r
268 case ST_PARSE_QUERY_VALUE_DB:
\r
269 if(i_c!='\0' && i_c!='&'){
\r
270 switch(NyLPC_cMiMicDbCompiler_compileFragment2(&(out->_binparser),i_c,out->_binarray.ptr))
\r
272 case NyLPC_TcMiMicDbCompiler_RET_CONTINUE:
\r
274 case NyLPC_TcMiMicDbCompiler_RET_OK:
\r
276 if(!NyLPC_TUInt32ArrayPtr_seek(&(out->_binarray),1)){
\r
278 NyLPC_OnErrorGoto(ERROR);
\r
281 case NyLPC_TcMiMicDbCompiler_RET_ERROR:
\r
284 NyLPC_OnErrorGoto(ERROR);
\r
288 if(NyLPC_cMiMicDbCompiler_hasFragment(&(out->_binparser))){
\r
290 NyLPC_OnErrorGoto(ERROR);
\r
292 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
295 out->_astate=ST_PARSE_QUERY_NAME;
\r
297 return NyLPC_TBool_TRUE;
\r
301 NyLPC_OnErrorGoto(ERROR);
\r
303 NyLPC_OnErrorGoto(ERROR);
\r
305 return NyLPC_TBool_TRUE;
\r
307 return NyLPC_TBool_FALSE;
\r
312 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=
\r
322 void NyLPC_cModRemoteMcu_initialize(NyLPC_TcModRemoteMcu_t* i_inst,const NyLPC_TChar* i_ref_root_path)
\r
324 NyLPC_cModRomFiles_initialize(&i_inst->super,i_ref_root_path,NULL,0);
\r
326 void NyLPC_cModRemoteMcu_finalize(NyLPC_TcModRemoteMcu_t* i_inst)
\r
328 NyLPC_cModRomFiles_finalize(&i_inst->super);
\r
331 * モジュールがコネクションをハンドリングできるかを返します。
\r
333 NyLPC_TBool NyLPC_cModRemoteMcu_canHandle(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
\r
335 return NyLPC_cModRomFiles_canHandle(&i_inst->super,i_connection);
\r
338 static struct TModMiMicRemoteMcuHeader single_header;
\r
343 NyLPC_TBool NyLPC_cModRemoteMcu_execute(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
\r
345 NyLPC_TcHttpBasicHeaderParser_t parser;
\r
347 if(!NyLPC_cHttpdConnection_getReqStatus(i_connection)==NyLPC_cHttpdConnection_ReqStatus_REQPARSE)
\r
349 NyLPC_OnErrorGoto(Error1);
\r
351 //リクエストParse済へ遷移(この関数の後はModが責任を持ってリクエストを返却)
\r
352 NyLPC_cHttpdConnection_setReqStatusParsed(i_connection);
\r
356 NyLPC_cHttpdConnection_lock(i_connection);
\r
360 single_header._prefix_len=-(NyLPC_TInt16)strlen(i_inst->super._ref_root_path);
\r
361 single_header._astate=ST_PARSE_PATH;
\r
362 NyLPC_cStr_initialize(&single_header._tstr,single_header._tstr_buf,16);
\r
363 NyLPC_cMiMicDbCompiler_initialize(&single_header._binparser);
\r
364 NyLPC_cMiMicTxtCompiler_initialize(&single_header._txtcmp);
\r
366 NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);
\r
369 NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(single_header.super));
\r
370 NyLPC_cHttpdConnection_pushPrefetchInfo(i_connection,&parser,&single_header.super);
\r
372 if(!NyLPC_cHttpBasicHeaderParser_parseStream(&parser,NyLPC_cHttpdConnection_refStream(i_connection),&(single_header.super))){
\r
373 NyLPC_OnErrorGoto(Error2);
\r
375 if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(single_header.super))){
\r
376 NyLPC_OnErrorGoto(Error2);
\r
378 //Connection Modeの設定 1.1 && !closeの場合はCONTINUE
\r
379 if(single_header.super.connection!=NyLPC_THttpMessgeHeader_Connection_CLOSE && single_header.super.startline.req.version==NyLPC_THttpVersion_11)
\r
381 NyLPC_cHttpdConnection_setConnectionMode(i_connection,NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE);
\r
384 switch(single_header._content_id)
\r
386 case CONTENT_ID_MVM:
\r
387 mvm(i_connection,&single_header);
\r
389 case CONTENT_ID_STATUS:
\r
390 status(i_connection);
\r
393 NyLPC_OnErrorGoto(Error2);
\r
395 NyLPC_cStr_finalize(&single_header._tstr);
\r
396 NyLPC_cMiMicDbCompiler_finalize(&single_header._binparser);
\r
397 NyLPC_cMiMicTxtCompiler_finalize(&single_header._txtcmp);
\r
398 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
400 NyLPC_cHttpdConnection_unlock(i_connection);
\r
401 return NyLPC_TBool_TRUE;
\r
403 NyLPC_cHttpdConnection_sendResponseHeader2(i_connection,500,"text/html",0,NULL);
\r
404 NyLPC_cStr_finalize(&single_header._tstr);
\r
405 NyLPC_cMiMicDbCompiler_finalize(&single_header._binparser);
\r
406 NyLPC_cMiMicTxtCompiler_finalize(&single_header._txtcmp);
\r
407 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
409 NyLPC_cHttpdConnection_unlock(i_connection);
\r
411 return NyLPC_TBool_FALSE;
\r
418 struct TVmEventHandler
\r
420 struct NyLPC_TcMiMicVM_TEvent super;
\r
421 const struct TModMiMicRemoteMcuHeader* req;
\r
422 NyLPC_TcHttpdConnection_t* connection;
\r
423 NyLPC_TUInt16 db_pos;
\r
424 /** ストリームへ出力したデータの数*/
\r
425 NyLPC_TUInt16 st_len;
\r
431 static NyLPC_TBool mvmputs_json(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_val)
\r
433 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
436 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,",%u",i_val);
\r
439 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,"%u",i_val);
\r
446 static NyLPC_TBool mvmgets(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32* o_val)
\r
448 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
450 if(eh->req->content.mvm.vm_instruction.db_len<=eh->db_pos){
\r
452 return NyLPC_TBool_FALSE;
\r
454 *o_val=eh->req->content.mvm.vm_instruction.db_part[eh->db_pos];
\r
456 return NyLPC_TBool_TRUE;
\r
461 static NyLPC_TUInt32 nativeCall(struct NyLPC_TcMiMicVM_TEvent* i_evh,NyLPC_TUInt32 i_id,NyLPC_TcMiMicVM_t* i_vm)
\r
464 // NyLPC_TNativeFunction f=getNativeFunctionById(i_id);
\r
466 // return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_UNKNOWN_CALL;
\r
468 // return f(i_vm)?NyLPC_cMiMicVM_RESULT_OK:NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
469 return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
473 static void mvmsleep(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_sleep_in_msec)
\r
476 NyLPC_cThread_sleep(i_sleep_in_msec);
\r
480 * RemoteMCUのステータスを返す。基本的にjson
\r
482 * application:"[VERSION]"
\r
485 static void status(NyLPC_TcHttpdConnection_t* i_connection)
\r
487 if(!NyLPC_cHttpdModUtils_sendJsonHeader(i_connection)){
\r
491 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"{\"application\":\""MVM_VERSION";%s\"}",NyLPC_cNet_PlatformName)){
\r
497 * MimicVMの起動と,ResponseJSONの起動
\r
501 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh)
\r
503 struct TVmEventHandler he;
\r
504 NyLPC_TcMiMicVM_t vm;
\r
505 NyLPC_TUInt32 vmret;
\r
506 if(i_rqh->content.mvm.v!=QVAL_V_1 || i_rqh->content.mvm.o!=QVAL_O_JSON)
\r
508 NyLPC_cHttpdConnection_sendResponseHeader2(i_connection,500,"text/html",0,NULL);
\r
513 //ここでリクエストパーサのエラー原因を調べて、詳細JSONをかくのもあり
\r
515 if(!NyLPC_cHttpdModUtils_sendJsonHeader(i_connection)){
\r
516 NyLPC_OnErrorGoto(Error1);
\r
519 he.super.get_stream=mvmgets;
\r
520 he.super.put_stream=mvmputs_json;
\r
521 he.super.native_call=nativeCall;
\r
522 he.super.sleep=mvmsleep;
\r
525 he.connection=i_connection;
\r
529 NyLPC_cMiMicVM_initialize(&vm,(struct NyLPC_TcMiMicVM_TEvent*)&(he.super));
\r
532 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"{\"version\":\""MVM_VERSION"\",\"stream\":[")){
\r
533 NyLPC_OnErrorGoto(Error3);
\r
536 vmret=NyLPC_cMiMicVM_run(&(vm),i_rqh->content.mvm.vm_instruction.bc_buf,i_rqh->content.mvm.vm_instruction.txt_len);
\r
537 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"],\"result\":%u}",vmret)){
\r
538 NyLPC_OnErrorGoto(Error3);
\r
540 NyLPC_cMiMicVM_finalize(&vm);
\r
544 NyLPC_cMiMicVM_finalize(&vm);
\r
547 NyLPC_cMiMicVM_finalize(&vm);
\r
548 NyLPC_cHttpBodyWriter_finalize(&hw);
\r