// ------------------------------------------------------------------------------------ public void Expand_WS_buf() { m_rem_ui16 += (WS_Buf_Pool.Expand_MemBlk(ref m_ary_buf) >> 1); if (m_idx_byte + (m_rem_ui16 << 1) != m_ary_buf.Length) //// エラー顕在化 { throw new Exception("Write_WS_Buffer.Expand_WS_buf() : m_idx_byte + (m_rem_ui16 << 1) != m_ary_buf.Length"); } }
// ------------------------------------------------------------------------------------ public void Copy_bytes_from(byte[] ary_buf_src) { if ((ary_buf_src.Length & 1) == 1) { // idx_byte が奇数である場合はエラーとする throw new Exception("Write_WS_Buffer.Set_idx_byte() : ary_buf_src.Length が奇数となっています。"); } int len_src_u16 = (ary_buf_src.Length >> 1); while (m_rem_ui16 < len_src_u16) // ここでは、大きなサイズのコピーが発生しても大丈夫なようにしている { // Expand_MemBlk の戻り値は、増加された「バイト数」 m_rem_ui16 += (WS_Buf_Pool.Expand_MemBlk(ref m_ary_buf) >> 1); if (m_idx_byte + (m_rem_ui16 << 1) != m_ary_buf.Length) //// エラー顕在化 { throw new Exception("Write_WS_Buffer.Copy_bytes_from() : m_idx_byte + m_rem_ui16 != m_ary_buf.Length"); } } // m_rem_ui16 の値は先に決定しておく m_rem_ui16 -= len_src_u16; unsafe { fixed(byte *pdst_byte_top = m_ary_buf) fixed(byte *psrc_byte_top = ary_buf_src) { ushort *pdst_u16 = (ushort *)(pdst_byte_top + m_idx_byte); ushort *psrc_u16 = (ushort *)psrc_byte_top; for (; len_src_u16 > 0; --len_src_u16) { *pdst_u16++ = *psrc_u16++; } m_idx_byte = (int)(((byte *)pdst_u16) - pdst_byte_top); } } }
// ------------------------------------------------------------------------------------ // 1行分の文字数をカウントして、バッファを確保する。 // 必要となる最大バッファサイズは、 // 文字数+3(先頭の ID_Text or ID_TR, ID_TD, ID_Text)+1(` の未ペアがあった場合) // +2*「| の個数(TD、ID_Text)」+(Chr.PCS_Tab - 1)*TABの個数 public unsafe void SecureBuf_for1Line(ushort *psrc) { ushort *psrc_top = psrc; int pcs_add = 0; while (true) { switch (*psrc) { case Chr.CR: case Chr.LF: goto LOOP_OUT; case Chr.TAB: pcs_add += (Chr.PCS_Tab - 1); break; case '|': pcs_add += 2; break; } psrc++; } LOOP_OUT: // 本当は +4 でいいが、余裕をみて +10 としている int pcs_to_need = (int)(psrc - psrc_top) + 10 + pcs_add; if (m_rem_ui16 < pcs_to_need) { m_rem_ui16 += (WS_Buf_Pool.Expand_MemBlk(ref m_ary_buf) >> 1); if (m_idx_byte + (m_rem_ui16 << 1) != m_ary_buf.Length) //// エラー顕在化 { throw new Exception("Write_WS_Buffer.SecureBuf_for1Line() : m_idx_byte + m_rem_ui16 != m_ary_buf.Length"); } } }
// m_ary_buf に書き込まれる内容 // ID_ERR_Report -> ID_Div -> ID_Text -> err_msg -> ID_Div -> ID_Text -> psrc からの EN_MAX_ERR_Text 文字数分の内容 // err_msg は、クライアントと、サーバー側の StdOut に送られるメッセージ // psrc は MD ファイル側のポインタで fixed されている // 注意: バッファの拡張をする場合があるため、m_ary_buf は fixed されていてはならない public unsafe void CrtErrReport_to_WrtBuf_and_ThrowErr(ushort *psrc, string err_msg) { // +10 は念のためのマージン int max_len_u16_to_wrt_buf = 1 + 1 + 2 + err_msg.Length + 1 + 2 + EN_MAX_ERR_Text + 10; if (m_rem_ui16 < max_len_u16_to_wrt_buf) { // Expand_MemBlk の戻り値は、増加された「バイト数」 m_rem_ui16 += (WS_Buf_Pool.Expand_MemBlk(ref m_ary_buf) >> 1); if (m_idx_byte + (m_rem_ui16 << 1) != m_ary_buf.Length) //// エラー顕在化 { throw new Exception( "Write_WS_Buffer.CrtErrReport_to_WrtBuf_and_ThrowErr() : m_idx_byte + m_rem_ui16 != m_ary_buf.Length"); } } unsafe { fixed(byte *pdst_top = m_ary_buf) { ushort *pdst = (ushort *)(pdst_top + m_idx_byte); // err_msg の埋め込み { int len_err_msg = err_msg.Length; *pdst = (ushort)ID.ERR_Report; // このブロックで8バイト *(pdst + 1) = (ushort)ID.Div; *(pdst + 2) = (ushort)ID.Text; *(pdst + 3) = (ushort)len_err_msg; pdst += 4; fixed(char *pmsg_top = err_msg) { ushort *pmsg = (ushort *)pmsg_top; for (; len_err_msg > 0; --len_err_msg) { *pdst++ = *pmsg++; } } } // エラーを特定しやすいように、クライアントに psrc からの文字列を送出する // psrc は '\0' で終了していることに留意する ushort *pTmnt_dst = pdst + EN_MAX_ERR_Text; *pdst = (ushort)ID.Div; *(pdst + 1) = (ushort)ID.Text; ushort *ptr_at_pos_text_len = pdst + 2; pdst += 3; while (true) { ushort chr = *psrc++; if (pdst == pTmnt_dst || chr == 0) { break; } /* * if (chr == Chr.CR) { *pdst++ = (ushort)ID.BR; psrc++; continue; } * if (chr == Chr.LF) { *pdst++ = (ushort)ID.BR; continue; } */ *pdst++ = chr; } *ptr_at_pos_text_len = (ushort)((pdst - ptr_at_pos_text_len) - 1); // 文字数の書き込み m_idx_byte = (int)(((byte *)pdst) - pdst_top); m_rem_ui16 = (m_ary_buf.Length - m_idx_byte) >> 1; } } this.Wrt_ID_End(); throw new Exception(err_msg); }
// ------------------------------------------------------------------------------------ public async Task Spawn_Context(HttpListenerContext context, uint idx_context) { // AcceptWebSocketAsync() は、キャンセルトークンをサポートしていない // 引数: サポートされている WebSocket サブプロトコル HttpListenerWebSocketContext wsc = await context.AcceptWebSocketAsync(null); MainForm.StdOut("--- WebSocket 接続完了\r\n"); using (m_WS = wsc.WebSocket) using (WS_Buf_Pool.MemBlock mem_blk = WS_Buf_Pool.Lease_MemBlock()) { m_read_WS_buf = new Read_WS_Buf(mem_blk.m_ary_buf); m_write_WS_buf = new Write_WS_Buffer(mem_blk.m_ary_buf); try { // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #if CREATE_TEST_LEXED_CODE // Test Lexed Code を送信する Write_WS_Buffer write_ws_buf = MainForm.ms_DBG_write_WS_buf; await m_WS.SendAsync( new ArraySegment <byte>(write_ws_buf.Get_buf(), 0, write_ws_buf.Get_idx_byte_cur()) , WebSocketMessageType.Binary, true, ms_cts_shutdown.Token); #else // まずはルートフォルダのファイル情報を送信しておく FileLister.Set_DirFileNames(m_write_WS_buf, "./"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); #endif while (true) { WebSocketReceiveResult rslt = await m_WS.ReceiveAsync( new ArraySegment <byte>(mem_blk.m_ary_buf), ms_cts_shutdown.Token); if (rslt.EndOfMessage == false) { MainForm.StdOut("--- 不正な大きさのデータを受信しました。クライアントを切断します\r\n"); break; } if (m_WS.State == WebSocketState.CloseReceived) { MainForm.StdOut("--- クライアントが接続を Close しました\r\n"); break; } m_read_WS_buf.Renew(rslt.Count); switch (m_read_WS_buf.Read_ID()) { case ID.DirFileList: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 DirFileList / id -> {((byte)id).ToString()}"); } FileLister.Set_DirFileNames(m_write_WS_buf, m_read_WS_buf.Get_text_cur()); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.Files_inDir: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } string str_path_dir = m_read_WS_buf.Get_text_cur(); id = m_read_WS_buf.Read_ID(); if (id != ID.Num_int) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } int SEC_Updated_recv = m_read_WS_buf.Get_Num_int(); FileLister.OnFiles_inDir(m_write_WS_buf, str_path_dir, SEC_Updated_recv); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.MD_file: { var(path_md_file, SEC_Updated, idx_byte_SEC_updated) = m_read_WS_buf.Read_Req_MD(); MainForm.StdOut($"path_md_file : {path_md_file} / SEC_Updated : {SEC_Updated.ToString()}\r\n"); // ID.MD_file -> ID_Text (path_dir) -> ID_Text (file name) は Receive時の値を流用 m_write_WS_buf.Set_idx_byte(idx_byte_SEC_updated); m_write_WS_buf.Wrt_Num_int(1000); // 1000 は試験値 Lexer.LexFile(m_write_WS_buf, path_md_file); MainForm.StdOut("--- Lexing 処理完了\r\n"); m_write_WS_buf.Simplify_Buf(); MainForm.StdOut("--- Simplify_Buf 処理完了\r\n"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; } MainForm.StdOut($"--- ReceiveAsync() : 受信バイト数 -> {rslt.Count}\r\n"); MainForm.HexDump(mem_blk.m_ary_buf, 0, 20); DBG_WS_Buffer.Show_WS_buf(MainForm.ms_RBox_stdout, mem_blk.m_ary_buf, rslt.Count); // 今は、index.md のみを解析するようにしている // string ret_str = Lexer.LexFile(m_write_WS_buf, "md_root/index.md"); // string str_recv = ms_utf16_encoding.GetString(mem_blk.m_ary_buf, 0, rslt.Count); // MainForm.StdOut(str_recv); } await m_WS.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "接続を終了します", ms_cts_shutdown.Token); } catch (OperationCanceledException) { MainForm.StdOut("--- サーバーシャットダウンのシグナルを受信しました\r\n"); } catch (WebSocketException ex) { MainForm.StdOut($"!!! 例外発を補足しました WebSoketErrorCode : {ex.WebSocketErrorCode.ToString()}\r\n"); MainForm.StdOut($" {ex.ToString()}\r\n"); } catch (Exception ex) { MainForm.StdOut($"!!! 例外を補足しました : {ex.ToString()}\r\n"); } } MdSvr.Remove_task_context(idx_context); MainForm.StdOut("--- WebSocket 切断完了\r\n"); }