/// <summary> /// Handles the asynchronous connect event. /// </summary> /// <param name="iEvent"></param> private void ProcessConnect(SocketAsyncEventArgs iEvent) { if (iEvent.SocketError == SocketError.Success) { // notify connected event subscribers ConnectedEvent(this, new EventArgs()); // Depending on the type of protocol, the initial size of the buffer // and the buffer object itself will vary. // For APP messages, it is important that we identify the length of the expected message first // For HTTP messages, the length is stored in the Content-Length parameter // For XML messages, the end of the message is identified by a null or SOH character // create read buffers _RspBfr = new byte[BUFFER_SIZE]; _DataBfr = new byte[BUFFER_SIZE]; Int32 cReadLength = BUFFER_SIZE; byte[] aReadBuffer = _DataBfr; if (_ProtocolType == AisProtocolType.App) { // use response read buffer aReadBuffer = _RspBfr; // read the length field first cReadLength = LENGTH_SIZE; // set APP read state to reading response length _AppReadState = AppReadState.ReadingResponseLength; } _AsyncReadEventArgs = new SocketAsyncEventArgs(); // assign buffer but read only the length field _AsyncReadEventArgs.SetBuffer(aReadBuffer, 0, cReadLength); _AsyncReadEventArgs.Completed += new EventHandler <SocketAsyncEventArgs>(ReceiveComplete); try { // asynchronous receive if (!_RemoteSocket.ReceiveAsync(_AsyncReadEventArgs)) { // if synchronous ProcessReceive(_AsyncReadEventArgs); } } catch (SocketException aEx) { Debug.WriteLine(aEx.Message); // if socket is connected if (_RemoteSocket.Connected) { // disconnect from server _RemoteSocket.Close(); } // notify disconnected event subscribers DisconnectedEvent(this, new EventArgs()); // throw away our socket object _RemoteSocket = null; } } else { // create socket error event object SocketErrorEventArgs aSocketErrorEventArgs = new SocketErrorEventArgs(); aSocketErrorEventArgs.Status = (int)iEvent.SocketError; aSocketErrorEventArgs.Error = "Connect failed"; // notify socket error event subscribers SocketErrorEvent(this, aSocketErrorEventArgs); //MessageBox.Show("Connect failed"); // delete socket _RemoteSocket = null; } }
/// <summary> /// Handles the HTTP response. /// </summary> /// <param name="iEvent">Socket event arguments object.</param> private void ProcessHttp(SocketAsyncEventArgs iEvent) { // resize response buffer if not enough if ((_RspLength + iEvent.BytesTransferred) < _RspBfr.Length) { Array.Resize(ref _RspBfr, _RspLength + iEvent.BytesTransferred); } // append new data to response buffer Array.Copy(iEvent.Buffer, 0, _RspBfr, _RspLength, iEvent.BytesTransferred); // update new response length _RspLength += iEvent.BytesTransferred; Int32 aBeg = 0; Int32 aB = 0; Int32 aEnd = _RspLength; String aTemp = String.Empty; Int32 aMsgLength = 0; byte[] aCookie = null; bool aClear = true; // process response buffer loop while (aBeg < aEnd) { // skip whitespaces while ((Char.IsWhiteSpace((char)_RspBfr[aBeg])) && (aBeg < aEnd)) { aBeg++; } // buffer overflow protection if (aBeg == aEnd) { aClear = false; break; // not enough bytes } // make sure we can read the protocol header if (aBeg + HTTP_HDR.Length > aEnd) { aClear = false; break; // not enough bytes } // read the protocol header aTemp = System.Text.Encoding.ASCII.GetString(_RspBfr, aBeg, HTTP_HDR.Length); if (aTemp != HTTP_HDR) { // EMIT PROTOCOL ERROR SocketErrorEventArgs aSocketError = new SocketErrorEventArgs(); aSocketError.Error = "Unknown Procotol"; SocketErrorEvent(this, aSocketError); break; } aB = aBeg; // extract Set-Cookie and Content-Length loop do { // scan past next newline while (aB < aEnd && ((char)_RspBfr[aB++]) != '\n') { ; } if (aB + SET_COOKIE.Length < aEnd && _RspBfr[aB] == 'S' && _RspBfr[aB + 1] == 'e' && _RspBfr[aB + 2] == 't' && _RspBfr[aB + 3] == '-' && _RspBfr[aB + 4] == 'C' && _RspBfr[aB + 5] == 'o' && _RspBfr[aB + 6] == 'o' && _RspBfr[aB + 7] == 'k' && _RspBfr[aB + 8] == 'i' && _RspBfr[aB + 9] == 'e') { // scan past the colon (:) while ((aB < aEnd) && (_RspBfr[aB++] != ':')) { ; } if (aB < aEnd) { Int32 aEol = 0; if (_RspBfr[aB] == ' ') { aB++; } for (aEol = aB; (aEol < aEnd) && (_RspBfr[aEol] != '\r') && (_RspBfr[aEol] != '\n'); aEol++) { ; } aCookie = new byte[aEol - aB]; Array.Copy(_RspBfr, aB, aCookie, 0, aEol - aB); } } else if (aB + CONTENT_LENGTH.Length < aEnd && _RspBfr[aB] == 'C' && _RspBfr[aB + 1] == 'o' && _RspBfr[aB + 2] == 'n' && _RspBfr[aB + 3] == 't' && _RspBfr[aB + 4] == 'e' && _RspBfr[aB + 5] == 'n' && _RspBfr[aB + 6] == 't' && _RspBfr[aB + 7] == '-' && _RspBfr[aB + 8] == 'L' && _RspBfr[aB + 9] == 'e' && _RspBfr[aB + 10] == 'g' && _RspBfr[aB + 11] == 'n' && _RspBfr[aB + 12] == 't' && _RspBfr[aB + 13] == 'h') { while ((aB < aEnd) && _RspBfr[aB] < '0' || _RspBfr[aB] > '9') { aB++; } // get the content-length if (aB < aEnd) { Int32 aEol = 0; for (aEol = aB; (aEol < aEnd) && (_RspBfr[aEol] != '\r') && (_RspBfr[aEol] != '\n'); aEol++) { ; } aTemp = Encoding.ASCII.GetString(_RspBfr, aB, (aEol - aB)); try { aMsgLength = Int32.Parse(aTemp); } catch (FormatException) { Debug.WriteLine("Invalid Content-Length value."); } } } else if (_RspBfr[aB] == '\r') { aB++; } } // extract Set-Cookie and Content-Length loop while (aB < aEnd && (_RspBfr[aB++]) != '\n'); // partial. save the partial request. // aBeg = Beginning of this message // aB = Beginning of the body of request if (aB + aMsgLength > aEnd) { // if aBeg has been moved past the beginning of the buffer // just keep the partial if (aBeg > 0) { // create new buffer byte[] aNewBfr = new byte[aEnd - aBeg]; Array.Copy(_RspBfr, aBeg, aNewBfr, 0, aNewBfr.Length); _RspBfr = aNewBfr; } aBeg = aB + aMsgLength; // DO NOT CLEAR BUFFER aClear = false; // quit the main loop break; } else { ResponseEventArgs aHtmlResponse = new ResponseEventArgs(); aHtmlResponse.ResponseBuffer = new byte[aMsgLength]; aHtmlResponse.CookieBuffer = aCookie; Array.Copy(_RspBfr, aB, aHtmlResponse.ResponseBuffer, 0, aMsgLength); // emit response signal ResponseEvent(this, aHtmlResponse); // move aBeg to end of body aBeg += aMsgLength; } } if (aClear) { _RspLength = 0; } // call asynchronous read again _RemoteSocket.ReceiveAsync(iEvent); } // end of process response buffer loop
/// <summary> /// Handles the XML response. /// </summary> /// <param name="iEvent">Socket event arguments object.</param> private void ProcessXml(SocketAsyncEventArgs iEvent) { // resize response buffer if not enough if ((_RspLength + iEvent.BytesTransferred) < _RspBfr.Length) { Array.Resize(ref _RspBfr, _RspLength + iEvent.BytesTransferred); } // append new data to response buffer Array.Copy(iEvent.Buffer, 0, _RspBfr, _RspLength, iEvent.BytesTransferred); // update new response length _RspLength += iEvent.BytesTransferred; Int32 aBeg = 0; Int32 aB = 0; Int32 aEnd = _RspLength; String aTemp = String.Empty; bool aClear = true; // process response buffer loop while (aBeg < aEnd) { // skip whitespaces while ((Char.IsWhiteSpace((char)_RspBfr[aBeg])) && (aBeg < aEnd)) { aBeg++; } // buffer overflow protection if (aBeg == aEnd) { aClear = false; break; // not enough bytes } // make sure we can read the protocol header if (aBeg + XML_HDR.Length > aEnd) { aClear = false; break; // not enough bytes } // read the protocol header aTemp = System.Text.Encoding.ASCII.GetString(_RspBfr, aBeg, XML_HDR.Length); if (aTemp != XML_HDR) { // EMIT PROTOCOL ERROR SocketErrorEventArgs aSocketError = new SocketErrorEventArgs(); aSocketError.Error = "Unknown Protocol"; SocketErrorEvent(this, aSocketError); break; } for (aB = aBeg; aB < aEnd && _RspBfr[aB] > MSG_TERM; aB++) { ; } // if read past the last character if (aB == aEnd) { // DO NOT CLEAR BUFFER aClear = false; break; } // partial. save partial request. // aBeg - Beginning of next response // aB - end of this response if (_RspBfr[aB] > MSG_TERM) { // if aBeg has been moved past the beginning of the buffer if (aBeg > 0) { byte[] aNewBuffer = new byte[aEnd - aBeg]; Array.Copy(_RspBfr, aBeg, aNewBuffer, 0, aNewBuffer.Length); _RspBfr = aNewBuffer; } // DO NOT CLEAR BUFFER aClear = false; break; } // NULL terminate the response _RspBfr[aB] = (byte)MSG_NULL; ResponseEventArgs aResponse = new ResponseEventArgs(); aResponse.ResponseBuffer = new byte[aB + 1]; Array.Copy(_RspBfr, aBeg, aResponse.ResponseBuffer, 0, aB + 1); // emit response signal ResponseEvent(this, aResponse); // move aBeg to aBeg = aB + 1; } if (aClear) { _RspLength = 0; } // call asynchronous read again _RemoteSocket.ReceiveAsync(iEvent); }
/// <summary> /// Opens a persistent connection to the AIS server. /// </summary> /// <param name="iHostDnsIP">Hostname or IP Address of the server.</param> /// <param name="iPort">Server port.</param> /// <returns>true if the operation is successful.</returns> /// <remarks>After this function is called, the following events can be received: /// 1. ConnectedEvent - When connection to the server is successful. /// 2. DisconnectedEvent - When connection to the server is closed/disconnected. /// 3. SocketErrorEvent - When there's an error in one of the socket operations. /// 4. ResponseEvent - When there's data received from the server. /// </remarks> public bool OpenConnection(ref String iHostDnsIP, UInt16 iPort) { bool aRet = false; // check parameters and make sure no there's no existing socket connection if (iHostDnsIP.Length > 0 && iPort > 0 && _RemoteSocket == null) { try { IPAddress aIPAdd = null; if (!IPAddress.TryParse(iHostDnsIP, out aIPAdd)) { // resolve host IP IPHostEntry aIPHost = Dns.GetHostEntry(iHostDnsIP); aIPAdd = aIPHost.AddressList[0]; } // create end point object IPEndPoint aEndPt = new IPEndPoint(aIPAdd, iPort); // create our socket object _RemoteSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); /* * // establish connection with the server * _RemoteSocket.Connect(aEndPt); * // notify connected event subscribers * ConnectedEvent(this, new EventArgs()); * * // Depending on the type of protocol, the initial size of the buffer * // and the buffer object itself will vary. * // For APP messages, it is important that we identify the length of the expected message first * // For HTTP messages, the length is stored in the Content-Length parameter * // For XML messages, the end of the message is identified by a null or SOH character * // create read buffers * _RspBfr = new byte[BUFFER_SIZE]; * _DataBfr = new byte[BUFFER_SIZE]; * Int32 cReadLength = BUFFER_SIZE; * byte[] aReadBuffer = _DataBfr; * if (_ProtocolType == AisProtocolType.App) * { // use response read buffer * aReadBuffer = _RspBfr; * // read the length field first * cReadLength = LENGTH_SIZE; * // set APP read state to reading response length * _AppReadState = AppReadState.ReadingResponseLength; * } * _AsyncReadEventArgs = new SocketAsyncEventArgs(); * // assign buffer but read only the length field * _AsyncReadEventArgs.SetBuffer(aReadBuffer, 0, cReadLength); * _AsyncReadEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveComplete); * * // asynchronous receive * if (!_RemoteSocket.ReceiveAsync(_AsyncReadEventArgs)) * { * // if synchronous * ProcessReceive(_AsyncReadEventArgs); * }*/ _AsyncConnEventArgs = new SocketAsyncEventArgs(); _AsyncConnEventArgs.RemoteEndPoint = aEndPt; _AsyncConnEventArgs.Completed += new EventHandler <SocketAsyncEventArgs>(ConnectComplete); if (!_RemoteSocket.ConnectAsync(_AsyncConnEventArgs)) { // if synchronous ProcessConnect(_AsyncConnEventArgs); } // return success aRet = true; } catch (SocketException aEx) { Debug.WriteLine(aEx.Message); // if socket object was created successfully if (_RemoteSocket != null) { // if socket is connected if (_RemoteSocket.Connected) { // disconnect from server _RemoteSocket.Close(); // notify disconnected event subscribers DisconnectedEvent(this, new EventArgs()); } // throw away our socket object _RemoteSocket = null; } else { // create socket error event object SocketErrorEventArgs aSocketErrorEventArgs = new SocketErrorEventArgs(); aSocketErrorEventArgs.Status = aEx.ErrorCode; aSocketErrorEventArgs.Error = aEx.Message; // notify socket error event subscribers SocketErrorEvent(this, aSocketErrorEventArgs); } // return failure aRet = false; } } return(aRet); }