This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088
Dependents: MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more
NyLPC_cModWebSocket.c
00001 /********************************************************************************* 00002 * PROJECT: MiMic 00003 * -------------------------------------------------------------------------------- 00004 * 00005 * This file is part of MiMic 00006 * Copyright (C)2011 Ryo Iizuka 00007 * 00008 * MiMic is free software: you can redistribute it and/or modify 00009 * it under the terms of the GNU Lesser General Public License as published 00010 * by the Free Software Foundation, either version 3 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public License 00019 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 * 00021 * For further information please contact. 00022 * http://nyatla.jp/ 00023 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp> 00024 * 00025 *********************************************************************************/ 00026 #include "NyLPC_cModWebSocket_protected.h" 00027 #include "NyLPC_utils.h" 00028 00029 #define HTTP_TIMEOUT NyLPC_TiHttpPtrStream_DEFAULT_HTTP_TIMEOUT 00030 00031 #define NyLPC_TcModWebSocket_FRAME_TYPE_BIN 0x01 00032 #define NyLPC_TcModWebSocket_FRAME_TYPE_TXT 0x02 00033 00034 00035 00036 #define STRBUF_MAX 32 00037 struct TModWebSocketHeader 00038 { 00039 struct NyLPC_THttpBasicHeader super; 00040 NyLPC_TcStr_t _tstr; 00041 NyLPC_TChar _tstr_buf[STRBUF_MAX]; 00042 NyLPC_TChar key[24+4]; 00043 NyLPC_TInt16 version; 00044 NyLPC_TUInt8 sub_protocol_id; 00045 NyLPC_TUInt8 message_id; 00046 const NyLPC_TChar* _ref_sub_protocol; 00047 }; 00048 00049 00050 00051 #define MESSAGE_ID_UNKNOWN 0x00 00052 #define MESSAGE_ID_UPGRADE 0x01 00053 #define MESSAGE_ID_SEC_WEBSOCKET_KEY 0x02 00054 #define MESSAGE_ID_ORIGIN 0x03 00055 #define MESSAGE_ID_SEC_WEBSOCKET_PROTOCL 0x04 00056 #define MESSAGE_ID_SEC_WEBSOCKET_VERSION 0x05 00057 00058 static const struct NyLPC_TTextIdTbl msg_tbl[]= 00059 { 00060 {"Upgrade",MESSAGE_ID_UPGRADE}, 00061 {"Sec-WebSocket-Key",MESSAGE_ID_SEC_WEBSOCKET_KEY}, 00062 {"Origin",MESSAGE_ID_ORIGIN}, 00063 {"Sec-WebSocket-Protocol",MESSAGE_ID_SEC_WEBSOCKET_PROTOCL}, 00064 {"Sec-WebSocket-Version",MESSAGE_ID_SEC_WEBSOCKET_VERSION}, 00065 {NULL,MESSAGE_ID_UNKNOWN} 00066 }; 00067 00068 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out) 00069 { 00070 struct TModWebSocketHeader* out=(struct TModWebSocketHeader*)o_out; 00071 if(i_name!=NULL){ 00072 out->message_id=NyLPC_TTextIdTbl_getMatchIdIgnoreCase(i_name,msg_tbl); 00073 NyLPC_cStr_clear(&(out->_tstr)); 00074 }else{ 00075 switch(out->message_id) 00076 { 00077 case MESSAGE_ID_UPGRADE: 00078 if(i_c!='\0'){ 00079 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){ 00080 NyLPC_OnErrorGoto(ERROR); 00081 } 00082 }else{ 00083 //websocketかチェック 00084 if(!NyLPC_cStr_isEqualIgnoreCase(&out->_tstr,"websocket")){ 00085 return NyLPC_TBool_FALSE;//不一致 00086 } 00087 } 00088 break; 00089 case MESSAGE_ID_SEC_WEBSOCKET_KEY: 00090 if(i_c!='\0'){ 00091 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){ 00092 NyLPC_OnErrorGoto(ERROR); 00093 } 00094 }else{ 00095 //HASH値をコピー 00096 strcpy(out->key,NyLPC_cStr_str(&out->_tstr)); 00097 } 00098 break; 00099 case MESSAGE_ID_SEC_WEBSOCKET_PROTOCL: 00100 if(i_c!='\0' && i_c!=','){ 00101 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){ 00102 NyLPC_OnErrorGoto(ERROR); 00103 } 00104 }else{ 00105 //トークン終端 00106 if(out->_ref_sub_protocol!=NULL){ 00107 //サブプロトコルが指定されている場合はチェック 00108 if(NyLPC_stricmp(NyLPC_cStr_str(&out->_tstr),out->_ref_sub_protocol)==0){ 00109 out->sub_protocol_id=1;//SubProtocol一致 00110 } 00111 } 00112 //','の時はリセット 00113 if(i_c!=','){ 00114 NyLPC_cStr_clear(&(out->_tstr)); 00115 } 00116 } 00117 break; 00118 case MESSAGE_ID_SEC_WEBSOCKET_VERSION: 00119 if(i_c!='\0'){ 00120 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){ 00121 NyLPC_OnErrorGoto(ERROR); 00122 } 00123 }else{ 00124 //VERSION 00125 out->version=atoi(NyLPC_cStr_str(&out->_tstr)); 00126 if(out->version<0){ 00127 NyLPC_OnErrorGoto(ERROR); 00128 } 00129 } 00130 } 00131 } 00132 return NyLPC_TBool_TRUE; 00133 ERROR: 00134 return NyLPC_TBool_FALSE; 00135 } 00136 00137 00138 00139 00140 /** 00141 * デフォルトハンドラ 00142 */ 00143 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler= 00144 { 00145 messageHandler, 00146 NULL 00147 }; 00148 00149 00150 00151 /** 00152 * コンストラクタ。 00153 */ 00154 void NyLPC_cModWebSocket_initialize(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_ref_root_path) 00155 { 00156 NyLPC_cModRomFiles_initialize(&i_inst->super,i_ref_root_path,NULL,0); 00157 i_inst->_frame_type=NyLPC_TcModWebSocket_FRAME_TYPE_TXT; 00158 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00159 } 00160 void NyLPC_cModWebSocket_finalize(NyLPC_TcModWebSocket_t* i_inst) 00161 { 00162 NyLPC_cModRomFiles_finalize(&i_inst->super); 00163 } 00164 /** 00165 * モジュールがコネクションをハンドリングできるかを返します。 00166 */ 00167 NyLPC_TBool NyLPC_cModWebSocket_canHandle(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection) 00168 { 00169 return NyLPC_cModRomFiles_canHandle(&i_inst->super,i_connection); 00170 } 00171 00172 static union{ 00173 struct TModWebSocketHeader header; 00174 }work; 00175 00176 00177 00178 /** 00179 * モジュールを実行します。 00180 */ 00181 NyLPC_TBool NyLPC_cModWebSocket_execute(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection) 00182 { 00183 union{ 00184 NyLPC_TcHttpBasicHeaderParser_t parser; 00185 SHA1_CTX sh1; 00186 }sh; 00187 00188 //リクエストParse済へ遷移(この関数の後はModが責任を持ってリクエストを返却) 00189 NyLPC_cHttpdConnection_setReqStatusParsed(i_connection); 00190 00191 00192 00193 //排他ロック 00194 NyLPC_cHttpdConnection_lock(i_connection); 00195 {//parser 00196 00197 //初期化 00198 work.header.version=0; 00199 work.header.sub_protocol_id=0; 00200 NyLPC_cStr_initialize(&work.header._tstr,work.header._tstr_buf,STRBUF_MAX); 00201 00202 NyLPC_cHttpBasicHeaderParser_initialize(&sh.parser,&handler); 00203 00204 //プリフェッチしたデータを流す 00205 NyLPC_cHttpBasicHeaderParser_parseInit(&sh.parser,&(work.header.super)); 00206 NyLPC_cHttpdConnection_pushPrefetchInfo(i_connection,&sh.parser,&work.header.super); 00207 //後続をストリームから取り込む 00208 if(!NyLPC_cHttpBasicHeaderParser_parseStream(&sh.parser,NyLPC_cHttpdConnection_refStream(i_connection),&(work.header.super))){ 00209 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500); 00210 NyLPC_OnErrorGoto(Error1); 00211 } 00212 if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&sh.parser,&(work.header.super))){ 00213 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500); 00214 NyLPC_OnErrorGoto(Error1); 00215 } 00216 //HeaderParserはここで破棄(URLEncode,cSTRも) 00217 NyLPC_cHttpBasicHeaderParser_finalize(&sh.parser); 00218 00219 NyLPC_cStr_finalize(&single_header._tstr); 00220 00221 00222 //HTTP/1.1であること。Connection:Upgradeはチェックしない。 00223 if(work.header.super.startline.req.version!=NyLPC_THttpVersion_11) 00224 { 00225 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,400); 00226 NyLPC_OnErrorGoto(Error2); 00227 } 00228 if(NyLPC_cHttpdConnection_getMethod(i_connection)!=NyLPC_THttpMethodType_GET){ 00229 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,400); 00230 NyLPC_OnErrorGoto(Error2); 00231 } 00232 //WebSocket version 13であること 00233 if(work.header.version!=13){ 00234 NyLPC_cHttpdUtils_sendErrorResponse(i_connection,400); 00235 NyLPC_OnErrorGoto(Error2); 00236 } 00237 00238 //レスポンスの生成(生データを直接ストリームへ書きこむ) 00239 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_connection), 00240 "HTTP/1.1 101 Switching Protocols\r\n" //32+2 00241 "Upgrade: websocket\r\n" //18+2 00242 "Connection: Upgrade\r\n" //19+2 00243 "Sec-WebSocket-Accept: " //22 00244 ,32+2+18+2+19+2+22)){ 00245 NyLPC_OnErrorGoto(Error3); 00246 } 00247 //SH1キーの生成 00248 SHA1Init(&sh.sh1); 00249 SHA1Update(&sh.sh1,(const unsigned char*)work.header.key,strlen(work.header.key)); 00250 SHA1Update(&sh.sh1,(const unsigned char*)"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",36); 00251 //ワークメモリ32バイトはstrの使いまわし 00252 SHA1Final((unsigned char*)(work.header._tstr_buf),&sh.sh1); 00253 //BASE64化(single_header.keyへ出力) 00254 NyLPC_cBase64_encode(work.header._tstr_buf,20,work.header.key); 00255 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_connection),work.header.key,28)){ 00256 NyLPC_OnErrorGoto(Error3); 00257 } 00258 //SubProtocolの認証が有る場合 00259 if(work.header.sub_protocol_id!=0){ 00260 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_connection) 00261 ,"\r\nSec-WebSocket-Protocol: " //24 00262 ,24)){ 00263 NyLPC_OnErrorGoto(Error3); 00264 } 00265 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_connection) 00266 ,work.header._ref_sub_protocol 00267 ,strlen(work.header._ref_sub_protocol))) 00268 { 00269 NyLPC_OnErrorGoto(Error3); 00270 } 00271 } 00272 //Sec-WebSocket-Protocol 00273 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_connection),"\r\n\r\n",4)){ 00274 NyLPC_OnErrorGoto(Error3); 00275 } 00276 //connection phase 00277 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_START_PAYLOAD; 00278 } 00279 //占有解除 00280 NyLPC_cHttpdConnection_unlock(i_connection); 00281 //参照コネクションの設定 00282 i_inst->_ref_connection=i_connection; 00283 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00284 return NyLPC_TBool_TRUE; 00285 Error3: 00286 Error2: 00287 //VM排他ロックの解除 00288 NyLPC_cHttpdConnection_unlock(i_connection); 00289 return NyLPC_TBool_FALSE; 00290 Error1: 00291 NyLPC_cHttpBasicHeaderParser_finalize(&parser); 00292 NyLPC_cStr_finalize(&single_header._tstr); 00293 //VM排他ロックの解除 00294 NyLPC_cHttpdConnection_unlock(i_connection); 00295 return NyLPC_TBool_FALSE; 00296 } 00297 00298 00299 00300 static void writeClosePacket(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TUInt16 i_code) 00301 { 00302 char w[4]; 00303 w[0]=0x88; 00304 w[1]=0x02; 00305 *((NyLPC_TUInt16*)(&w[2]))=NyLPC_htons(i_code); //REASON 00306 //CloseFrame送信 00307 NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),w,4); 00308 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00309 } 00310 00311 00312 NyLPC_TBool NyLPC_cModWebSocket_canRead(const NyLPC_TcModWebSocket_t* i_inst) 00313 { 00314 const NyLPC_TUInt8* rx; 00315 return NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,0)>0; 00316 } 00317 00318 #define FLAGS_MASK_BIT 7 00319 00320 /** 00321 * Websocketの状態を更新します。 00322 * @return 00323 */ 00324 void NyLPC_cModWebSocket_update(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TUInt32 i_time_out) 00325 { 00326 const NyLPC_TUInt8* rx; 00327 NyLPC_TInt32 rs,rt; 00328 NyLPC_TUInt16 header_size; 00329 NyLPC_TUInt8 w8[2]; 00330 if(i_inst->_payload_st==NyLPC_TcModWebSocket_ST_CLOSED){ 00331 return; 00332 } 00333 START: 00334 rs=NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,i_time_out); 00335 00336 //Error? 00337 if(rs<0){ 00338 NyLPC_OnErrorGoto(Error); 00339 } 00340 //Timeout? 00341 if(rs==0){ 00342 goto Timeout; 00343 } 00344 switch(i_inst->_payload_st){ 00345 case NyLPC_TcModWebSocket_ST_READ_PAYLOAD: 00346 //ペイロード読み出し中破何もしない 00347 return; 00348 case NyLPC_TcModWebSocket_ST_START_PAYLOAD: 00349 //ペイロード 00350 //2バイト溜まるまで待つ 00351 if(rs<2){ 00352 //Timeout? 00353 goto Timeout; 00354 } 00355 //ペイロードサイズの分析 00356 if((0x7f&rx[1])<=125){ 00357 header_size=2+(((rx[1]&0x80)==0x80)?4:0); 00358 i_inst->payload_size=(0x7f&rx[1]); 00359 }else if((0x7f&rx[1])==126){ 00360 if(rs<4){ 00361 //Timeout? 00362 goto Timeout; 00363 } 00364 header_size=2+2+(((rx[1]&0x80)==0x80)?4:0); 00365 i_inst->payload_size=(rx[2]<<8)|rx[3]; 00366 }else{ 00367 //CLOSEの送信 00368 writeClosePacket(i_inst,1009); 00369 NyLPC_OnErrorGoto(Error); 00370 } 00371 //十分なヘッダが集まったかチェック 00372 if(rs<header_size){ 00373 goto Timeout; 00374 } 00375 i_inst->_frame_flags_bits=0; 00376 //FINがセットされていること.断片化禁止! 00377 if((rx[0]&0x80)!=0x80){ 00378 NyLPC_OnErrorGoto(Error); 00379 } 00380 //必要ならMaskをコピー 00381 if((rx[1]&0x80)==0x80){ 00382 memcpy(i_inst->_frame_mask,(rx+header_size-4),4); 00383 NyLPC_TUInt8_setBit(i_inst->_frame_flags_bits,FLAGS_MASK_BIT); 00384 } 00385 //ペイロードポインターのリセット 00386 i_inst->payload_ptr=0; 00387 00388 //パケットサイズの確定(基本ヘッダ+マスク) 00389 switch(rx[0]&0x0f){ 00390 case 0x00: 00391 //継続パケットは扱わない 00392 NyLPC_OnErrorGoto(Error); 00393 case 0x01: 00394 if(i_inst->_frame_type!=NyLPC_TcModWebSocket_FRAME_TYPE_TXT){ 00395 NyLPC_OnErrorGoto(Error); 00396 } 00397 break; 00398 case 0x02: 00399 if(i_inst->_frame_type==NyLPC_TcModWebSocket_FRAME_TYPE_BIN){ 00400 NyLPC_OnErrorGoto(Error); 00401 } 00402 break; 00403 case 0x08://close(非断片) 00404 //CloseFrame送信 00405 writeClosePacket(i_inst,1009); 00406 //Errorとして処理 00407 NyLPC_OnErrorGoto(Error); 00408 case 0x09://ping(非断片) 00409 //PONGを送信 00410 w8[0]=0x0a; 00411 NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),w8,1); 00412 NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rx+1,header_size-1); 00413 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00414 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),header_size); 00415 while(i_inst->payload_size!=i_inst->payload_ptr){ 00416 rs=NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,HTTP_TIMEOUT); 00417 if(rs<=0){ 00418 if(rs<0){ 00419 //Error 00420 NyLPC_OnErrorGoto(Error); 00421 } 00422 //Timeout 00423 goto Timeout; 00424 } 00425 //読出し可能なサイズを決定 00426 rt=i_inst->payload_size-i_inst->payload_ptr; 00427 if(rs>rt){ 00428 rs=rt; 00429 } 00430 //パケットを破棄 00431 NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rx,rs); 00432 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rs); 00433 i_inst->payload_ptr+=rs; 00434 } 00435 //Timeout(パケットスタートに戻る?) 00436 goto START; 00437 case 0x0a://pong(非断片) 00438 //パケットの読み捨て 00439 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),header_size); 00440 while(i_inst->payload_size!=i_inst->payload_ptr){ 00441 rs=NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,HTTP_TIMEOUT); 00442 if(rs<=0){ 00443 if(rs<0){ 00444 //Error 00445 NyLPC_OnErrorGoto(Error); 00446 } 00447 //Timeout 00448 goto Timeout; 00449 } 00450 //読出し可能なサイズを決定 00451 rt=i_inst->payload_size-i_inst->payload_ptr; 00452 if(rs>rt){ 00453 rs=rt; 00454 } 00455 //パケットを破棄 00456 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rs); 00457 i_inst->payload_ptr+=rs; 00458 } 00459 //Timeout(パケットスタートに戻る?) 00460 goto START; 00461 default: 00462 //知らないコードはエラー 00463 NyLPC_OnErrorGoto(Error); 00464 } 00465 //読み出し位置のシーク(Header部) 00466 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),header_size); 00467 //ペイロード読み出しへ 00468 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_READ_PAYLOAD; 00469 //継続してペイロード受信処理 00470 return; 00471 } 00472 //処理されなければエラー 00473 Error: 00474 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00475 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00476 return; 00477 Timeout: 00478 return; 00479 } 00480 00481 00482 /** 00483 * 受信データをコールバック関数に通知するNyLPC_cModWebSocket_readです。 00484 * @return 00485 * n>0:データ受信 00486 * 0 :タイムアウト。コネクションの状態は変化しない。 00487 * -1 :エラー コネクションはNyLPC_TcModWebSocket_ST_CLOSEDへ遷移する。 00488 */ 00489 NyLPC_TInt16 NyLPC_cModWebSocket_readCB(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TcModWebSocket_onRreadCB i_cb,void* i_cb_param) 00490 { 00491 const NyLPC_TUInt8* rx; 00492 NyLPC_TInt32 rs,rd,i; 00493 //ストリームの状態を更新する。 00494 NyLPC_cModWebSocket_update(i_inst,HTTP_TIMEOUT); 00495 00496 switch(i_inst->_payload_st) 00497 { 00498 case NyLPC_TcModWebSocket_ST_READ_PAYLOAD: 00499 break;//処理継続 00500 case NyLPC_TcModWebSocket_ST_START_PAYLOAD: 00501 //タイムアウト扱い 00502 return 0; 00503 default: 00504 return -1; 00505 } 00506 //読み出し可能なデータをパース 00507 rs=NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,HTTP_TIMEOUT); 00508 if(rs<=0){ 00509 if(rs<0){ 00510 //Error 00511 NyLPC_OnErrorGoto(Error); 00512 } 00513 //Timeout 00514 goto Timeout; 00515 } 00516 //読出し可能な残りサイズを計算して上書き 00517 rd=i_inst->payload_size-i_inst->payload_ptr; 00518 if(rs>rd){ 00519 rs=rd; 00520 } 00521 //読みだしたバイト数をリセット 00522 rd=0; 00523 //アンマスク 00524 if(NyLPC_TUInt8_isBitOn(i_inst->_frame_flags_bits,FLAGS_MASK_BIT)){ 00525 //マスク有の時 00526 for(i=0;i<rs;i++){ 00527 rd++; 00528 switch(i_cb(i_cb_param,rx[i]^i_inst->_frame_mask[(i_inst->payload_ptr+i)%4])){ 00529 case 1: 00530 continue; 00531 case 0: 00532 break; 00533 default: 00534 NyLPC_OnErrorGoto(Error); 00535 } 00536 } 00537 }else{ 00538 //マスクなしの時 00539 for(i=0;i<rs;i++){ 00540 rd++; 00541 switch(i_cb(i_cb_param,rx[i])){ 00542 case 1: 00543 continue; 00544 case 0: 00545 break; 00546 default: 00547 NyLPC_OnErrorGoto(Error); 00548 } 00549 } 00550 } 00551 //読取位置を移動 00552 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rd); 00553 i_inst->payload_ptr+=rd; 00554 if(i_inst->payload_size==i_inst->payload_ptr){ 00555 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_START_PAYLOAD; 00556 } 00557 return rd; 00558 //処理されなければエラー 00559 Error: 00560 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00561 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00562 return -1; 00563 Timeout: 00564 return 0; 00565 } 00566 00567 /** 00568 * @return 00569 * n>0:データ受信 00570 * 0 :タイムアウト。コネクションの状態は変化しない。 00571 * -1 :エラー コネクションはNyLPC_TcModWebSocket_ST_CLOSEDへ遷移する。 00572 */ 00573 NyLPC_TInt16 NyLPC_cModWebSocket_read(NyLPC_TcModWebSocket_t* i_inst,void* i_buf,NyLPC_TInt16 i_buf_len) 00574 { 00575 const NyLPC_TUInt8* rx; 00576 NyLPC_TInt32 rs,i; 00577 //ストリームの状態を更新する。 00578 NyLPC_cModWebSocket_update(i_inst,HTTP_TIMEOUT); 00579 00580 switch(i_inst->_payload_st) 00581 { 00582 case NyLPC_TcModWebSocket_ST_READ_PAYLOAD: 00583 break;//処理継続 00584 case NyLPC_TcModWebSocket_ST_START_PAYLOAD: 00585 //タイムアウト扱い 00586 return 0; 00587 default: 00588 return -1; 00589 } 00590 //読み出し可能なデータをパース 00591 rs=NyLPC_iHttpPtrStream_pread(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),(const void**)&rx,HTTP_TIMEOUT); 00592 if(rs<=0){ 00593 if(rs<0){ 00594 //Error 00595 NyLPC_OnErrorGoto(Error); 00596 } 00597 //Timeout 00598 goto Timeout; 00599 } 00600 //読み込みサイズを決定 00601 rs=(rs<i_buf_len)?rs:i_buf_len; 00602 //アンマスク 00603 if(NyLPC_TUInt8_isBitOn(i_inst->_frame_flags_bits,FLAGS_MASK_BIT)){ 00604 for(i=0;i<rs;i++){ 00605 *(((NyLPC_TUInt8*)i_buf)+i)=rx[i]^i_inst->_frame_mask[(i_inst->payload_ptr+i)%4]; 00606 } 00607 }else{ 00608 memcpy(i_buf,rx,rs); 00609 } 00610 //読取位置を移動 00611 NyLPC_iHttpPtrStream_rseek(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),rs); 00612 i_inst->payload_ptr+=rs; 00613 if(i_inst->payload_size==i_inst->payload_ptr){ 00614 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_START_PAYLOAD; 00615 } 00616 return rs; 00617 //処理されなければエラー 00618 Error: 00619 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00620 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00621 return -1; 00622 Timeout: 00623 return 0; 00624 } 00625 00626 00627 00628 00629 static NyLPC_TBool fmt_handler(void* i_inst,const void* i_buf,NyLPC_TUInt32 i_len) 00630 { 00631 return NyLPC_iHttpPtrStream_write((NyLPC_TiHttpPtrStream_t*)i_inst,i_buf,i_len); 00632 } 00633 00634 00635 /** 00636 * Payloadヘッダを書く。 00637 */ 00638 NyLPC_TBool NyLPC_cModWebSocket_writePayloadHeader(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TInt16 i_len) 00639 { 00640 NyLPC_TUInt16 s; 00641 NyLPC_TChar w[4]; 00642 //CLOSED,CONNECTの時は使用不可 00643 switch(i_inst->_payload_st){ 00644 case NyLPC_TcModWebSocket_ST_CLOSED: 00645 return NyLPC_TBool_FALSE; 00646 default: 00647 break; 00648 } 00649 //データサイズで切り分け 00650 switch(i_inst->_frame_type) 00651 { 00652 case NyLPC_TcModWebSocket_FRAME_TYPE_TXT: 00653 w[0]=0x80|0x01; 00654 break; 00655 case NyLPC_TcModWebSocket_FRAME_TYPE_BIN: 00656 w[0]=0x80|0x02; 00657 break; 00658 default: 00659 NyLPC_OnErrorGoto(Error); 00660 } 00661 if(i_len<126){ 00662 w[1]=(NyLPC_TUInt8)i_len; 00663 s=2; 00664 }else{ 00665 w[1]=126; 00666 s=4; 00667 *((NyLPC_TUInt16*)(&(w[2])))=NyLPC_htons(i_len); 00668 } 00669 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),w,s)){ 00670 //CLOSE 00671 NyLPC_OnErrorGoto(Error); 00672 } 00673 return NyLPC_TBool_TRUE; 00674 Error: 00675 return NyLPC_TBool_FALSE; 00676 } 00677 00678 00679 00680 NyLPC_TBool NyLPC_cModWebSocket_writeFormatV(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,va_list args) 00681 { 00682 NyLPC_TInt16 l; 00683 va_list a; 00684 //ストリームの状態を更新する。 00685 NyLPC_cModWebSocket_update(i_inst,0); 00686 00687 //書式文字列の長さを計算 00688 NyLPC_va_copy(a,args); 00689 l=NyLPC_cFormatWriter_length(i_fmt,a); 00690 va_end(a); 00691 if(!NyLPC_cModWebSocket_writePayloadHeader(i_inst,l)){ 00692 //CLOSE 00693 NyLPC_OnErrorGoto(Error); 00694 } 00695 if(!NyLPC_cFormatWriter_print(fmt_handler,NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),i_fmt,args)){ 00696 NyLPC_OnErrorGoto(Error); 00697 } 00698 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00699 return NyLPC_TBool_TRUE; 00700 Error: 00701 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00702 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00703 return NyLPC_TBool_FALSE; 00704 } 00705 00706 NyLPC_TBool NyLPC_cModWebSocket_writeFormat(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,...) 00707 { 00708 NyLPC_TBool r; 00709 va_list a; 00710 va_start(a,i_fmt); 00711 r=NyLPC_cModWebSocket_writeFormatV(i_inst,i_fmt,a); 00712 va_end(a); 00713 return r; 00714 } 00715 00716 00717 00718 00719 NyLPC_TBool NyLPC_cModWebSocket_write(NyLPC_TcModWebSocket_t* i_inst,const void* i_buf,NyLPC_TInt16 i_len) 00720 { 00721 //ストリームの状態を更新する。 00722 NyLPC_cModWebSocket_update(i_inst,0); 00723 if(!NyLPC_cModWebSocket_writePayloadHeader(i_inst,i_len)){ 00724 //CLOSE 00725 NyLPC_OnErrorGoto(Error); 00726 } 00727 if(!NyLPC_iHttpPtrStream_write(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),i_buf,i_len)){ 00728 //CLOSE 00729 NyLPC_OnErrorGoto(Error); 00730 } 00731 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00732 return NyLPC_TBool_TRUE; 00733 Error: 00734 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00735 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00736 return NyLPC_TBool_FALSE; 00737 } 00738 00739 void NyLPC_cModWebSocket_close(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TUInt16 i_code) 00740 { 00741 //ストリームの状態を更新する。 00742 NyLPC_cModWebSocket_update(i_inst,0); 00743 00744 if(i_inst->_payload_st==NyLPC_TcModWebSocket_ST_CLOSED){ 00745 return; 00746 } 00747 //CLOSE送信 00748 writeClosePacket(i_inst,i_code); 00749 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00750 //切断 00751 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00752 } 00753 00754 00755 NyLPC_TInt16 NyLPC_cModWebSocket_testFormatV(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,va_list args) 00756 { 00757 return NyLPC_cFormatWriter_length(i_fmt,args); 00758 } 00759 NyLPC_TInt16 NyLPC_cModWebSocket_testFormat(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,...) 00760 { 00761 NyLPC_TInt16 r; 00762 va_list a; 00763 va_start(a,i_fmt); 00764 r=NyLPC_cFormatWriter_length(i_fmt,a); 00765 va_end(a); 00766 return r; 00767 } 00768 00769 00770 NyLPC_TBool NyLPC_cModWebSocket_startBulkWrite(NyLPC_TcModWebSocket_t* i_inst,NyLPC_TInt16 i_len) 00771 { 00772 //ストリームの状態を更新する。 00773 NyLPC_cModWebSocket_update(i_inst,0); 00774 //ペイロードヘッダの出力 00775 if(!NyLPC_cModWebSocket_writePayloadHeader(i_inst,i_len)){ 00776 //CLOSE 00777 NyLPC_OnErrorGoto(Error); 00778 } 00779 return NyLPC_TBool_TRUE; 00780 Error: 00781 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00782 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00783 return NyLPC_TBool_FALSE; 00784 } 00785 /** 00786 * バルク書き込みを終了します。 00787 * この関数をコールする前に、startBulkWrite関数のi_lenで指定した大きさのデータを入力し終えている必要があります。 00788 * 過不足があった場合、関数は失敗するか、WebSocketセッションが破壊されます。 00789 */ 00790 NyLPC_TBool NyLPC_cModWebSocket_endBulkWrite(NyLPC_TcModWebSocket_t* i_inst) 00791 { 00792 if(i_inst->_payload_st==NyLPC_TcModWebSocket_ST_CLOSED){ 00793 return NyLPC_TBool_FALSE; 00794 } 00795 //送信サイズ確認? 00796 NyLPC_iHttpPtrStream_flush(NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection)); 00797 return NyLPC_TBool_TRUE; 00798 } 00799 00800 NyLPC_TBool NyLPC_cModWebSocket_writeBulkFormatV(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,va_list args) 00801 { 00802 if(i_inst->_payload_st==NyLPC_TcModWebSocket_ST_CLOSED){ 00803 return NyLPC_TBool_FALSE; 00804 } 00805 if(!NyLPC_cFormatWriter_print(fmt_handler,NyLPC_cHttpdConnection_refStream(i_inst->_ref_connection),i_fmt,args)){ 00806 NyLPC_OnErrorGoto(Error); 00807 } 00808 return NyLPC_TBool_TRUE; 00809 Error: 00810 NyLPC_cHttpdConnection_closeSocket(i_inst->_ref_connection); 00811 i_inst->_payload_st=NyLPC_TcModWebSocket_ST_CLOSED; 00812 return NyLPC_TBool_FALSE; 00813 } 00814 NyLPC_TBool NyLPC_cModWebSocket_writeBulkFormat(NyLPC_TcModWebSocket_t* i_inst,const NyLPC_TChar* i_fmt,...) 00815 { 00816 NyLPC_TBool ret; 00817 va_list a; 00818 va_start(a,i_fmt); 00819 ret=NyLPC_cModWebSocket_writeBulkFormatV(i_inst,i_fmt,a); 00820 va_end(a); 00821 return ret; 00822 }
Generated on Tue Jul 12 2022 15:46:16 by 1.7.2