public void TestMethod3() { byte[] buffer = Convert.FromBase64String("41YAAAABEKq7zN3u/wARIjNEVWZ3iJkBAAAAJoUGAAAAAgEAAQYAbXlkZWFyAwEAETwAAAADAQD57BfsFwMBAPoeQhM0AwEA/rQBAAADAQDuDOmJFAAAAA=="); // 分析请求包 BerTree tree1 = new BerTree(); tree1.m_RootNode.BuildPartTree(buffer, 0, buffer.Length, out int nTotallen); BerNode root = tree1.GetAPDuRoot(); switch (root.m_uTag) { case BerTree.z3950_initRequest: break; case BerTree.z3950_searchRequest: break; case BerTree.z3950_presentRequest: break; } }
// 默认的请求处理过程。应可以被重新指定 // 下级函数,例如处理 Initialize Search Present 的函数,还可以被重新指定 public async Task <byte[]> DefaultProcessRequest(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); switch (root.m_uTag) { case BerTree.z3950_initRequest: if (this.ProcessInitialize == null) { return(await DefaultProcessInitialize(channel, request).ConfigureAwait(false)); // 2018/10/10 add configure } else { ProcessInitializeEventArgs e = new ProcessInitializeEventArgs(); e.Request = request; this.ProcessInitialize(channel, e); return(e.Response); } break; case BerTree.z3950_searchRequest: if (this.ProcessSearch == null) { return(await DefaultProcessSearch(channel, request).ConfigureAwait(false)); // 2018/10/10 add configure } else { ProcessSearchEventArgs e = new ProcessSearchEventArgs(); e.Request = request; this.ProcessSearch(channel, e); return(e.Response); } break; case BerTree.z3950_presentRequest: if (this.ProcessPresent == null) { return(await DefaultProcessPresent(channel, request).ConfigureAwait(false)); // 2018/10/10 add configure } else { ProcessPresentEventArgs e = new ProcessPresentEventArgs(); e.Request = request; this.ProcessPresent(channel, e); return(e.Response); } break; } return(new byte[0]); // TODO 如果将来嫌日志中记载 BerNode Dump 结果体积太大,Dump 结果可以考虑不进入日志 //string text = JsonConvert.SerializeObject(root, Formatting.Indented); //throw new UnknownApduException(string.Format("无法识别的 APDU tag[{0}]\r\nBerNode={1}", root.m_uTag, text)); }
public async Task <byte[]> DefaultProcessPresent(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); // 解码Search请求包 int nRet = ZProcessor.Decode_PresentRequest( root, out PresentRequestInfo info, out string strError); if (nRet == -1) { goto ERROR1; } if (channel.EnsureProperty()._bInitialized == false) { return(null); } PresentGetRecordsEventArgs e = new PresentGetRecordsEventArgs(); if (this.PresentGetRecords == null) { // 模拟返回一条记录 e.Records = new List <RetrivalRecord>(); RetrivalRecord record = new RetrivalRecord(); // TODO: 准备数据 e.Records.Add(record); } else { e.Request = info; this.PresentGetRecords(channel, e); } // 编码Present响应包 nRet = ZProcessor.Encode_PresentResponse(info, e.Records, e.Diag, e.TotalCount, out byte[] baResponsePackage); if (nRet == -1) { goto ERROR1; } return(baResponsePackage); ERROR1: // TODO: 将错误原因写入日志 return(null); }
public void TestMethod1() { BerTree tree = new BerTree(); BerNode root = null; root = tree.m_RootNode.NewChildConstructedNode( BerTree.z3950_presentResponse, BerNode.ASN1_CONTEXT); byte[] baPackage = null; root.EncodeBERPackage(ref baPackage); }
public async Task <byte[]> DefaultProcessSearch(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); // 解码Search请求包 int nRet = ZProcessor.Decode_SearchRequest( root, out SearchRequestInfo info, out string strError); if (nRet == -1) { goto ERROR1; } if (channel.EnsureProperty()._bInitialized == false) { return(null); } SearchSearchEventArgs e = new SearchSearchEventArgs(); e.Request = info; if (this.SearchSearch == null) { // 返回模拟的结果,假装命中了一条记录 e.Result = new ZClient.SearchResult { Value = 1 }; } else { this.SearchSearch(channel, e); } // 编码Search响应包 nRet = ZProcessor.Encode_SearchResponse(info, e.Result, e.Diag, out byte[] baResponsePackage, out strError); if (nRet == -1) { goto ERROR1; } return(baResponsePackage); ERROR1: // TODO: 将错误原因写入日志 return(null); }
// 处理 Server 端可能发来的 Close // return value: // -1 error // 0 不是Close // 1 是Close,已经迫使ZChannel处于尚未初始化状态 // return InitialResult: // 在 InitialResult::ResultInfo 中返回诊断信息 async Task <InitialResult> CheckServerCloseRequest() { if (this._channel.Connected == false || this._channel.DataAvailable == false) { return(new InitialResult()); // 没有发现问题 } // 注意调用返回后如果发现出错,调主要主动 Close 和重新分配 TcpClient RecvResult result = await ZChannel.SimpleRecvTcpPackage(this._channel._client, -1).ConfigureAwait(false); if (result.Value == -1) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = result.ErrorInfo }); } BerTree tree1 = new BerTree(); // TODO: 这里需要捕获异常,然后把 Package Dump 到日志文件(base64 形态),便于事后分析调试 tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); if (tree1.GetAPDuRoot().m_uTag != BerTree.z3950_close) { // 不是Close return(new InitialResult { Value = 0 }); } CLOSE_REQUEST closeStruct = new CLOSE_REQUEST(); int nRet = BerTree.GetInfo_closeRequest( tree1.GetAPDuRoot(), ref closeStruct, out string strError); if (nRet == -1) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = strError }); } this.CloseConnection(); return(new InitialResult { Value = 1, ResultInfo = closeStruct.m_strDiagnosticInformation }); }
// 默认的请求处理过程。应可以被重新指定 // 下级函数,例如处理 Initialize Search Present 的函数,还可以被重新指定 public async Task <byte[]> DefaultProcessRequest(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); switch (root.m_uTag) { case BerTree.z3950_initRequest: if (this.ProcessInitialize == null) { return(await DefaultProcessInitialize(channel, request)); } else { ProcessInitializeEventArgs e = new ProcessInitializeEventArgs(); e.Request = request; this.ProcessInitialize(channel, e); return(e.Response); } break; case BerTree.z3950_searchRequest: if (this.ProcessSearch == null) { return(await DefaultProcessSearch(channel, request)); } else { ProcessSearchEventArgs e = new ProcessSearchEventArgs(); e.Request = request; this.ProcessSearch(channel, e); return(e.Response); } break; case BerTree.z3950_presentRequest: if (this.ProcessPresent == null) { return(await DefaultProcessPresent(channel, request)); } else { ProcessPresentEventArgs e = new ProcessPresentEventArgs(); e.Request = request; this.ProcessPresent(channel, e); return(e.Response); } break; } return(new byte[0]); }
// 处理 Server 端可能发来的 Close // return value: // -1 error // 0 不是Close // 1 是Close,已经迫使ZChannel处于尚未初始化状态 // return InitialResult: // 在 InitialResult::ResultInfo 中返回诊断信息 async Task <InitialResult> CheckServerCloseRequest() { if (this._channel.Connected == false || this._channel.DataAvailable == false) { return(new InitialResult()); // 没有发现问题 } RecvResult result = await this._channel.SimpleRecvTcpPackage(); if (result.Value == -1) { return new InitialResult { Value = -1, ErrorInfo = result.ErrorInfo } } ; BerTree tree1 = new BerTree(); tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); if (tree1.GetAPDuRoot().m_uTag != BerTree.z3950_close) { // 不是Close return(new InitialResult { Value = 0 }); } CLOSE_REQUEST closeStruct = new CLOSE_REQUEST(); int nRet = BerTree.GetInfo_closeRequest( tree1.GetAPDuRoot(), ref closeStruct, out string strError); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = strError } } ; this.CloseConnection(); return(new InitialResult { Value = 1, ResultInfo = closeStruct.m_strDiagnosticInformation }); }
public static string BuildInitialResultInfo(INIT_RESPONSE info) { string strText = ""; strText += "reference-id:\t" + info.m_strReferenceId + "\r\n"; strText += "options:\t" + info.m_strOptions + "\r\n"; strText += "preferred-message-size:\t" + info.m_lPreferredMessageSize.ToString() + "\r\n"; strText += "exceptional-record-size:\t" + info.m_lExceptionalRecordSize.ToString() + "\r\n"; strText += "\r\n--- Result Code ---\r\n"; strText += "initial-result:\t" + info.m_nResult.ToString() + "\r\n"; strText += "\r\n--- Implementation information ---\r\n"; strText += "implementation-id:\t" + info.m_strImplementationId + "\r\n"; strText += "implementation-name:\t" + info.m_strImplementationName + "\r\n"; strText += "implementation-version:\t" + info.m_strImplementationVersion + "\r\n"; strText += "\r\n--- Error Code and Message ---\r\n"; strText += "error-code:\t" + info.m_lErrorCode.ToString() + "\r\n"; strText += "error-messsage:\t" + info.m_strErrorMessage + "\r\n"; if (info.m_charNego != null) { strText += "\r\n--- Charset Negotiation Parameters ---\r\n"; if (BerTree.GetBit(info.m_strOptions, 17) == false) { strText += "options bit 17 is false, not allow negotiation\r\n"; } strText += "charnego-encoding-level-oid:\t" + info.m_charNego.EncodingLevelOID + "(note: UTF-8 is: " + CharsetNeogatiation.Utf8OID + ")\r\n"; strText += "charnego-records-in-selected-charsets:\t" + info.m_charNego.RecordsInSelectedCharsets.ToString() + "\r\n"; } return(strText); }
// 处理一个通道的通讯活动 public async override void HandleClient(TcpClient tcpClient, Action close_action, CancellationToken token) { List <byte> cache = new List <byte>(); ZServerChannel channel = _tcpChannels.Add(tcpClient, () => { return(new ZServerChannel()); }) as ZServerChannel; // 允许对 channel 做额外的初始化 if (this.ChannelOpened != null) { this.ChannelOpened(channel, new EventArgs()); } try { string ip = ""; try { ip = GetClientIP(tcpClient); channel.Touch(); int i = 0; bool running = true; while (running) { if (token != null && token.IsCancellationRequested) { return; } // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient BerTree request = await ZProcessor.GetIncomingRequest( cache, tcpClient, () => channel.Touch()).ConfigureAwait(false); // 2018/10/10 add configure if (request == null) { Console.WriteLine("client close on request " + i); break; } Console.WriteLine("request " + i); channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } byte[] response = null; if (this.ProcessRequest == null) { response = await DefaultProcessRequest(channel, request).ConfigureAwait(false); // 2018/10/10 add configure } else { ProcessRequestEventArgs e = new ProcessRequestEventArgs(); e.Request = request; this.ProcessRequest(channel, e); response = e.Response; } channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient Result result = await ZProcessor.SendResponse(response, tcpClient).ConfigureAwait(false); // 2018/10/10 add configure channel.Touch(); if (result.Value == -1) { Console.WriteLine("error on response " + i + ": " + result.ErrorInfo); break; } i++; } } catch (Exception ex) { if (ex.InnerException != null && ex.InnerException is ObjectDisposedException) { // 这种情况一般是 server 主动清理闲置通道导致的,不记入日志 } else if (ex is ObjectDisposedException) { // 这种情况一般是 client close 通道导致,不记入日志 } else { string strName = "ip:" + ip + channel == null ? "(null)" : " channel:" + channel.GetHashCode(); string strError = strName + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex); LibraryManager.Log?.Error(strError); // Console.WriteLine(strError); } } finally { #if NO outputStream.Flush(); outputStream.Close(); outputStream = null; inputStream.Close(); inputStream = null; #endif // tcpClient.Close(); // 清除全局结果集 } } finally { _tcpChannels.Remove(channel); #if NO if (this.ChannelClosed != null) { ChannelClosedEventArgs e = new ChannelClosedEventArgs(); e.Channel = channel; this.ChannelClosed(channel, e); } #endif channel.Close(); if (close_action != null) { close_action.Invoke(); } } }
// return: // -1 error // 0 fail // 1 succeed int DoSearch( ZConnection connection, string strQuery, Encoding queryTermEncoding, string[] dbnames, string strResultSetName, out int nResultCount, out string strError) { strError = ""; BerTree tree = new BerTree(); SEARCH_REQUEST struSearch_request = new SEARCH_REQUEST(); byte[] baPackage = null; int nRet; int nRecvLen; //int nMax; //int i; // --> BerTree tree1 = new BerTree(); int nTotlen = 0; nResultCount = 0; struSearch_request.m_dbnames = dbnames; Debug.Assert(struSearch_request.m_dbnames.Length != 0, ""); struSearch_request.m_strReferenceId = this.CurrentRefID; struSearch_request.m_lSmallSetUpperBound = 0; struSearch_request.m_lLargeSetLowerBound = 1; struSearch_request.m_lMediumSetPresentNumber = 0; struSearch_request.m_nReplaceIndicator = 1; struSearch_request.m_strResultSetName = strResultSetName; // "default"; struSearch_request.m_strSmallSetElementSetNames = ""; struSearch_request.m_strMediumSetElementSetNames = ""; struSearch_request.m_strPreferredRecordSyntax = ZTargetControl.GetLeftValue(this.comboBox_recordSyntax.Text); // this.CurrentTargetInfo.PreferredRecordSyntax; // BerTree.MARC_SYNTAX; struSearch_request.m_strQuery = strQuery; struSearch_request.m_nQuery_type = 1; struSearch_request.m_queryTermEncoding = queryTermEncoding; // m_search_response.m_lErrorCode = 0; nRet = tree.SearchRequest(struSearch_request, out baPackage); if (nRet == -1) { strError = "CBERTree::SearchRequest() fail!"; return -1; } #if NOTCPIP if (m_hSocket == INVALID_SOCKET) { strError = "socket已经关闭!"; return -1; } #endif #if DUMPTOFILE string strBinFile = this.MainForm.DataDir + "\\searchrequest.bin"; File.Delete(strBinFile); DumpPackage(strBinFile, baPackage); string strLogFile = this.MainForm.DataDir + "\\searchrequest.txt"; File.Delete(strLogFile); tree.m_RootNode.DumpToFile(strLogFile); #endif nRet = CheckConnect( connection, out strError); if (nRet == -1) return -1; /* nRet = this.ZChannel.SendTcpPackage( baPackage, baPackage.Length, out strError); if (nRet == -1 || nRet == 1) { // CloseZAssociation(); return -1; } //AfxMessageBox("发送成功"); baPackage = null; nRet = this.ZChannel.RecvTcpPackage( out baPackage, out nRecvLen, out strError); if (nRet == -1) { // CloseZAssociation(); return -1; } * */ byte [] baOutPackage = null; nRet = connection.ZChannel.SendAndRecv( baPackage, out baOutPackage, out nRecvLen, out strError); if (nRet == -1) return -1; #if DEBUG if (nRet == 0) { Debug.Assert(strError == "", ""); } #endif #if DUPMTOFILE DeleteFile("searchresponse.bin"); DumpPackage("searchresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(baOutPackage, 0, baOutPackage.Length, out nTotlen); SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); nRet = BerTree.GetInfo_SearchResponse(tree1.GetAPDuRoot(), ref search_response, true, out strError); if (nRet == -1) return -1; #if DUMPTOFILE DeleteFile("SearchResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("SearchResponse.txt"); #endif /* nRet = FitDebugInfo_SearchResponse(&tree1, strError); if (nRet == -1) { AfxMessageBox(strError); return; } */ nResultCount = (int)search_response.m_lResultCount; if (search_response.m_nSearchStatus != 0) // 不一定是1 return 1; strError = "Search Fail: diagRecords:\r\n" + search_response.m_diagRecords.GetMessage(); return 0; // search fail }
// 获得记录 // 不确保一定可以获得nCount个 // parameters: // nStart 开始记录(从0计算) int DoOncePresent( ZConnection connection, string strResultSetName, int nStart, int nCount, string strElementSetName, string strPreferredRecordSyntax, out RecordCollection records, out string strError) { records = null; strError = ""; if (nCount == 0) { strError = "nCount为0"; return 0; } BerTree tree = new BerTree(); PRESENT_REQUEST struPresent_request = new PRESENT_REQUEST(); byte[] baPackage = null; int nRet; int nRecvLen; // --> BerTree tree1 = new BerTree(); int nTotlen = 0; struPresent_request.m_strReferenceId = this.CurrentRefID; struPresent_request.m_strResultSetName = strResultSetName; // "default"; struPresent_request.m_lResultSetStartPoint = nStart + 1; struPresent_request.m_lNumberOfRecordsRequested = nCount; struPresent_request.m_strElementSetNames = strElementSetName; struPresent_request.m_strPreferredRecordSyntax = strPreferredRecordSyntax; nRet = tree.PresentRequest(struPresent_request, out baPackage); if (nRet == -1) { strError = "CBERTree::PresentRequest() fail!"; return -1; } #if DUMPTOFILE DeleteFile("presentrequest.bin"); DumpPackage("presentrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile ("presentrequest.txt"); tree.m_RootNode.DumpToFile("presentrequest.txt"); #endif nRet = CheckConnect( connection, out strError); if (nRet == -1) return -1; /* nRet = this.ZChannel.SendTcpPackage( baPackage, baPackage.Length, out strError); if (nRet == -1 || nRet == 1) { // CloseZAssociation(); return -1; } ////////////// baPackage = null; nRet = this.ZChannel.RecvTcpPackage( out baPackage, out nRecvLen, out strError); if (nRet == -1) { // CloseZAssociation(); goto ERROR1; } * */ byte [] baOutPackage = null; nRet = connection.ZChannel.SendAndRecv( baPackage, out baOutPackage, out nRecvLen, out strError); if (nRet == -1) return -1; #if DUMPTOFILE DeleteFile("presendresponse.bin"); DumpPackage("presentresponse.bin", (char *)baPackage.GetData(), baPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(baOutPackage, 0, baOutPackage.Length, out nTotlen); #if DUMPTOFILE DeleteFile("PresentResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("PresentResponse.txt"); #endif SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); nRet = BerTree.GetInfo_PresentResponse(tree1.GetAPDuRoot(), ref search_response, out records, true, out strError); if (nRet == -1) goto ERROR1; /* nRet = FitDebugInfo_PresentResponse(&tree1, strError); if (nRet == -1) { goto ERROR1; } DeleteFile("PresentResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("PresentResponse.txt"); */ if (search_response.m_diagRecords.Count != 0) { /* string strDiagText; string strAddInfo; nRet = GetDiagTextByNumber("bib1diag.txt", m_search_response.m_nDiagCondition, strDiagText, strAddInfo, strError); if (nRet == -1) { if (this->m_bAllowMessageBox) AfxMessageBox(strError); return -1; } if (strDiagText.GetLength()) strError = strDiagText; else strError.Format("diag condition[%d] diag set id[%s]", m_search_response.m_nDiagCondition, m_search_response.m_strDiagSetID); * */ strError = "error diagRecords:\r\n\r\n---\r\n" + search_response.m_diagRecords.GetMessage(); return -1; } return 0; ERROR1: return -1; }
public /*async*/ Task <byte[]> DefaultProcessInitialize(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); Encoding encoding = Encoding.GetEncoding(936); REDO: int nRet = ZProcessor.Decode_InitRequest( root, encoding, out InitRequestInfo info, out string strDebugInfo, out string strError); if (nRet == -1) { goto ERROR1; } // 可以用groupid来表示字符集信息 InitResponseInfo response_info = new InitResponseInfo(); if (info.m_charNego != null) { /* option * * search (0), * present (1), * delSet (2), * resourceReport (3), * triggerResourceCtrl (4), * resourceCtrl (5), * accessCtrl (6), * scan (7), * sort (8), * -- (9) (reserved) * extendedServices (10), * level-1Segmentation (11), * level-2Segmentation (12), * concurrentOperations (13), * namedResultSets (14) * 15 Encapsulation Z39.50-1995 Amendment 3: Z39.50 Encapsulation * 16 resultCount parameter in Sort Response See Note 8 Z39.50-1995 Amendment 1: Add resultCount parameter to Sort Response * 17 Negotiation Model See Note 9 Model for Z39.50 Negotiation During Initialization * 18 Duplicate Detection See Note 1 Z39.50 Duplicate Detection Service * 19 Query type 104 * } */ response_info.m_strOptions = "yynnnnnnnnnnnnn"; if (info.m_charNego.EncodingLevelOID == CharsetNeogatiation.Utf8OID) { BerTree.SetBit(ref response_info.m_strOptions, 17, true); response_info.m_charNego = info.m_charNego; // 2018/9/19 // 如果最初解码用的编码方式不是 UTF8,则需要重新解码 if (encoding != Encoding.UTF8) { encoding = Encoding.UTF8; goto REDO; } channel.EnsureProperty()._searchTermEncoding = Encoding.UTF8; if (info.m_charNego.RecordsInSelectedCharsets != -1) { response_info.m_charNego.RecordsInSelectedCharsets = info.m_charNego.RecordsInSelectedCharsets; // 依从前端的请求 if (response_info.m_charNego.RecordsInSelectedCharsets == 1) { channel.EnsureProperty()._marcRecordEncoding = Encoding.UTF8; } } } } else { response_info.m_strOptions = "yynnnnnnnnnnnnn"; } // 判断info中的信息,决定是否接受Init请求。 // ZServerChannel 初始化设置一些信息。这样它一直携带着伴随生命周期全程 Result result = AutoSetChannelProperty(channel, info); if (result.Value == -1) { response_info.m_nResult = 0; channel.EnsureProperty()._bInitialized = false; ZProcessor.SetInitResponseUserInfo(response_info, "1.2.840.10003.4.1", // string strOID, string.IsNullOrEmpty(result.ErrorCode) ? 100 : Convert.ToInt32(result.ErrorCode), // (unspecified) error result.ErrorInfo); goto DO_RESPONSE; } #if NO if (String.IsNullOrEmpty(info.m_strID) == true) { ZConfig config = AutoGetZConfig(channel, info, out strError); if (config == null) { ZProcessor.SetInitResponseUserInfo(response_info, "", // string strOID, 0, // long lErrorCode, strError); goto DO_RESPONSE; } // 如果定义了允许匿名登录 if (String.IsNullOrEmpty(config.AnonymousUserName) == false) { info.m_strID = config.AnonymousUserName; info.m_strPassword = config.AnonymousPassword; } else { response_info.m_nResult = 0; channel.SetProperty()._bInitialized = false; ZProcessor.SetInitResponseUserInfo(response_info, "", // string strOID, 0, // long lErrorCode, "不允许匿名登录"); goto DO_RESPONSE; } } #endif if (this.InitializeLogin != null) { InitializeLoginEventArgs e = new InitializeLoginEventArgs(); this.InitializeLogin(channel, e); if (e.Result.Value == -1 || e.Result.Value == 0) { response_info.m_nResult = 0; channel.EnsureProperty()._bInitialized = false; ZProcessor.SetInitResponseUserInfo(response_info, "1.2.840.10003.4.1", // string strOID, string.IsNullOrEmpty(e.Result.ErrorCode) ? 101 : Convert.ToInt32(e.Result.ErrorCode), // Access-control failure e.Result.ErrorInfo); } else { response_info.m_nResult = 1; channel.EnsureProperty()._bInitialized = true; } } else { response_info.m_nResult = 1; channel.EnsureProperty()._bInitialized = true; } #if NO // 进行登录 // return: // -1 error // 0 登录未成功 // 1 登录成功 nRet = DoLogin(info.m_strGroupID, info.m_strID, info.m_strPassword, out strError); if (nRet == -1 || nRet == 0) { response_info.m_nResult = 0; this._bInitialized = false; ZProcessor.SetInitResponseUserInfo(response_info, "", // string strOID, 0, // long lErrorCode, strError); } else { response_info.m_nResult = 1; channel._bInitialized = true; } #endif DO_RESPONSE: // 填充 response_info 的其它结构 response_info.m_strReferenceId = info.m_strReferenceId; //if (channel._property == null) // channel._property = new ChannelPropterty(); if (info.m_lPreferredMessageSize != 0) { channel.EnsureProperty().PreferredMessageSize = info.m_lPreferredMessageSize; } // 极限 if (channel.EnsureProperty().PreferredMessageSize > ZServerChannelProperty.MaxPreferredMessageSize) { channel.EnsureProperty().PreferredMessageSize = ZServerChannelProperty.MaxPreferredMessageSize; } response_info.m_lPreferredMessageSize = channel.EnsureProperty().PreferredMessageSize; if (info.m_lExceptionalRecordSize != 0) { channel.EnsureProperty().ExceptionalRecordSize = info.m_lExceptionalRecordSize; } // 极限 if (channel.EnsureProperty().ExceptionalRecordSize > ZServerChannelProperty.MaxExceptionalRecordSize) { channel.EnsureProperty().ExceptionalRecordSize = ZServerChannelProperty.MaxExceptionalRecordSize; } response_info.m_lExceptionalRecordSize = channel.EnsureProperty().ExceptionalRecordSize; response_info.m_strImplementationId = "Digital Platform"; response_info.m_strImplementationName = "dp2Capo"; response_info.m_strImplementationVersion = "1.0"; // BerTree tree = new BerTree(); ZProcessor.Encode_InitialResponse(response_info, out byte[] baResponsePackage); return(Task.FromResult(baResponsePackage)); ERROR1: // TODO: 将错误原因写入日志 LibraryManager.Log?.Error(strError); return(null); }
/// <summary> /// Session处理轮回 /// </summary> public void Processing() { int nRet = 0; string strError = ""; try { byte[] baPackage = null; int nLen = 0; byte[] baResponsePackage = null; for (; ; ) { _activateTime = DateTime.Now; // 接收前端请求 nRet = RecvTcpPackage(out baPackage, out nLen, out strError); if (nRet == -1) goto ERROR_NOT_LOG; // 分析请求包 BerTree tree1 = new BerTree(); int nTotlen = 0; tree1.m_RootNode.BuildPartTree(baPackage, 0, baPackage.Length, out nTotlen); BerNode root = tree1.GetAPDuRoot(); switch (root.m_uTag) { case BerTree.z3950_initRequest: { InitRequestInfo info = null; string strDebugInfo = ""; nRet = Decode_InitRequest( root, out info, out strDebugInfo, out strError); if (nRet == -1) goto ERROR1; // 可以用groupid来表示字符集信息 InitResponseInfo response_info = new InitResponseInfo(); // 判断info中的信息,决定是否接受Init请求。 if (String.IsNullOrEmpty(info.m_strID) == true) { // 如果定义了允许匿名登录 if (String.IsNullOrEmpty(this._service.AnonymousUserName) == false) { info.m_strID = this._service.AnonymousUserName; info.m_strPassword = this._service.AnonymousPassword; } else { response_info.m_nResult = 0; this._bInitialized = false; SetInitResponseUserInfo(response_info, "", // string strOID, 0, // long lErrorCode, "不允许匿名登录"); goto DO_RESPONSE; } } // 进行登录 // return: // -1 error // 0 登录未成功 // 1 登录成功 nRet = DoLogin(info.m_strGroupID, info.m_strID, info.m_strPassword, out strError); if (nRet == -1 || nRet == 0) { response_info.m_nResult = 0; this._bInitialized = false; SetInitResponseUserInfo(response_info, "", // string strOID, 0, // long lErrorCode, strError); } else { response_info.m_nResult = 1; this._bInitialized = true; } DO_RESPONSE: // 填充response_info的其它结构 response_info.m_strReferenceId = info.m_strReferenceId; // .m_strID; BUG!!! 2007/11/2 if (info.m_lPreferredMessageSize != 0) this._lPreferredMessageSize = info.m_lPreferredMessageSize; // 极限 if (this._lPreferredMessageSize > MaxPreferredMessageSize) this._lPreferredMessageSize = MaxPreferredMessageSize; response_info.m_lPreferredMessageSize = this._lPreferredMessageSize; if (info.m_lExceptionalRecordSize != 0) this._lExceptionalRecordSize = info.m_lExceptionalRecordSize; // 极限 if (this._lExceptionalRecordSize > MaxExceptionalRecordSize) this._lExceptionalRecordSize = MaxExceptionalRecordSize; response_info.m_lExceptionalRecordSize = this._lExceptionalRecordSize; response_info.m_strImplementationId = "Digital Platform"; response_info.m_strImplementationName = "dp2ZServer"; response_info.m_strImplementationVersion = "1.0"; if (info.m_charNego != null) { /* option * search (0), present (1), delSet (2), resourceReport (3), triggerResourceCtrl (4), resourceCtrl (5), accessCtrl (6), scan (7), sort (8), -- (9) (reserved) extendedServices (10), level-1Segmentation (11), level-2Segmentation (12), concurrentOperations (13), namedResultSets (14) 15 Encapsulation Z39.50-1995 Amendment 3: Z39.50 Encapsulation 16 resultCount parameter in Sort Response See Note 8 Z39.50-1995 Amendment 1: Add resultCount parameter to Sort Response 17 Negotiation Model See Note 9 Model for Z39.50 Negotiation During Initialization 18 Duplicate Detection See Note 1 Z39.50 Duplicate Detection Service 19 Query type 104 * } */ response_info.m_strOptions = "yynnnnnnnnnnnnn"; if (info.m_charNego.EncodingLevelOID == CharsetNeogatiation.Utf8OID) { BerTree.SetBit(ref response_info.m_strOptions, 17, true); response_info.m_charNego = info.m_charNego; this._searchTermEncoding = Encoding.UTF8; if (info.m_charNego.RecordsInSelectedCharsets != -1) { response_info.m_charNego.RecordsInSelectedCharsets = info.m_charNego.RecordsInSelectedCharsets; // 依从前端的请求 if (response_info.m_charNego.RecordsInSelectedCharsets == 1) this._marcRecordEncoding = Encoding.UTF8; } } } else { response_info.m_strOptions = "yynnnnnnnnnnnnn"; } BerTree tree = new BerTree(); nRet = Encode_InitialResponse(response_info, out baResponsePackage); if (nRet == -1) goto ERROR1; } break; case BerTree.z3950_searchRequest: { SearchRequestInfo info = null; // 解码Search请求包 nRet = Decode_SearchRequest( root, out info, out strError); if (nRet == -1) goto ERROR1; if (_bInitialized == false) goto ERROR_NOT_LOG; // 编码Search响应包 nRet = Encode_SearchResponse(info, out baResponsePackage, out strError); if (nRet == -1) goto ERROR1; } break; case BerTree.z3950_presentRequest: { PresentRequestInfo info = null; // 解码Search请求包 nRet = Decode_PresentRequest( root, out info, out strError); if (nRet == -1) goto ERROR1; if (_bInitialized == false) goto ERROR_NOT_LOG; // 编码Present响应包 nRet = Encode_PresentResponse(info, out baResponsePackage); if (nRet == -1) goto ERROR1; } break; default: break; } // 发出响应包 // return: // -1 出错 // 0 正确发出 // 1 发出前,发现流中有未读入的数据 nRet = SendTcpPackage(baResponsePackage, baResponsePackage.Length, out strError); if (nRet == -1) goto ERROR_NOT_LOG; } } catch (ThreadInterruptedException) { // string dummy = e.Message; // Needed for to remove compile warning } catch (Exception x) { /* if(m_clientSocket.Connected) { // SendData("421 Service not available, closing transmission channel\r\n"); // m_pSMTP_Server.WriteErrorLog(x.Message); } else { } * */ strError = "Session Processing()俘获异常: " + ExceptionUtil.GetDebugText(x); goto ERROR1; } finally { _service.RemoveSession(this.SessionID); this.CloseSocket(); } return; ERROR1: // 将strError写入日志 this._service.Log.WriteEntry(strError, EventLogEntryType.Error); return; ERROR_NOT_LOG: // 不写入日志 return; }
async Task <Result> ProcessAndResponse( TcpClient tcpClient, Action close_action, ZServerChannel channel, BerTree request, CancellationToken token) { string name = ""; string ip = ""; bool error = false; try { name = channel.GetDebugName(tcpClient); ip = TcpServer.GetClientIP(tcpClient); byte[] response = null; if (this.ProcessRequest == null) { response = await DefaultProcessRequest(channel, request).ConfigureAwait(false); // 2018/10/10 add configure } else { ProcessRequestEventArgs e = new ProcessRequestEventArgs(); e.Request = request; this.ProcessRequest(channel, e); response = e.Response; } channel.Touch(); if (token != null && token.IsCancellationRequested) { error = true; return(new Result { Value = -1, ErrorInfo = "Cancelled" }); } // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient Result result = await ZProcessor.SendResponse(response, tcpClient).ConfigureAwait(false); // 2018/10/10 add configure channel.Touch(); if (result.Value == -1) { Console.WriteLine("error on response " + name + ": " + result.ErrorInfo); error = true; return(result); } return(new Result()); } catch (Exception ex) { if (ex is UnknownApduException || ex is BadApduException) { IpTable.SetInBlackList(ip, TimeSpan.FromHours(1)); LibraryManager.Log?.Info(string.Format("IP 地址 {0} 已被加入黑名单,时限一个小时", ip)); } if (channel != null) { channel.Close(); if (close_action != null) { close_action.Invoke(); } LogException(ex, channel, name); channel = null; } else { LogException(ex, channel, name); } return(new Result { Value = -1, ErrorInfo = "Cancelled" }); } finally { if (error == true && channel != null) { channel.Close(); if (close_action != null) { close_action.Invoke(); } } } }
// 装载记录索引 int LoadIndex(string strLogFilename, out string strError) { strError = ""; Stream stream = null; try { stream = File.OpenRead(strLogFilename); } catch (Exception ex) { strError = "file '" + strLogFilename + "'open error: " + ex.Message; return(-1); } try { this.treeView_ber.Nodes.Clear(); for (long i = 0; ; i++) { byte[] len_buffer = new byte[8]; int nRet = stream.Read(len_buffer, 0, 8); if (nRet == 0) { break; } if (nRet != 8) { strError = "file format error"; return(-1); } long length = BitConverter.ToInt64(len_buffer, 0); if (length == -1) { // 出现了一个未收尾的事项 // 把文件最后都算作它的内容 length = stream.Length - stream.Position; } IndexInfo info = new IndexInfo(); info.index = i; TreeNode node = new TreeNode(); if (length == 0) { // 特殊处理 node.Text = i.ToString(); node.ImageIndex = 0; node.Tag = info; this.treeView_ber.Nodes.Add(node); continue; } int direction = stream.ReadByte(); long lStartOffs = stream.Position; length--; // 这是内容长度 node.Text = i.ToString(); // 方向' string strDirection = ""; int nImageIndex = 0; if (direction == 0) { strDirection = "none"; nImageIndex = 0; } else if (direction == 1) { strDirection = "client"; nImageIndex = 1; } else if (direction == 2) { strDirection = "server"; nImageIndex = 2; } else { strDirection = "error direction value: " + ((int)direction).ToString(); nImageIndex = 0; } node.Text += " " + strDirection; node.Text += " len:" + length.ToString(); node.Text += " offs:" + lStartOffs.ToString(); node.ImageIndex = nImageIndex; info.Offs = lStartOffs; info.Length = length; node.Tag = info; this.treeView_ber.Nodes.Add(node); if (length >= 100 * 1024) { stream.Seek(length, SeekOrigin.Current); info.BerTree = null; } else { byte [] baPackage = new byte[(int)length]; stream.Read(baPackage, 0, (int)length); int nParseStart = 0; for (int j = 0; ; j++) { BerTree tree = new BerTree(); int nTotlen = 0; tree.m_RootNode.BuildPartTree(baPackage, nParseStart, baPackage.Length, out nTotlen); if (j == 0) { TreeNode newnode = new TreeNode(); node.Nodes.Add(newnode); FillNodeAndChildren(newnode, tree.m_RootNode.ChildrenCollection[0]); } else { TreeNode newnode = new TreeNode(); node.Nodes.Add(newnode); FillNodeAndChildren(newnode, tree.m_RootNode.ChildrenCollection[0]); } nParseStart += nTotlen; if (nParseStart >= baPackage.Length) { break; } } } } } finally { stream.Close(); } return(0); }
// 执行初始化 // 同步模式 // parameters: // strResultInfo [out]返回说明初始化结果的文字 // return Value: // -1 出错 // 0 成功 async Task <InitialResult> Initial( TargetInfo targetinfo, bool bIgnoreReferenceID, string reference_id) { string strResultInfo = ""; BerTree tree = new BerTree(); INIT_REQUEST struInit_request = new INIT_REQUEST(); // TargetInfo targetinfo = connection.TargetInfo; if (this._channel.Initialized == true) { return new InitialResult { Value = -1, ErrorInfo = "先前已经初始化过了,不应重复初始化" } } ; // 不能重复调用 struInit_request.m_strReferenceId = reference_id; struInit_request.m_strOptions = "yynnnnnnnnnnnnnnnn"; // "yyynynnyynynnnyn"; struInit_request.m_lPreferredMessageSize = 0x100000; ////16384; struInit_request.m_lExceptionalRecordSize = 0x100000; if (String.IsNullOrEmpty(targetinfo.UserName) == false) { struInit_request.m_strID = targetinfo.UserName; struInit_request.m_strPassword = targetinfo.Password; struInit_request.m_strGroupID = targetinfo.GroupID; struInit_request.m_nAuthenticationMethod = targetinfo.AuthenticationMethod; } else { struInit_request.m_strID = ""; struInit_request.m_strPassword = ""; struInit_request.m_strGroupID = ""; struInit_request.m_nAuthenticationMethod = -1; } struInit_request.m_strImplementationId = "DigitalPlatform"; struInit_request.m_strImplementationVersion = "1.2.0"; struInit_request.m_strImplementationName = "Z3950_library"; if (targetinfo.CharNegoUTF8 == true) { struInit_request.m_charNego = new CharsetNeogatiation(); struInit_request.m_charNego.EncodingLevelOID = CharsetNeogatiation.Utf8OID; // "1.0.10646.1.0.8"; // utf-8 struInit_request.m_charNego.RecordsInSelectedCharsets = (targetinfo.CharNegoRecordsUTF8 == true ? 1 : 0); } int nRet = tree.InitRequest(struInit_request, targetinfo.DefaultQueryTermEncoding, out byte[] baPackage); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = "CBERTree::InitRequest() fail!" } } ; if (this._channel.Connected == false) { this.CloseConnection(); return(new InitialResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE DeleteFile("initrequest.bin"); DumpPackage("initrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile("initrequest.txt"); tree.m_RootNode.DumpToFile("initrequest.txt"); #endif RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new InitialResult(result)); } #if DUMPTOFILE DeleteFile("initresponse.bin"); DumpPackage("initresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif //////////////////////////////////////////////////////////////// BerTree tree1 = new BerTree(); tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); #if DUMPTOFILE DeleteFile("InitResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("InitResponse.txt"); #endif INIT_RESPONSE init_response = new INIT_RESPONSE(); nRet = BerTree.GetInfo_InitResponse(tree1.GetAPDuRoot(), ref init_response, out string strError); if (nRet == -1) { return new InitialResult { Value = -1, ErrorInfo = strError } } ; if (bIgnoreReferenceID == false) { // 可以帮助发现旧版本dp2zserver的错误 if (struInit_request.m_strReferenceId != init_response.m_strReferenceId) { strError = "请求的 reference id [" + struInit_request.m_strReferenceId + "] 和 响应的 reference id [" + init_response.m_strReferenceId + "] 不一致!"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } } // 2007/11/5检查version和options bool bOption_0 = BerTree.GetBit(init_response.m_strOptions, 0); if (bOption_0 == false) { strError = "服务器响应的 option bit 0 表示不支持 search"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } bool bOption_1 = BerTree.GetBit(init_response.m_strOptions, 1); if (bOption_1 == false) { strError = "服务器响应的 option bit 1 表示不支持 present"; return(new InitialResult { Value = -1, ErrorInfo = strError }); } if (init_response.m_nResult != 0) { strError = "Initial OK"; } else { strError = "Initial被拒绝。\r\n\r\n错误码 [" + init_response.m_lErrorCode.ToString() + "]\r\n错误消息[" + init_response.m_strErrorMessage + "]"; strResultInfo = BuildInitialResultInfo(init_response); return(new InitialResult { Value = -1, ErrorInfo = strError, ResultInfo = strResultInfo }); } /* * this->m_init_strOption = init_response.m_strOptions; * this->m_init_lPreferredMessageSize = init_response.m_lPreferredMessageSize; * this->m_init_lExceptionalRecordSize = init_response.m_lExceptionalRecordSize; * this->m_init_nResult = init_response.m_nResult; * */ this._channel.Initialized = true; // 字符集协商 if (init_response.m_charNego != null && BerTree.GetBit(init_response.m_strOptions, 17) == true) { if (init_response.m_charNego.EncodingLevelOID == CharsetNeogatiation.Utf8OID) { // 临时修改检索词的编码方式。 // 但是还无法反映到PropertyDialog上。最好能反馈。 targetinfo.DefaultQueryTermEncoding = Encoding.UTF8; targetinfo.Changed = true; if (init_response.m_charNego.RecordsInSelectedCharsets == 1) { this.ForcedRecordsEncoding = Encoding.UTF8; } } } strResultInfo = BuildInitialResultInfo(init_response); return(new InitialResult { Value = 0, ErrorInfo = strError, ResultInfo = strResultInfo }); }
// 检索 // 本函数每次调用前,最好调用一次 TryInitialize() // parameters: // strQuery Search() 专用的检索式。注意,不是一个检索词那么简单 // dbnames 一般是从 targetInfo.DbNames 里面获得。或者从中选择一个数据库名用在这里 // strPreferredRecordSyntax 一般是从 targetInfo.PreferredRecordSyntax 获得即可 // result.Value: // -1 error // 0 fail // 1 succeed // result.ResultCount: // 命中结果集内记录条数 (当 result.Value 为 1 时) public async Task <SearchResult> Search( string strQuery, Encoding queryTermEncoding, string[] dbnames, string strPreferredRecordSyntax, string strResultSetName) { BerTree tree = new BerTree(); SEARCH_REQUEST struSearch_request = new SEARCH_REQUEST { m_dbnames = dbnames }; Debug.Assert(struSearch_request.m_dbnames.Length != 0, ""); struSearch_request.m_strReferenceId = this._currentRefID; struSearch_request.m_lSmallSetUpperBound = 0; struSearch_request.m_lLargeSetLowerBound = 1; struSearch_request.m_lMediumSetPresentNumber = 0; struSearch_request.m_nReplaceIndicator = 1; struSearch_request.m_strResultSetName = strResultSetName; // "default"; struSearch_request.m_strSmallSetElementSetNames = ""; struSearch_request.m_strMediumSetElementSetNames = ""; struSearch_request.m_strPreferredRecordSyntax = strPreferredRecordSyntax; // ZTargetControl.GetLeftValue(this.TargetInfo.PreferredRecordSyntax); // BerTree.MARC_SYNTAX; struSearch_request.m_strQuery = strQuery; struSearch_request.m_nQuery_type = 1; struSearch_request.m_queryTermEncoding = queryTermEncoding; // m_search_response.m_lErrorCode = 0; byte[] baPackage = null; try { // 这里可能抛出异常 tree.SearchRequest(struSearch_request, out baPackage); } catch (Exception ex) { return(new SearchResult { Value = -1, ErrorInfo = "CBERTree::SearchRequest() Exception: " + ex.Message }); } if (this._channel.Connected == false) { this.CloseConnection(); return(new SearchResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE string strBinFile = this.MainForm.DataDir + "\\searchrequest.bin"; File.Delete(strBinFile); DumpPackage(strBinFile, baPackage); string strLogFile = this.MainForm.DataDir + "\\searchrequest.txt"; File.Delete(strLogFile); tree.m_RootNode.DumpToFile(strLogFile); #endif #if NO nRet = CheckConnect( out strError); if (nRet == -1) { return(-1); } #endif BerTree tree1 = new BerTree(); { RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new SearchResult(result)); } #if NO #if DEBUG if (nRet == 0) { Debug.Assert(strError == "", ""); } #endif #endif #if DUPMTOFILE DeleteFile("searchresponse.bin"); DumpPackage("searchresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); } SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); int nRet = BerTree.GetInfo_SearchResponse(tree1.GetAPDuRoot(), ref search_response, true, out string strError); if (nRet == -1) { return new SearchResult { Value = -1, ErrorInfo = strError } } ; #if DUMPTOFILE DeleteFile("SearchResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("SearchResponse.txt"); #endif { SearchResult result = new SearchResult(); result.ResultCount = (int)search_response.m_lResultCount; if (search_response.m_nSearchStatus != 0) // 不一定是1 { result.Value = 1; return(result); } result.ErrorInfo = "Search Fail: diagRecords:\r\n" + search_response.m_diagRecords.GetMessage(); result.Value = 0; // search fail return(result); } }
// 处理Server可能发来的Close // return: // -1 error // 0 不是Close // 1 是Close,已经迫使ZChannel处于尚未初始化状态 int CheckServerCloseRequest( ZConnection connection, out string strMessage, out string strError) { strMessage = ""; strError = ""; if (connection.ZChannel.DataAvailable == false) return 0; int nRecvLen = 0; byte [] baPackage = null; int nRet = connection.ZChannel.RecvTcpPackage( out baPackage, out nRecvLen, out strError); if (nRet == -1) return -1; BerTree tree1 = new BerTree(); int nTotlen = 0; tree1.m_RootNode.BuildPartTree(baPackage, 0, baPackage.Length, out nTotlen); if (tree1.GetAPDuRoot().m_uTag != BerTree.z3950_close) { // 不是Close return 0; } CLOSE_REQUEST closeStruct = new CLOSE_REQUEST(); nRet = BerTree.GetInfo_closeRequest( tree1.GetAPDuRoot(), ref closeStruct, out strError); if (nRet == -1) return -1; strMessage = closeStruct.m_strDiagnosticInformation; /* this.ZChannel.CloseSocket(); this.ZChannel.Initialized = false; // 迫使重新初始化 if (this.CurrentTargetInfo != null) this.CurrentTargetInfo.OfflineServerIcon(); * */ connection.CloseConnection(); return 1; }
// 处理一个通道的通讯活动 public async void HandleClient(TcpClient tcpClient, CancellationToken token) { ZServerChannel channel = _zChannels.Add(tcpClient); // 允许对 channel 做额外的初始化 if (this.ChannelOpened != null) { this.ChannelOpened(channel, new EventArgs()); } try { //List<byte> cache = new List<byte>(); string ip = ""; //Stream inputStream = tcpClient.GetStream(); //Stream outputStream = tcpClient.GetStream(); try { ip = GetClientIP(tcpClient); channel.Touch(); int i = 0; bool running = true; while (running) { // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient BerTree request = await ZProcessor.GetIncomingRequest(tcpClient); if (request == null) { Console.WriteLine("client close on request " + i); break; } Console.WriteLine("request " + i); channel.Touch(); byte[] response = null; if (this.ProcessRequest == null) { response = await DefaultProcessRequest(channel, request); } else { ProcessRequestEventArgs e = new ProcessRequestEventArgs(); e.Request = request; this.ProcessRequest(channel, e); response = e.Response; } channel.Touch(); // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient Result result = await ZProcessor.SendResponse(response, tcpClient); channel.Touch(); if (result.Value == -1) { Console.WriteLine("error on response " + i + ": " + result.ErrorInfo); break; } i++; } } catch (Exception ex) { // 2016/11/14 ZManager.Log?.Error("ip:" + ip + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex)); } finally { #if NO outputStream.Flush(); outputStream.Close(); outputStream = null; inputStream.Close(); inputStream = null; #endif // tcpClient.Close(); // 清除全局结果集 } } finally { _zChannels.Remove(channel); #if NO if (this.ChannelClosed != null) { ChannelClosedEventArgs e = new ChannelClosedEventArgs(); e.Channel = channel; this.ChannelClosed(channel, e); } #endif channel.Close(); } }
// 编码(构造) Present响应包 int Encode_PresentResponse(PresentRequestInfo info, out byte[] baPackage) { baPackage = null; int nRet = 0; string strError = ""; DiagFormat diag = null; BerTree tree = new BerTree(); BerNode root = null; string strResultSetName = info.m_strResultSetID; if (String.IsNullOrEmpty(strResultSetName) == true) strResultSetName = "default"; long lStart = info.m_lResultSetStartPoint - 1; long lNumber = info.m_lNumberOfRecordsRequested; long lPerCount = lNumber; long lHitCount = 0; List<string> paths = new List<string>(); int nPresentStatus = 5; // failed // 获取结果集中需要部分的记录path long lOffset = lStart; int nCount = 0; for (; ; ) { DigitalPlatform.LibraryClient.localhost.Record[] searchresults = null; long lRet = this._channel.GetSearchResult( null, // stop, strResultSetName, // strResultSetName lOffset, lPerCount, "id", "zh", // this.Lang, out searchresults, out strError); /* // 测试获取结果集失败的情况,返回非代理诊断记录 lRet = -1; strError = "测试检索错误信息!"; * */ if (lRet == -1) { SetPresentDiagRecord(ref diag, 2, // temporary system error strError); break; } if (lRet == 0) { // goto ERROR1 ? } lHitCount = lRet; // 顺便得到命中记录总条数 // 转储 for (int i = 0; i < searchresults.Length; i++) { paths.Add(searchresults[i].Path); } lOffset += searchresults.Length; lPerCount -= searchresults.Length; nCount += searchresults.Length; if (lOffset >= lHitCount || lPerCount <= 0 || nCount >= lNumber) { // break; } } // TODO: 需要注意多个错误是否形成多个diag记录?V2不允许这样,V3允许这样 if (lHitCount < info.m_lResultSetStartPoint && diag == null) { strError = "start参数值 " + info.m_lResultSetStartPoint + " 超过结果集中记录总数 " + lHitCount; // return -1; // 如果表示错误状态? SetPresentDiagRecord(ref diag, 13, // Present request out-of-range strError); } int MAX_PRESENT_RECORD = 100; // 限制每次 present 的记录数量 if (lNumber > MAX_PRESENT_RECORD) lNumber = MAX_PRESENT_RECORD; long nNextResultSetPosition = 0; // if (lHitCount < (lStart - 1) + lNumber) { // 是 present 错误,但还可以调整 lNumber lNumber = lHitCount - (lStart - 1); nNextResultSetPosition = 0; } else { // nNextResultSetPosition = lStart + lNumber + 1; } root = tree.m_RootNode.NewChildConstructedNode( BerTree.z3950_presentResponse, BerNode.ASN1_CONTEXT); // reference id if (String.IsNullOrEmpty(info.m_strReferenceId) == false) { root.NewChildCharNode(BerTree.z3950_ReferenceId, BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strReferenceId)); } List<RetrivalRecord> records = new List<RetrivalRecord>(); // 获取要返回的MARC记录 if (diag == null) { // 记录编码格式为 GRS-1 (generic-record-syntax-1) : // EXTERNAL // --- OID (Object Identifier) // --- MARC (OCTET STRING) // m_strOID = _T("1.2.840.10003.5.1"); // OID of UNIMARC // m_strOID = _T("1.2.840.10003.5.10"); // OID of USMARC // // 需要建立一个数据库名和oid的对照表,方面快速取得数据库MARC syntax OID // TODO: 编码过程中,可能会发现记录太多,总尺寸超过Initial中规定的prefered message size。 // 这样需要减少返回的记录数量。这样,就需要先做这里的循环,后构造另外几个参数 int nSize = 0; for (int i = 0; i < (int)lNumber; i++) { // 编码 N 条 MARC 记录 // // if (m_bStop) return false; // 取出数据库指针 // lStart 不是 0 起点的 string strPath = paths[i]; // 解析出数据库名和ID string strDbName = Global.GetDbName(strPath); string strRecID = Global.GetRecordID(strPath); // 如果取得的是xml记录,则根元素可以看出记录的marc syntax,进一步可以获得oid; // 如果取得的是MARC格式记录,则需要根据数据库预定义的marc syntax来看出oid了 string strMarcSyntaxOID = GetMarcSyntaxOID(strDbName); byte[] baMARC = null; RetrivalRecord record = new RetrivalRecord(); record.m_strDatabaseName = strDbName; // 根据书目库名获得书目库属性对象 BiblioDbProperty prop = this._service.GetDbProperty( strDbName, false); nRet = GetMARC(strPath, info.m_elementSetNames, prop != null ? prop.AddField901 : false, out baMARC, out strError); /* // 测试记录群中包含诊断记录 if (i == 1) { nRet = -1; strError = "测试获取记录错误"; }*/ if (nRet == -1) { record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 14; // system error in presenting records record.m_surrogateDiagnostic.m_strAddInfo = strError; } else if (nRet == 0) { record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 1028; // record deleted record.m_surrogateDiagnostic.m_strAddInfo = strError; } else if (String.IsNullOrEmpty(strMarcSyntaxOID) == true) { // 根据数据库名无法获得marc syntax oid。可能是虚拟库检索命中记录所在的物理库没有在dp2zserver.xml中配置。 record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 109; // database unavailable // 似乎235:database dos not exist也可以 record.m_surrogateDiagnostic.m_strAddInfo = "根据数据库名 '" + strDbName + "' 无法获得marc syntax oid"; } else { record.m_external = new External(); record.m_external.m_strDirectRefenerce = strMarcSyntaxOID; record.m_external.m_octectAligned = baMARC; } nSize += record.GetPackageSize(); if (i == 0) { // 连一条记录也放不下 if (nSize > this._lExceptionalRecordSize) { Debug.Assert(diag == null, ""); SetPresentDiagRecord(ref diag, 17, // record exceeds Exceptional_record_size "记录尺寸 " + nSize.ToString() + " 超过 Exceptional_record_size " + this._lExceptionalRecordSize.ToString()); lNumber = 0; break; } } else { if (nSize >= this._lPreferredMessageSize) { // 调整返回的记录数 lNumber = i; break; } } records.Add(record); } } // numberOfRecordsReturned root.NewChildIntegerNode(BerTree.z3950_NumberOfRecordsReturned, // 24 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)lNumber)); if (diag != null) nPresentStatus = 5; else nPresentStatus = 0; // nextResultSetPosition // if 0, that's end of the result set // else M+1, M is 最后一次 present response 的最后一条记录在 result set 中的 position root.NewChildIntegerNode(BerTree.z3950_NextResultSetPosition, // 25 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)nNextResultSetPosition)); // presentStatus // success (0), // partial-1 (1), // partial-2 (2), // partial-3 (3), // partial-4 (4), // failure (5). root.NewChildIntegerNode(BerTree.z3950_presentStatus, // 27 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)nPresentStatus)); // 诊断记录 if (diag != null) { BerNode nodeDiagRoot = root.NewChildConstructedNode(BerTree.z3950_nonSurrogateDiagnostic, // 130 BerNode.ASN1_CONTEXT); diag.BuildBer(nodeDiagRoot); /* nodeDiagRoot.NewChildOIDsNode(6, BerNode.ASN1_UNIVERSAL, diag.m_strDiagSetID); // "1.2.840.10003.4.1" nodeDiagRoot.NewChildIntegerNode(2, BerNode.ASN1_UNIVERSAL, BitConverter.GetBytes((long)diag.m_nDiagCondition)); if (String.IsNullOrEmpty(diag.m_strAddInfo) == false) { nodeDiagRoot.NewChildCharNode(26, BerNode.ASN1_UNIVERSAL, Encoding.UTF8.GetBytes(diag.m_strAddInfo)); } * */ } // 如果 present 是非法的,到这里打包完成,可以返回了 if (0 != nPresentStatus) goto END1; // 编码记录BER树 // 以下为 present 成功时,打包返回记录。 // present success // presRoot records child, constructed (choice of ... ... optional) // if present fail, then may be no records 'node' // Records ::= CHOICE { // responseRecords [28] IMPLICIT SEQUENCE OF NamePlusRecord, // nonSurrogateDiagnostic [130] IMPLICIT DefaultDiagFormat, // multipleNonSurDiagnostics [205] IMPLICIT SEQUENCE OF DiagRec} // 当 present 成功时,response 选择了 NamePlusRecord (数据库名 + 记录) BerNode node = root.NewChildConstructedNode(BerTree.z3950_dataBaseOrSurDiagnostics, // 28 BerNode.ASN1_CONTEXT); for (int i = 0; i < records.Count; i++) { RetrivalRecord record = records[i]; record.BuildNamePlusRecord(node); } END1: baPackage = null; root.EncodeBERPackage(ref baPackage); return 0; }
// 2007/7/18 // build a z39.50 Init response public static int Encode_InitialResponse(InitResponseInfo info, out byte[] baPackage) { baPackage = null; BerNode root = null; BerTree tree = new BerTree(); root = tree.m_RootNode.NewChildConstructedNode(BerTree.z3950_initResponse, BerNode.ASN1_CONTEXT); if (String.IsNullOrEmpty(info.m_strReferenceId) == false) { root.NewChildCharNode(BerTree.z3950_ReferenceId, BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strReferenceId)); } root.NewChildBitstringNode(BerTree.z3950_ProtocolVersion, // 3 BerNode.ASN1_CONTEXT, "yy"); /* option search (0), present (1), delSet (2), resourceReport (3), triggerResourceCtrl (4), resourceCtrl (5), accessCtrl (6), scan (7), sort (8), -- (9) (reserved) extendedServices (10), level-1Segmentation (11), level-2Segmentation (12), concurrentOperations (13), namedResultSets (14) 15 Encapsulation Z39.50-1995 Amendment 3: Z39.50 Encapsulation 16 resultCount parameter in Sort Response See Note 8 Z39.50-1995 Amendment 1: Add resultCount parameter to Sort Response 17 Negotiation Model See Note 9 Model for Z39.50 Negotiation During Initialization 18 Duplicate Detection See Note 1 Z39.50 Duplicate Detection Service 19 Query type 104 */ root.NewChildBitstringNode(BerTree.z3950_Options, // 4 BerNode.ASN1_CONTEXT, info.m_strOptions); // "110000000000001" root.NewChildIntegerNode(BerTree.z3950_PreferredMessageSize, // 5 BerNode.ASN1_CONTEXT, BitConverter.GetBytes((long)info.m_lPreferredMessageSize)); root.NewChildIntegerNode(BerTree.z3950_ExceptionalRecordSize, // 6 BerNode.ASN1_CONTEXT, BitConverter.GetBytes((long)info.m_lExceptionalRecordSize)); // 2007/11/7 原来这个事项曾经位置不对,现在调整到这里 // bool root.NewChildIntegerNode(BerTree.z3950_result, // 12 BerNode.ASN1_CONTEXT, BitConverter.GetBytes((long)info.m_nResult)); root.NewChildCharNode(BerTree.z3950_ImplementationId, // 110 BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strImplementationId)); root.NewChildCharNode(BerTree.z3950_ImplementationName, // 111 BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strImplementationName)); root.NewChildCharNode(BerTree.z3950_ImplementationVersion, // 112 BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strImplementationVersion)); // "3" // userInformationField if (info.UserInfoField != null) { BerNode nodeUserInfoRoot = root.NewChildConstructedNode(BerTree.z3950_UserInformationField, // 11 BerNode.ASN1_CONTEXT); info.UserInfoField.Build(nodeUserInfoRoot); } if (info.m_charNego != null) { info.m_charNego.EncodeResponse(root); } baPackage = null; root.EncodeBERPackage(ref baPackage); return 0; }
// parameters: // strResultInfo [out]返回说明初始化结果的文字 int DoInitial( ZConnection connection, out string strResultInfo, out string strError) { strResultInfo = ""; strError = ""; byte[] baPackage = null; BerTree tree = new BerTree(); INIT_REQUEST struInit_request = new INIT_REQUEST(); int nRet; int nRecvLen; TargetInfo targetinfo = connection.TargetInfo; if (connection.ZChannel.Initialized == true) { strError = "Already Initialized"; goto ERROR1; } struInit_request.m_strReferenceId = this.CurrentRefID; // "0";!!! struInit_request.m_strOptions = "yynnnnnnnnnnnnnnnn"; // "yyynynnyynynnnyn"; struInit_request.m_lPreferredMessageSize = 0x100000; ////16384; struInit_request.m_lExceptionalRecordSize = 0x100000; if (String.IsNullOrEmpty(targetinfo.UserName) == false) { struInit_request.m_strID = targetinfo.UserName; struInit_request.m_strPassword = targetinfo.Password; struInit_request.m_strGroupID = targetinfo.GroupID; struInit_request.m_nAuthenticationMethod = targetinfo.AuthenticationMethod; } else { struInit_request.m_strID = ""; struInit_request.m_strPassword = ""; struInit_request.m_strGroupID = ""; struInit_request.m_nAuthenticationMethod = -1; } /* struInit_request.m_strImplementationId = "81"; // "81"; struInit_request.m_strImplementationVersion = "2.0.3 WIN32 Debug"; struInit_request.m_strImplementationName = "Index Data/YAZ"; * */ struInit_request.m_strImplementationId = "DigitalPlatform"; struInit_request.m_strImplementationVersion = "1.1.0"; struInit_request.m_strImplementationName = "dp2Catalog"; if (targetinfo.CharNegoUTF8 == true) { struInit_request.m_charNego = new CharsetNeogatiation(); struInit_request.m_charNego.EncodingLevelOID = CharsetNeogatiation.Utf8OID; // "1.0.10646.1.0.8"; // utf-8 struInit_request.m_charNego.RecordsInSelectedCharsets = (targetinfo.CharNegoRecordsUTF8 == true ? 1 : 0); } nRet = tree.InitRequest(struInit_request, targetinfo.DefaultQueryTermEncoding, out baPackage); if (nRet == -1) { strError = "CBERTree::InitRequest() fail!"; goto ERROR1; } if (connection.ZChannel.Connected == false) { strError = "socket尚未连接或者已经被关闭"; goto ERROR1; } #if DUMPTOFILE DeleteFile("initrequest.bin"); DumpPackage("initrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile ("initrequest.txt"); tree.m_RootNode.DumpToFile("initrequest.txt"); #endif /* nRet = this.ZChannel.SendTcpPackage( baPackage, baPackage.Length, out strError); if (nRet == -1 || nRet == 1) { // CloseZAssociation(); return -1; } baPackage = null; nRet = this.ZChannel.RecvTcpPackage( out baPackage, out nRecvLen, out strError); if (nRet == -1) { // CloseZAssociation(); return -1; } * */ byte[] baOutPackage = null; nRet = connection.ZChannel.SendAndRecv( baPackage, out baOutPackage, out nRecvLen, out strError); if (nRet == -1) { goto ERROR1; } #if DUMPTOFILE DeleteFile("initresponse.bin"); DumpPackage("initresponse.bin", (char *)baOutPackage.GetData(), baOutPackage.GetSize()); #endif //////////////////////////////////////////////////////////////// BerTree tree1 = new BerTree(); int nTotlen = 0; tree1.m_RootNode.BuildPartTree(baOutPackage, 0, baOutPackage.Length, out nTotlen); #if DUMPTOFILE DeleteFile("InitResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("InitResponse.txt"); #endif /* nRet = FitDebugInfo_InitResponse(&tree1, strError); if (nRet == -1) { return -1; } */ INIT_RESPONSE init_response = new INIT_RESPONSE(); nRet = BerTree.GetInfo_InitResponse(tree1.GetAPDuRoot(), ref init_response, out strError); if (nRet == -1) { goto ERROR1; } if (targetinfo.IgnoreReferenceID == false) { // 2007/11/2。可以帮助发现旧版本dp2zserver的错误 if (struInit_request.m_strReferenceId != init_response.m_strReferenceId) { strError = "请求的 reference id [" + struInit_request.m_strReferenceId + "] 和 响应的 reference id [" + init_response.m_strReferenceId + "] 不一致!"; goto ERROR1; } } if (init_response.m_nResult != 0) { strError = "Initial OK"; } else { strError = "Initial被拒绝。\r\n\r\n错误码 [" + init_response.m_lErrorCode.ToString() + "]\r\n错误消息[" + init_response.m_strErrorMessage + "]"; strResultInfo = ZConnection.BuildInitialResultInfo(init_response); return -1; } /* this->m_init_strOption = init_response.m_strOptions; this->m_init_lPreferredMessageSize = init_response.m_lPreferredMessageSize; this->m_init_lExceptionalRecordSize = init_response.m_lExceptionalRecordSize; this->m_init_nResult = init_response.m_nResult; * */ connection.ZChannel.Initialized = true; // 字符集协商 if (init_response.m_charNego != null && BerTree.GetBit(init_response.m_strOptions, 17) == true) { if (init_response.m_charNego.EncodingLevelOID == CharsetNeogatiation.Utf8OID) { // 临时修改检索词的编码方式。 // 但是还无法反映到PropertyDialog上。最好能反馈。 targetinfo.DefaultQueryTermEncoding = Encoding.UTF8; targetinfo.Changed = true; if (init_response.m_charNego.RecordsInSelectedCharsets == 1) connection.ForcedRecordsEncoding = Encoding.UTF8; } } strResultInfo = ZConnection.BuildInitialResultInfo(init_response); return 0; ERROR1: strResultInfo = strError; return -1; }
// 装载记录索引 int LoadIndex(string strLogFilename, out string strError) { strError = ""; Stream stream = null; try { stream = File.OpenRead(strLogFilename); } catch (Exception ex) { strError = "file '" + strLogFilename + "'open error: " + ex.Message; return -1; } try { this.treeView_ber.Nodes.Clear(); for (long i = 0; ; i++) { byte[] len_buffer = new byte[8]; int nRet = stream.Read(len_buffer, 0, 8); if (nRet == 0) break; if (nRet != 8) { strError = "file format error"; return -1; } long length = BitConverter.ToInt64(len_buffer, 0); if (length == -1) { // 出现了一个未收尾的事项 // 把文件最后都算作它的内容 length = stream.Length - stream.Position; } IndexInfo info = new IndexInfo(); info.index = i; TreeNode node = new TreeNode(); if (length == 0) { // 特殊处理 node.Text = i.ToString(); node.ImageIndex = 0; node.Tag = info; this.treeView_ber.Nodes.Add(node); continue; } int direction = stream.ReadByte(); long lStartOffs = stream.Position; length--; // 这是内容长度 node.Text = i.ToString(); // 方向' string strDirection = ""; int nImageIndex = 0; if (direction == 0) { strDirection = "none"; nImageIndex = 0; } else if (direction == 1) { strDirection = "client"; nImageIndex = 1; } else if (direction == 2) { strDirection = "server"; nImageIndex = 2; } else { strDirection = "error direction value: " + ((int)direction).ToString(); nImageIndex = 0; } node.Text += " " + strDirection; node.Text += " len:" + length.ToString(); node.Text += " offs:" + lStartOffs.ToString(); node.ImageIndex = nImageIndex; info.Offs = lStartOffs; info.Length = length; node.Tag = info; this.treeView_ber.Nodes.Add(node); if (length >= 100*1024) { stream.Seek(length, SeekOrigin.Current); info.BerTree = null; } else { byte [] baPackage = new byte[(int)length]; stream.Read(baPackage, 0, (int)length); int nParseStart = 0; for (int j=0; ;j++ ) { BerTree tree = new BerTree(); int nTotlen = 0; tree.m_RootNode.BuildPartTree(baPackage, nParseStart, baPackage.Length, out nTotlen); if (j == 0) { TreeNode newnode = new TreeNode(); node.Nodes.Add(newnode); FillNodeAndChildren(newnode, tree.m_RootNode.ChildrenCollection[0]); } else { TreeNode newnode = new TreeNode(); node.Nodes.Add(newnode); FillNodeAndChildren(newnode, tree.m_RootNode.ChildrenCollection[0]); } nParseStart += nTotlen; if (nParseStart >= baPackage.Length) break; } } } } finally { stream.Close(); } return 0; }
// 处理一个通道的通讯活动 public virtual void HandleClient(TcpClient tcpClient, Action close_action, CancellationToken token) { #if NO ZServerChannel channel = _zChannels.Add(tcpClient); // 允许对 channel 做额外的初始化 if (this.ChannelOpened != null) { this.ChannelOpened(channel, new EventArgs()); } try { string ip = ""; try { ip = GetClientIP(tcpClient); channel.Touch(); int i = 0; bool running = true; while (running) { if (token != null && token.IsCancellationRequested) { return; } // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient BerTree request = await ZProcessor.GetIncomingRequest(tcpClient); if (request == null) { Console.WriteLine("client close on request " + i); break; } Console.WriteLine("request " + i); channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } byte[] response = null; if (this.ProcessRequest == null) { response = await DefaultProcessRequest(channel, request); } else { ProcessRequestEventArgs e = new ProcessRequestEventArgs(); e.Request = request; this.ProcessRequest(channel, e); response = e.Response; } channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient Result result = await SendResponse(response, tcpClient); channel.Touch(); if (result.Value == -1) { Console.WriteLine("error on response " + i + ": " + result.ErrorInfo); break; } i++; } } catch (Exception ex) { string strError = "ip:" + ip + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex); ZManager.Log?.Error(strError); // Console.WriteLine(strError); } finally { // tcpClient.Close(); // 清除全局结果集 } } finally { _zChannels.Remove(channel); channel.Close(); close_action.Invoke(); } #endif }
// Pipeline 版本 // 处理一个通道的通讯活动 public async override void HandleClient(TcpClient tcpClient, Action close_action, CancellationToken token) { List <byte> cache = new List <byte>(); ZServerChannel channel = _tcpChannels.Add(tcpClient, () => { return(new ZServerChannel()); }) as ZServerChannel; // 允许对 channel 做额外的初始化 if (this.ChannelOpened != null) { this.ChannelOpened(channel, new EventArgs()); } try { string name = ""; string ip = ""; Task <Result> task = null; try { name = channel.GetDebugName(tcpClient); ip = TcpServer.GetClientIP(tcpClient); channel.Touch(); int i = 0; bool running = true; while (running) { if (token != null && token.IsCancellationRequested) { return; } // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient BerTree request = await ZProcessor.GetIncomingRequest( cache, tcpClient, () => channel.Touch()).ConfigureAwait(false); // 2018/10/10 add configure if (request == null) { Console.WriteLine("client close on request " + i); break; } Console.WriteLine("request " + i); channel.Touch(); if (token != null && token.IsCancellationRequested) { return; } // 如果前一轮的任务还没有完成,这里等待 if (task != null) { Result result = task.Result; if (result.Value == -1) { return; } task = null; } task = Task.Run(() => ProcessAndResponse( tcpClient, close_action, channel, request, token)); i++; } } catch (Exception ex) { #if NO if (ex.InnerException != null && ex.InnerException is ObjectDisposedException) { // 这种情况一般是 server 主动清理闲置通道导致的,不记入日志 } else if (ex is ObjectDisposedException) { // 这种情况一般是 client close 通道导致,不记入日志 } #endif #if NO if (GetException(ex, typeof(ObjectDisposedException)) != null) { return; } SocketException socket_ex = (SocketException)GetException(ex, typeof(SocketException)); if (socket_ex != null && socket_ex.SocketErrorCode == SocketError.ConnectionReset) { return; } { string strName = "ip:" + ip + channel == null ? "(null)" : " channel:" + channel.GetHashCode(); string strError = strName + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex); LibraryManager.Log?.Error(strError); // Console.WriteLine(strError); } #endif if (ex is UnknownApduException || ex is BadApduException) { IpTable.SetInBlackList(ip, TimeSpan.FromHours(1)); LibraryManager.Log?.Info(string.Format("IP 地址 {0} 已被加入黑名单,时限一个小时", ip)); } LogException(ex, channel, name); } finally { #if NO outputStream.Flush(); outputStream.Close(); outputStream = null; inputStream.Close(); inputStream = null; #endif // tcpClient.Close(); // 清除全局结果集 if (task != null) { // TODO: 要想办法立即终止检索和响应过程 } } } finally { _tcpChannels.Remove(channel); #if NO if (this.ChannelClosed != null) { ChannelClosedEventArgs e = new ChannelClosedEventArgs(); e.Channel = channel; this.ChannelClosed(channel, e); } #endif channel.Close(); if (close_action != null) { close_action.Invoke(); } } }
// 解释包 void menuItem_explainContent_Click(object sender, EventArgs e) { TreeNode node = this.treeView_ber.SelectedNode; if (node == null) { MessageBox.Show(this, "尚未选定节点"); return; } BerNode bernode = (BerNode)node.Tag; if (TreeNodeLevel(node) != 1) { MessageBox.Show(this, "必须是Ber包根节点"); return; } BerNode root = bernode; int nRet = 0; string strError = ""; string strDebugInfo = "OK"; if (root.m_uTag == BerTree.z3950_initRequest) { // 观察Initial请求包 nRet = BerTree.GetInfo_InitRequest( root, out strDebugInfo, out strError); } else if (root.m_uTag == BerTree.z3950_searchRequest) { nRet = BerTree.GetInfo_SearchRequest( root, out strDebugInfo, out strError); } else if (root.m_uTag == BerTree.z3950_presentRequest) { nRet = BerTree.GetInfo_PresentRequest( root, out strDebugInfo, out strError); } else if (root.m_uTag == BerTree.z3950_initResponse) { nRet = BerTree.GetInfo_InitResponse(root, out strDebugInfo, out strError); } else if (root.m_uTag == BerTree.z3950_searchResponse) { nRet = BerTree.GetInfo_SearchResponse(root, out strDebugInfo, out strError); } else if (root.m_uTag == BerTree.z3950_presentResponse) { RecordCollection records = null; SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); nRet = BerTree.GetInfo_PresentResponse(root, ref search_response, out records, true, out strError); } if (nRet == -1) { MessageBox.Show(this, strError); } else { MessageBox.Show(this, strDebugInfo); } }
// 编码(构造) Search响应包 int Encode_SearchResponse(SearchRequestInfo info, out byte[] baPackage, out string strError) { baPackage = null; int nRet = 0; long lRet = 0; strError = ""; DiagFormat diag = null; BerTree tree = new BerTree(); BerNode root = null; long lSearchStatus = 0; // 0 失败;1成功 long lHitCount = 0; string strQueryXml = ""; // 根据逆波兰表进行检索 // return: // -1 error // 0 succeed nRet = BuildQueryXml( info.m_dbnames, info.m_rpnRoot, out strQueryXml, out strError); if (nRet == -1) { SetPresentDiagRecord(ref diag, 2, // temporary system error strError); } string strResultSetName = info.m_strResultSetName; if (String.IsNullOrEmpty(strResultSetName) == true) strResultSetName = "default"; if (diag == null) { lRet = _channel.Search(null, strQueryXml, strResultSetName, "", // strOutputStyle out strError); /* // 测试检索失败 lRet = -1; strError = "测试检索失败"; * */ if (lRet == -1) { lSearchStatus = 0; // failed SetPresentDiagRecord(ref diag, 2, // temporary system error strError); } else { lHitCount = lRet; lSearchStatus = 1; // succeed } } root = tree.m_RootNode.NewChildConstructedNode( BerTree.z3950_searchResponse, BerNode.ASN1_CONTEXT); // reference id if (String.IsNullOrEmpty(info.m_strReferenceId) == false) { root.NewChildCharNode(BerTree.z3950_ReferenceId, BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strReferenceId)); } // resultCount root.NewChildIntegerNode(BerTree.z3950_resultCount, // 23 BerNode.ASN1_CONTEXT, // ASNI_PRIMITIVE BUG!!!! BitConverter.GetBytes((long)lHitCount)); // numberOfRecordsReturned root.NewChildIntegerNode(BerTree.z3950_NumberOfRecordsReturned, // 24 BerNode.ASN1_CONTEXT, // ASNI_PRIMITIVE BUG!!!! BitConverter.GetBytes((long)0/*info.m_lNumberOfRecordReturned*/)); // 0 // nextResultSetPosition root.NewChildIntegerNode(BerTree.z3950_NextResultSetPosition, // 25 BerNode.ASN1_CONTEXT, // ASNI_PRIMITIVE BUG!!!! BitConverter.GetBytes((long)1/*info.m_lNextResultSetPosition*/)); // 2007/11/7 原来本项位置不对,现在移动到这里 // bool // searchStatus root.NewChildIntegerNode(BerTree.z3950_searchStatus, // 22 BerNode.ASN1_CONTEXT, // ASNI_PRIMITIVE BUG!!!! BitConverter.GetBytes((long)lSearchStatus)); // resultSetStatus OPTIONAL // 2007/11/7 // presentStatus root.NewChildIntegerNode(BerTree.z3950_presentStatus, // 27 BerNode.ASN1_CONTEXT, // ASNI_PRIMITIVE BUG!!!! BitConverter.GetBytes((long)0)); // 诊断记录 if (diag != null) { BerNode nodeDiagRoot = root.NewChildConstructedNode(BerTree.z3950_nonSurrogateDiagnostic, // 130 BerNode.ASN1_CONTEXT); diag.BuildBer(nodeDiagRoot); } baPackage = null; root.EncodeBERPackage(ref baPackage); return 0; }
// 获得记录 // 本函数每次调用前,最好调用一次 TryInitialize() // 不确保一定可以获得nCount个 // parameters: // nStart 获取记录的开始位置(从0开始计数) public async Task <PresentResult> OncePresent( string strResultSetName, int nStart, int nCount, string strElementSetName, string strPreferredRecordSyntax) { if (nCount == 0) { return new PresentResult { Value = 0, ErrorInfo = "nCount 参数为 0,本次没有真正请求服务器获取记录" } } ; BerTree tree = new BerTree(); PRESENT_REQUEST struPresent_request = new PRESENT_REQUEST(); //byte[] baPackage = null; //int nRet; struPresent_request.m_strReferenceId = this._currentRefID; struPresent_request.m_strResultSetName = strResultSetName; // "default"; struPresent_request.m_lResultSetStartPoint = nStart + 1; struPresent_request.m_lNumberOfRecordsRequested = nCount; struPresent_request.m_strElementSetNames = strElementSetName; struPresent_request.m_strPreferredRecordSyntax = strPreferredRecordSyntax; int nRet = tree.PresentRequest(struPresent_request, out byte[] baPackage); if (nRet == -1) { return new PresentResult { Value = -1, ErrorInfo = "CBERTree::PresentRequest() fail!" } } ; if (this._channel.Connected == false) { this.CloseConnection(); return(new PresentResult { Value = -1, ErrorInfo = "socket尚未连接或者已经被关闭" }); } #if DUMPTOFILE DeleteFile("presentrequest.bin"); DumpPackage("presentrequest.bin", (char *)baPackage.GetData(), baPackage.GetSize()); DeleteFile("presentrequest.txt"); tree.m_RootNode.DumpToFile("presentrequest.txt"); #endif BerTree tree1 = new BerTree(); { RecvResult result = await this._channel.SendAndRecv( baPackage); if (result.Value == -1) { return(new PresentResult(result)); } #if DUMPTOFILE DeleteFile("presendresponse.bin"); DumpPackage("presentresponse.bin", (char *)baPackage.GetData(), baPackage.GetSize()); #endif tree1.m_RootNode.BuildPartTree(result.Package, 0, result.Package.Length, out int nTotalLen); } #if DUMPTOFILE DeleteFile("PresentResponse.txt"); tree1.m_RootNode.DumpDebugInfoToFile("PresentResponse.txt"); #endif SEARCH_RESPONSE search_response = new SEARCH_RESPONSE(); nRet = BerTree.GetInfo_PresentResponse(tree1.GetAPDuRoot(), ref search_response, out RecordCollection records, true, out string strError); if (nRet == -1) { return new PresentResult { Value = -1, ErrorInfo = strError } } ; SetElementSetName(records, strElementSetName); if (search_response.m_diagRecords.Count != 0) { return new PresentResult { Value = -1, ErrorInfo = "error diagRecords:\r\n\r\n---\r\n" + search_response.m_diagRecords.GetMessage() } } ; return(new PresentResult { Records = records }); }
// 发出超大攻击请求包 // return: // -1 出错 // 0 正确发出 // 1 发出前,发现流中有未读入的数据 public static async Task <Result> SendInfinitPackage( TcpClient _client, int length) { Result result = new Result(); if (_client == null) { result.Value = -1; result.ErrorInfo = "client尚未初始化。请重新连接和检索。"; return(result); } if (_client == null) { result.Value = -1; result.ErrorInfo = "用户中断"; return(result); } NetworkStream stream = _client.GetStream(); if (stream.DataAvailable == true) { result.Value = 1; result.ErrorInfo = "发送前发现流中有未读的数据"; return(result); } try { { BerTree tree = new BerTree(); BerNode root = tree.m_RootNode.NewChildConstructedNode(BerTree.z3950_initRequest, BerNode.ASN1_CONTEXT); byte[] baTempPackage = null; root.MakeHeadPart(ref baTempPackage, length); await stream.WriteAsync(baTempPackage, 0, baTempPackage.Length).ConfigureAwait(false); } #if NO for (int i = 0; i < length; i++) { byte[] baPackage = new byte[1]; await stream.WriteAsync(baPackage, 0, 1).ConfigureAwait(false); } #endif int chunk_size = 4096 * 10; for (int i = 0; i < (length / chunk_size) + 1; i++) { byte[] baPackage = new byte[chunk_size]; await stream.WriteAsync(baPackage, 0, chunk_size).ConfigureAwait(false); } } catch (Exception ex) { if (ex is IOException && ex.InnerException is SocketException) { // "ConnectionAborted" result.ErrorCode = ((SocketException)ex.InnerException).SocketErrorCode.ToString(); } result.Value = -1; result.ErrorInfo = "send出错: " + ex.Message; return(result); } return(result); }