// 处理 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 }); }
// 处理 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 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 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); }
// 默认的请求处理过程。应可以被重新指定 // 下级函数,例如处理 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]); }
// 获得记录 // 本函数每次调用前,最好调用一次 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 }); }
// 检索 // 本函数每次调用前,最好调用一次 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); } }
// 执行初始化 // 同步模式 // 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 }); }
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; }
// 获得记录 // 不确保一定可以获得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; }
// 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 }
// 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; }
// 处理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; }