/// <summary> /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. /// </summary> /// <param name="buffer">An array of bytes.</param> /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param> /// <param name="count">The number of bytes to be written to the current stream.</param> public override void Write(byte[] buffer, int offset, int count) { BinaryLogWriter binaryLogWriter = this._remote.ITransportContext.BinaryLogWriter; try { while (count > 0) { int milliseconds = GenuineUtility.GetMillisecondsLeft(this._writeTimeout); if (milliseconds <= 0) { throw GenuineExceptions.Get_Send_Timeout(); } this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, milliseconds); int bytesSent = this._socket.Send(buffer, offset, count, SocketFlags.None); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "SyncSocketWritingStream.Write", LogMessageType.LowLevelTransport_SyncSendingCompleted, null, null, this._remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, count)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this._dbgConnectionId, count, this._socket.RemoteEndPoint.ToString(), null, null, "Immediately after Socket.Send(). Size: {0}. Sent: {1}.", count, bytesSent); } if (bytesSent == 0) { throw GenuineExceptions.Get_Send_TransportProblem(); } offset += bytesSent; count -= bytesSent; this._connectionManager.IncreaseBytesSent(bytesSent); } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "SyncSocketWritingStream.Write", LogMessageType.LowLevelTransport_SyncSendingCompleted, ex, null, this._remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, count)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this._dbgConnectionId, count, null, null, null, "Socket.Send(); ERROR."); } throw GenuineExceptions.Get_Send_TransportProblem(); } }
/// <summary> /// Sends a message synchronously. Does not process exceptions! /// </summary> /// <param name="content">The content being sent to the remote host.</param> /// <param name="timeout">The sending must be completed before this moment.</param> public void LowLevel_SendSync(Stream content, int timeout) { // apply the connection-level security session if (this.ConnectionLevelSecurity != null) { GenuineChunkedStream outputStream = new GenuineChunkedStream(true); this.ConnectionLevelSecurity.Encrypt(content, outputStream); content = outputStream; } for ( ; ;) { if (!this.IsValid) { throw GenuineExceptions.Get_Processing_TransportConnectionFailed(); } if (!GenuineUtility.WaitOne(_namedEventRemoteReadCompleted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(timeout))) { throw GenuineExceptions.Get_Send_Timeout(); } if (this._closed != 0) { throw GenuineExceptions.Get_Receive_ConnectionClosed(); } this._namedEventRemoteReadCompleted.ManualResetEvent.Reset(); // read the next portion int bytesRead = content.Read(this._sendBuffer, 0, this._sendSpaceSize); // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "GenuineSaredMemoryConnection.LowLevel_SendSync", LogMessageType.LowLevelTransport_AsyncSendingInitiating, null, null, this.Remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(this._sendBuffer, 0, bytesRead) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, bytesRead, null, null, null, "Content sending."); } Marshal.Copy(this._sendBuffer, 0, (IntPtr)(this._pointer.ToInt32() + this._sendOffset + SHARE_CONTENT_OFFSET), bytesRead); this._MessageToSendTotalSize = bytesRead; this._MessageToSendFinishFlag = bytesRead < this._sendSpaceSize ? 1 : 0; this._namedEventWriteCompleted.ManualResetEvent.Set(); if (bytesRead < this._sendSpaceSize) { this.UpdateLastTimeAMessageWasSent(); return; } } }
/// <summary> /// Reads data from the socket. /// </summary> /// <param name="buffer">An array of type Byte that is the storage location for received data.</param> /// <param name="offset">The location in buffer to store the received data.</param> /// <param name="count">The number of bytes to receive.</param> /// <returns>The number of bytes read.</returns> public int ReadFromSocket(byte[] buffer, int offset, int count) { BinaryLogWriter binaryLogWriter = this._tcpConnectionManager.ITransportContext.BinaryLogWriter; try { int millisecondsRemained = GenuineUtility.GetMillisecondsLeft(this._receiveTimeout); if (millisecondsRemained <= 0) { throw GenuineExceptions.Get_Send_ServerDidNotReply(); } this._tcpSocketInfo.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, millisecondsRemained); int bytesReceived = this._tcpSocketInfo.Socket.Receive(buffer, offset, count, SocketFlags.None); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "SyncSocketReadingStream.ReadFromSocket", LogMessageType.LowLevelTransport_SyncReceivingCompleted, null, null, this._tcpSocketInfo.Remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(buffer, offset, bytesReceived) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this._tcpSocketInfo.DbgConnectionId, bytesReceived, this._tcpSocketInfo.Socket.RemoteEndPoint.ToString(), null, null, "Socket.Receive(). Bytes received: {0}.", bytesReceived); } this._tcpConnectionManager.IncreaseBytesReceived(bytesReceived); return(bytesReceived); } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteEvent(LogCategory.LowLevelTransport, "SyncSocketReadingStream.ReadFromSocket", LogMessageType.LowLevelTransport_SyncReceivingCompleted, ex, null, this._tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, this._tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "Socket.Receive() failed."); } throw; } }
/// <summary> /// Synchronously reads the next network packet if it is available. /// </summary> private void ReadNextPortion() { if (!this.IsValid) { throw GenuineExceptions.Get_Processing_TransportConnectionFailed(); } this._namedEventReadCompleted.ManualResetEvent.Set(); if (!GenuineUtility.WaitOne(this._namedEventRemoteWriteCompleted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(this._readDeadline))) { throw GenuineExceptions.Get_Send_Timeout(); } this._namedEventRemoteWriteCompleted.ManualResetEvent.Reset(); this._validLength = this._MessageToReceiveTotalSize; this._currentPosition = 0; this._messageRead = this._MessageToReceiveFinishFlag != 0; // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { bool writeContent = binaryLogWriter[LogCategory.LowLevelTransport] > 1; byte[] receivedData = new byte[this._validLength]; Marshal.Copy((IntPtr)(this._pointer.ToInt32() + this._receiveOffset + this._currentPosition + SHARE_CONTENT_OFFSET), receivedData, 0, this._validLength); binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "GenuineSaredMemoryConnection.ReadNextPortion", LogMessageType.LowLevelTransport_SyncReceivingCompleted, null, null, this.Remote, writeContent ? new MemoryStream(receivedData, 0, this._validLength) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, this._validLength, null, null, null, "Content received."); } }
/// <summary> /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. /// </summary> /// <param name="buffer">An array of bytes.</param> /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param> /// <param name="count">The number of bytes to be written to the current stream.</param> public override void Write(byte[] buffer, int offset, int count) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; int milliseconds = GenuineUtility.GetMillisecondsLeft(this._syncWritingTimeout); if (milliseconds <= 0) { throw GenuineExceptions.Get_Send_Timeout(); } try { this.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, milliseconds); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "TcpSocketInfo.Write", LogMessageType.SynchronousSendingStarted, null, null, this.Remote == null ? null : this.Remote, binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, count)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, count, this.Remote == null || this.Remote.PhysicalAddress == null ? null : this.Remote.PhysicalAddress.ToString(), null, null, "The content is being sent synchronously. Size: {0}.", count); } for ( ; ;) { int bytesSent = 0; try { bytesSent = this.Socket.Send(buffer, offset, count, SocketFlags.None); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "TcpSocketInfo.Write", LogMessageType.LowLevelTransport_SyncSendingCompleted, null, null, this.Remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, bytesSent)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, bytesSent, this.Socket.RemoteEndPoint.ToString(), null, null, "Socket.Send(). Size: {0}. Sent: {1}.", count, bytesSent); } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "TcpSocketInfo.Write", LogMessageType.LowLevelTransport_SyncSendingCompleted, ex, null, this.Remote == null ? null : this.Remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, bytesSent)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, bytesSent, this.Socket.RemoteEndPoint.ToString(), null, null, "Socket.Send() failed. Size: {0}. Sent: {1}.", count, bytesSent); } } if (bytesSent == 0) { throw GenuineExceptions.Get_Send_TransportProblem(); } offset += bytesSent; count -= bytesSent; if (count <= 0) { break; } } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0) { binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpSocketInfo.Write", LogMessageType.SynchronousSendingStarted, ex, null, this.Remote == null ? null : this.Remote, binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(buffer, offset, count)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, this.DbgConnectionId, 0, 0, 0, count.ToString(), null, null, null, "An exception is raised during synchronous sending."); } throw GenuineExceptions.Get_Send_TransportProblem(); } }
/// <summary> /// Sends the message to the remote host. /// </summary> /// <param name="message">The message to be sent.</param> protected override void InternalSend(Message message) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; // get IP end point of the remote host IPEndPoint remoteEndPoint; if (message.Recipient.Uri != null && message.Recipient.Uri.StartsWith("_gb")) { remoteEndPoint = this._multicastTo; } else { remoteEndPoint = message.Recipient.PhysicalAddress as IPEndPoint; } if (remoteEndPoint == null) { try { int port; string baseUrl = GenuineUtility.SplitToHostAndPort(message.Recipient.Url, out port); message.Recipient.PhysicalAddress = remoteEndPoint = new IPEndPoint(GenuineUtility.ResolveIPAddress(baseUrl), port); } catch (Exception) { throw GenuineExceptions.Get_Send_DestinationIsUnreachable(message.Recipient.ToString()); } } Stream streamToSend = message.SerializedContent; // write the host URI if ((int)this.ITransportContext.IParameterProvider[GenuineParameter.CompatibilityLevel] > 0) { GenuineChunkedStream streamWith250Header = new GenuineChunkedStream(false); BinaryWriter binaryWriter = new BinaryWriter(streamWith250Header); streamWith250Header.Write(this.ITransportContext.BinaryHostIdentifier, 0, this.ITransportContext.BinaryHostIdentifier.Length); binaryWriter.Write((int)message.Recipient.LocalHostUniqueIdentifier); binaryWriter.Write((Int16)0); streamWith250Header.WriteStream(streamToSend); streamToSend = streamWith250Header; } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0) { binaryLogWriter.WriteEvent(LogCategory.Connection, "UdpConnectionManager.InternalSend", LogMessageType.MessageIsSentSynchronously, null, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, message.ConnectionLevelSecuritySession, message.ConnectionLevelSecuritySession == null ? null : message.ConnectionLevelSecuritySession.Name, -1, 0, 0, 0, remoteEndPoint.ToString(), null, null, null, "The message is being sent synchronously to {0}.", remoteEndPoint.ToString()); } // send the message byte[] streamId = Guid.NewGuid().ToByteArray(); lock (_socketLock) { for (int chunkNumber = 1; ; chunkNumber++) { // read the next chunk int chunkSize = streamToSend.Read(this._sendBuffer, HEADER_SIZE, this._sendBuffer.Length - HEADER_SIZE); // fill in the header this._sendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE; Buffer.BlockCopy(streamId, 0, this._sendBuffer, 1, 16); if (chunkSize < this._sendBuffer.Length - HEADER_SIZE) { chunkNumber = -chunkNumber; } MessageCoder.WriteInt32(this._sendBuffer, 17, chunkNumber); // and just send it! // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "UdpConnectionManager.InternalSend", LogMessageType.SynchronousSendingStarted, null, message, message.Recipient, binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(this._sendBuffer, 0, chunkSize + HEADER_SIZE)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, chunkSize + HEADER_SIZE, remoteEndPoint.ToString(), null, null, "Content is sent synchronously to {0}.", remoteEndPoint.ToString()); } this._socket.SendTo(this._sendBuffer, 0, chunkSize + HEADER_SIZE, SocketFlags.None, remoteEndPoint); if (chunkNumber < 0) { break; } } } }
/// <summary> /// Receives the content synchronously. /// </summary> private void ReceiveSynchronously() { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; byte[] receiveBuffer = null; this._receivingThreadClosed.Reset(); try { int mtu = (int)this.ITransportContext.IParameterProvider[GenuineParameter.UdpMtu]; for ( ; ;) { if (this._closing) { return; } if (BufferPool.GENERAL_BUFFER_SIZE >= mtu) { receiveBuffer = BufferPool.ObtainBuffer(); } else { receiveBuffer = new byte[mtu]; } try { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0); EndPoint endPointReference = ipEndPoint; int bytesReceived = this._socket.ReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref endPointReference); ipEndPoint = (IPEndPoint)endPointReference; // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "UdpConnectionManager.ReceiveSynchronously", LogMessageType.ReceivingFinished, null, null, null, binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(receiveBuffer, 0, bytesReceived)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, bytesReceived, ipEndPoint.ToString(), null, null, "Content is received from {0}.", ipEndPoint.ToString()); } // parse the header if (bytesReceived < HEADER_SIZE) { throw GenuineExceptions.Get_Receive_IncorrectData(); } if (receiveBuffer[0] != MessageCoder.COMMAND_MAGIC_CODE) { throw GenuineExceptions.Get_Receive_IncorrectData(); } // get the packet identifier byte[] guidBuffer = new byte[16]; Buffer.BlockCopy(receiveBuffer, 1, guidBuffer, 0, 16); Guid packetGuid = new Guid(guidBuffer); // and chunk number int chunkNumber = MessageCoder.ReadInt32(receiveBuffer, 17); bool isLast = chunkNumber < 0; if (chunkNumber < 0) { chunkNumber = -chunkNumber; } chunkNumber--; // process the chunk StreamAssembled streamAssembled; lock (this._streams.SyncRoot) { streamAssembled = this._streams[packetGuid] as StreamAssembled; if (streamAssembled == null) { this._streams[packetGuid] = streamAssembled = new StreamAssembled(ipEndPoint, HEADER_SIZE); } if (streamAssembled.IsProcessed) { continue; } } string uri = "gudp://" + ipEndPoint.ToString(); HostInformation remote = this.ITransportContext.KnownHosts[uri]; remote.Renew(this._closeInvocationConnectionAfterInactivity, false); if ((int)this.ITransportContext.IParameterProvider[GenuineParameter.CompatibilityLevel] <= 0) { remote.UpdateUri(uri, 0, false); } if (streamAssembled.BufferReceived(chunkNumber, receiveBuffer, bytesReceived, isLast)) { // prepare it for processing this._streams.Remove(packetGuid); streamAssembled.IsProcessed = true; // read the remote host URI if ((int)this.ITransportContext.IParameterProvider[GenuineParameter.CompatibilityLevel] > 0) { BinaryReader binaryReader = new BinaryReader(streamAssembled); // read the URI byte[] uriBuffer = new byte[16]; GenuineUtility.ReadDataFromStream(streamAssembled, uriBuffer, 0, uriBuffer.Length); Guid remoteHostUriGuid = new Guid(uriBuffer); string receivedUri = "_gudp://" + remoteHostUriGuid.ToString("N"); // read the remote host unique identifier int remoteHostUniqueIdentifier = binaryReader.ReadInt32(); // update the host information remote.UpdateUri(receivedUri, remoteHostUniqueIdentifier, false); // and skip the skip space GenuineUtility.CopyStreamToStream(streamAssembled, Stream.Null, binaryReader.ReadInt16()); } // LOG: if (remote.PhysicalAddress == null && binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0) { binaryLogWriter.WriteHostInformationEvent("UdpConnectionManager.ReceiveSynchronously", LogMessageType.HostInformationCreated, null, remote, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, this.DbgConnectionId, "HostInformation is ready for actions."); } remote.PhysicalAddress = endPointReference; this.ITransportContext.IIncomingStreamHandler.HandleMessage(streamAssembled, remote, GenuineConnectionType.Persistent, string.Empty, -1, false, this._iMessageRegistrator, null, null); } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0) { binaryLogWriter.WriteEvent(LogCategory.Connection, "UdpConnectionManager.ReceiveSynchronously", LogMessageType.ReceivingFinished, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, this.DbgConnectionId, 0, 0, 0, null, null, null, null, "UDP socket failure."); } if (this._closing) { return; } this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GUdpSocketException, ex, this.Local, null)); } } } finally { this._receivingThreadClosed.Set(); } }