public Partner(Socket s, SecondLevelCacheClusterTransportBase t) { ClientSocket = s; Definition = t; HeaderBuffer = new byte[t.HeaderLength]; alias = name = s.RemoteEndPoint.ToString(); }
static void ReadCallback(IAsyncResult ar) { // Retrieve the state object and the handler socket from the asynchronous state object. Partner source = (Partner)ar.AsyncState; bool close = false; try { // Read data from the client socket. int bytesRead = source.ClientSocket.EndReceive(ar); // TODO Handle situations when the messages get fragmented and not all bytes are returned immediately. if (bytesRead == source.Definition.HeaderLength) { SecondLevelCacheClusterTransportBase.OpCode code; int len = source.Definition.ReadHeader(source.HeaderBuffer, out code); if (len > definition.MaxMessageSize) { close = true; // A little protection must be. } else if (len > 0 && (code & SecondLevelCacheClusterTransportBase.OpCode.Evict) != 0) { var tmp = new byte[len + source.Definition.HeaderLength]; Buffer.BlockCopy(source.HeaderBuffer, 0, tmp, 0, source.Definition.HeaderLength); // Assumption: Because the sender pushes one message, we should have all bytes received in the // OS already, and we can use synchronous calls here without negative effects. if (SecondLevelCacheClusterTransportBase.ReceiveAll(source.ClientSocket, tmp, source.Definition.HeaderLength, len)) { source.Evictions++; var bc = new Broadcast() { Data = tmp, Sender = source }; Console.WriteLine("RECEIVED #{0} of {1} bytes from {2}", bc.Number, tmp.Length, source); // Let some other thread do the work of actually sending the message out. ThreadPool.QueueUserWorkItem(PerformBroadcast, bc); } else { Console.WriteLine("Data truncation {0} bytes from {1}", len, source); close = true; } } else { if ((code & SecondLevelCacheClusterTransportBase.OpCode.Hello) != 0) { var nameBytes = new byte[len]; if (SecondLevelCacheClusterTransportBase.ReceiveAll(source.ClientSocket, nameBytes, 0, len)) { try { var name = Encoding.UTF8.GetString(nameBytes); source.SetAlias(name); Console.WriteLine("HELLO {0}", source); Buffer.BlockCopy(BitConverter.GetBytes((int)SecondLevelCacheClusterTransportBase.OpCode.Welcome), 0, source.HeaderBuffer, definition.HeaderLength - 4, 4); close = SecondLevelCacheClusterTransportBase.SendAll(source.ClientSocket, source.HeaderBuffer, 0, source.HeaderBuffer.Length) == false; } catch { close = true; } } else { close = true; } } else { Console.WriteLine("RECEIVED {0} / {1} from {2}", code, len, source); } } } else { close = true; } } catch { close = true; } if (close) { // Something went wrong, let's disconnect from the partner. Maybe a better handling can be done. source.ClientSocket.Shutdown(SocketShutdown.Both); source.ClientSocket.Close(); source.ClientSocket.Dispose(); lock (clients) { clients.Remove(source); Console.WriteLine("DISCONNECTED {0}", source); } } else { // Immediately try to receive the next message from the same partner. source.ClientSocket.BeginReceive(source.HeaderBuffer, 0, source.HeaderBuffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), source); } }