This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088

Dependents:   MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NyLPC_cModWebSocket.c Source File

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 }