Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of libMiMic by
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 16:22:58 by
1.7.2
