//---- internal static System.Net.Sockets.Socket GetAConnectedSocket() { Socket s = SocketPair.GetConnectedSocket(); Debug.Assert(s != null); Debug.Assert(s.Connected); return(s); }
public void PassHandle() { PosixResult result; // server socket var serverSocket = Socket.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, blocking: true); var serverAddress = new IPEndPointStruct(IPAddress.Loopback, 0); serverSocket.Bind(serverAddress); serverAddress = serverSocket.GetLocalIPAddress(); serverSocket.Listen(10); // client connect var clientSocket = Socket.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, blocking: true); clientSocket.TryConnect(serverAddress); // accept and pass socket SocketPair pair = Socket.CreatePair(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified, blocking: false); result = serverSocket.TryAcceptAndSendHandleTo(pair.Socket1); Assert.True(result.IsSuccess); // receive accept socket int acceptSocketFd; result = SocketInterop.ReceiveSocket(pair.Socket2, out acceptSocketFd, blocking: true); Socket acceptSocket = result.IsSuccess ? new Socket(acceptSocketFd) : null; Assert.True(result.IsSuccess); Assert.Equal(1, result.Value); // Send result = clientSocket.TrySend(s_data); // Receive byte[] receiveBuffer = new byte[10]; result = acceptSocket.TryReceive(new ArraySegment <byte>(receiveBuffer)); Assert.True(result.IsSuccess); Assert.Equal(s_data.Count, result.Value); // Close pair.Dispose(); serverSocket.Dispose(); clientSocket.Dispose(); acceptSocket.Dispose(); }
//-------- internal static Socket GetConnectedSocket() { // No need for locking etc here, as it's ok to make one or more (not // many hopefully however!) The socket (is meant!) to be only used on // initialising the base NetworkStream, so it doesn't matter if the // SocketPair is finalized either. Better to create only one, hence // why we cache it. // Careful of a race between accessing it, it becoming null, and the // Finalizer running, so keep a reference locally. SocketPair sp = m_SocketPair; if (sp == null || !sp.Alive) { m_SocketPair = sp = SocketPair.Create(); } return(sp.m_cli); }
public void SocketPair() { SocketPair pair = Socket.CreatePair(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified, blocking: false); PosixResult result; Socket socket1 = new Socket(pair.Socket1); Socket socket2 = new Socket(pair.Socket2); // Send result = socket1.TrySend(s_data); // Receive byte[] receiveBuffer = new byte[10]; result = socket2.TryReceive(new ArraySegment <byte>(receiveBuffer)); Assert.True(result.IsSuccess); Assert.Equal(s_data.Count, result.Value); // Close socket1.Dispose(); socket2.Dispose(); }
private void ReadImpl() { List <IntPtr> dead = null, active = new List <IntPtr>(); IntPtr[] readSockets = EmptyPointers, errorSockets = EmptyPointers; long lastHeartbeat = Environment.TickCount; SocketPair[] allSocketPairs = null; while (true) { active.Clear(); if (dead != null) { dead.Clear(); } // this check is actually a pace-maker; sometimes the Timer callback stalls for // extended periods of time, which can cause socket disconnect long now = Environment.TickCount; if (unchecked (now - lastHeartbeat) >= 15000) { lastHeartbeat = now; lock (socketLookup) { if (allSocketPairs == null || allSocketPairs.Length != socketLookup.Count) { allSocketPairs = new SocketPair[socketLookup.Count]; } socketLookup.Values.CopyTo(allSocketPairs, 0); } foreach (var pair in allSocketPairs) { var callback = pair.Callback; if (callback != null) { try { callback.OnHeartbeat(); } catch { } } } } lock (socketLookup) { if (isDisposed) { return; } if (socketLookup.Count == 0) { // if empty, give it a few seconds chance before exiting Monitor.Wait(socketLookup, TimeSpan.FromSeconds(20)); if (socketLookup.Count == 0) { return; // nothing new came in, so exit } } foreach (var pair in socketLookup) { var socket = pair.Value.Socket; if (socket.Handle == pair.Key && socket.Connected) { if (pair.Value.Socket.Connected) { active.Add(pair.Key); } else { (dead ?? (dead = new List <IntPtr>())).Add(pair.Key); } } } if (dead != null && dead.Count != 0) { foreach (var socket in dead) { socketLookup.Remove(socket); } } } int pollingSockets = active.Count; if (pollingSockets == 0) { // nobody had actual sockets; just sleep Thread.Sleep(10); continue; } if (readSockets.Length < active.Count + 1) { ConnectionMultiplexer.TraceWithoutContext("Resizing socket array for " + active.Count + " sockets"); readSockets = new IntPtr[active.Count + 6]; // leave so space for growth errorSockets = new IntPtr[active.Count + 6]; } readSockets[0] = errorSockets[0] = (IntPtr)active.Count; active.CopyTo(readSockets, 1); active.CopyTo(errorSockets, 1); int ready; try { var timeout = new TimeValue(1000); ready = select(0, readSockets, null, errorSockets, ref timeout); if (ready <= 0) { continue; // -ve typically means a socket was disposed just before; just retry } ConnectionMultiplexer.TraceWithoutContext((int)readSockets[0] != 0, "Read sockets: " + (int)readSockets[0]); ConnectionMultiplexer.TraceWithoutContext((int)errorSockets[0] != 0, "Error sockets: " + (int)errorSockets[0]); } catch (Exception ex) { // this typically means a socket was disposed just before; just retry Trace.WriteLine(ex.Message); continue; } int queueCount = (int)readSockets[0]; lock (readQueue) { for (int i = 1; i <= queueCount; i++) { readQueue.Enqueue(readSockets[i]); } } queueCount = (int)errorSockets[0]; lock (errorQueue) { for (int i = 1; i <= queueCount; i++) { errorQueue.Enqueue(errorSockets[i]); } } if (ready >= 5) // number of sockets we should attempt to process by ourself before asking for help { // seek help, work in parallel, then synchronize var obj = new QueueDrainSyncLock(this); lock (obj) { ThreadPool.QueueUserWorkItem(HelpProcessItems, obj); ProcessItems(); if (!obj.Consume()) { // then our worker arrived and picked up work; we need // to let it finish; note that if it *didn't* get that far // yet, the Consume() call will mean that it never tries Monitor.Wait(obj); } } } else { // just do it ourself ProcessItems(); } } }
private void ReadImpl() { List<IntPtr> dead = null, active = new List<IntPtr>(); List<ISocketCallback> activeCallbacks = new List<ISocketCallback>(); IntPtr[] readSockets = EmptyPointers, errorSockets = EmptyPointers; long lastHeartbeat = Environment.TickCount; SocketPair[] allSocketPairs = null; while (true) { managerState = ManagerState.CheckForHeartbeat; active.Clear(); activeCallbacks.Clear(); if (dead != null) dead.Clear(); // this check is actually a pace-maker; sometimes the Timer callback stalls for // extended periods of time, which can cause socket disconnect long now = Environment.TickCount; if (unchecked(now - lastHeartbeat) >= 15000) { managerState = ManagerState.ExecuteHeartbeat; lastHeartbeat = now; lock (socketLookup) { if (allSocketPairs == null || allSocketPairs.Length != socketLookup.Count) allSocketPairs = new SocketPair[socketLookup.Count]; socketLookup.Values.CopyTo(allSocketPairs, 0); } foreach (var pair in allSocketPairs) { var callback = pair.Callback; if (callback != null) try { callback.OnHeartbeat(); } catch { } } } managerState = ManagerState.LocateActiveSockets; lock (socketLookup) { if (isDisposed) return; if (socketLookup.Count == 0) { // if empty, give it a few seconds chance before exiting managerState = ManagerState.NoSocketsPause; Monitor.Wait(socketLookup, TimeSpan.FromSeconds(20)); if (socketLookup.Count == 0) return; // nothing new came in, so exit } managerState = ManagerState.PrepareActiveSockets; foreach (var pair in socketLookup) { var socket = pair.Value.Socket; if (socket.Handle == pair.Key && socket.Connected) if (pair.Value.Socket.Connected) { active.Add(pair.Key); activeCallbacks.Add(pair.Value.Callback); } else { (dead ?? (dead = new List<IntPtr>())).Add(pair.Key); } } if (dead != null && dead.Count != 0) { managerState = ManagerState.CullDeadSockets; foreach (var socket in dead) socketLookup.Remove(socket); } } int pollingSockets = active.Count; if (pollingSockets == 0) { // nobody had actual sockets; just sleep managerState = ManagerState.NoActiveSocketsPause; Thread.Sleep(10); continue; } if (readSockets.Length < active.Count + 1) { managerState = ManagerState.GrowingSocketArray; ConnectionMultiplexer.TraceWithoutContext("Resizing socket array for " + active.Count + " sockets"); readSockets = new IntPtr[active.Count + 6]; // leave so space for growth errorSockets = new IntPtr[active.Count + 6]; } managerState = ManagerState.CopyingPointersForSelect; readSockets[0] = errorSockets[0] = (IntPtr)active.Count; active.CopyTo(readSockets, 1); active.CopyTo(errorSockets, 1); int ready; try { var timeout = new TimeValue(1000); managerState = ManagerState.ExecuteSelect; ready = select(0, readSockets, null, errorSockets, ref timeout); managerState = ManagerState.ExecuteSelectComplete; if (ready <= 0) // -ve typically means a socket was disposed just before; just retry { bool hasWorkToDo = false; if (ready == 0) { managerState = ManagerState.CheckForStaleConnections; foreach (var s in activeCallbacks) { if (s.IsDataAvailable) { hasWorkToDo = true; } else { s.CheckForStaleConnection(); } } } else { lastErrorTicks = Environment.TickCount; } if (!hasWorkToDo) { continue; } } ConnectionMultiplexer.TraceWithoutContext((int)readSockets[0] != 0, "Read sockets: " + (int)readSockets[0]); ConnectionMultiplexer.TraceWithoutContext((int)errorSockets[0] != 0, "Error sockets: " + (int)errorSockets[0]); } catch (Exception ex) { // this typically means a socket was disposed just before; just retry Trace.WriteLine(ex.Message); continue; } bool haveWork = false; int queueCount = (int)readSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueRead; lock (readQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(readSockets[i]); if (callback != null) { readQueue.Enqueue(callback); haveWork = true; } } } } queueCount = (int)errorSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueError; lock (errorQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(errorSockets[i]); if (callback != null) { errorQueue.Enqueue(callback); haveWork = true; } } } } if(!haveWork) { // edge case: select is returning 0, but data could still be available managerState = ManagerState.EnqueueReadFallback; lock (readQueue) { foreach (var callback in activeCallbacks) { if(callback.IsDataAvailable) { readQueue.Enqueue(callback); } } } } if (ready >= 5) // number of sockets we should attempt to process by ourself before asking for help { // seek help, work in parallel, then synchronize var obj = new QueueDrainSyncLock(this); lock (obj) { managerState = ManagerState.RequestAssistance; ThreadPool.QueueUserWorkItem(HelpProcessItems, obj); managerState = ManagerState.ProcessQueues; ProcessItems(true); if (!obj.Consume()) { // then our worker arrived and picked up work; we need // to let it finish; note that if it *didn't* get that far // yet, the Consume() call will mean that it never tries Monitor.Wait(obj); } } } else { // just do it ourself managerState = ManagerState.ProcessQueues; ProcessItems(true); } } }
private void ReadImpl() { List <IntPtr> dead = null, active = new List <IntPtr>(); List <ISocketCallback> activeCallbacks = new List <ISocketCallback>(); IntPtr[] readSockets = EmptyPointers, errorSockets = EmptyPointers; long lastHeartbeat = Environment.TickCount; SocketPair[] allSocketPairs = null; while (true) { managerState = ManagerState.CheckForHeartbeat; active.Clear(); activeCallbacks.Clear(); if (dead != null) { dead.Clear(); } // this check is actually a pace-maker; sometimes the Timer callback stalls for // extended periods of time, which can cause socket disconnect long now = Environment.TickCount; if (unchecked (now - lastHeartbeat) >= 15000) { managerState = ManagerState.ExecuteHeartbeat; lastHeartbeat = now; lock (socketLookup) { if (allSocketPairs == null || allSocketPairs.Length != socketLookup.Count) { allSocketPairs = new SocketPair[socketLookup.Count]; } socketLookup.Values.CopyTo(allSocketPairs, 0); } foreach (var pair in allSocketPairs) { var callback = pair.Callback; if (callback != null) { try { callback.OnHeartbeat(); } catch { } } } } managerState = ManagerState.LocateActiveSockets; lock (socketLookup) { if (isDisposed) { return; } if (socketLookup.Count == 0) { // if empty, give it a few seconds chance before exiting managerState = ManagerState.NoSocketsPause; Monitor.Wait(socketLookup, TimeSpan.FromSeconds(20)); if (socketLookup.Count == 0) { return; // nothing new came in, so exit } } managerState = ManagerState.PrepareActiveSockets; foreach (var pair in socketLookup) { var socket = pair.Value.Socket; if (socket.Handle == pair.Key && socket.Connected) { if (pair.Value.Socket.Connected) { active.Add(pair.Key); activeCallbacks.Add(pair.Value.Callback); } else { (dead ?? (dead = new List <IntPtr>())).Add(pair.Key); } } } if (dead != null && dead.Count != 0) { managerState = ManagerState.CullDeadSockets; foreach (var socket in dead) { socketLookup.Remove(socket); } } } int pollingSockets = active.Count; if (pollingSockets == 0) { // nobody had actual sockets; just sleep managerState = ManagerState.NoActiveSocketsPause; Thread.Sleep(10); continue; } if (readSockets.Length < active.Count + 1) { managerState = ManagerState.GrowingSocketArray; ConnectionMultiplexer.TraceWithoutContext("Resizing socket array for " + active.Count + " sockets"); readSockets = new IntPtr[active.Count + 6]; // leave so space for growth errorSockets = new IntPtr[active.Count + 6]; } managerState = ManagerState.CopyingPointersForSelect; readSockets[0] = errorSockets[0] = (IntPtr)active.Count; active.CopyTo(readSockets, 1); active.CopyTo(errorSockets, 1); int ready; try { var timeout = new TimeValue(1000); managerState = ManagerState.ExecuteSelect; ready = select(0, readSockets, null, errorSockets, ref timeout); managerState = ManagerState.ExecuteSelectComplete; if (ready <= 0) // -ve typically means a socket was disposed just before; just retry { bool hasWorkToDo = false; if (ready == 0) { managerState = ManagerState.CheckForStaleConnections; foreach (var s in activeCallbacks) { if (s.IsDataAvailable) { hasWorkToDo = true; } else { #pragma warning disable 0420 s.CheckForStaleConnection(ref managerState); #pragma warning restore 0420 } } managerState = ManagerState.CheckForStaleConnectionsDone; } else { lastErrorTicks = Environment.TickCount; } if (!hasWorkToDo) { continue; } } ConnectionMultiplexer.TraceWithoutContext((int)readSockets[0] != 0, "Read sockets: " + (int)readSockets[0]); ConnectionMultiplexer.TraceWithoutContext((int)errorSockets[0] != 0, "Error sockets: " + (int)errorSockets[0]); } catch (Exception ex) { // this typically means a socket was disposed just before; just retry Trace.WriteLine(ex.Message); continue; } bool haveWork = false; int queueCount = (int)readSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueRead; lock (readQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(readSockets[i]); if (callback != null) { readQueue.Enqueue(callback); haveWork = true; } } } } queueCount = (int)errorSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueError; lock (errorQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(errorSockets[i]); if (callback != null) { errorQueue.Enqueue(callback); haveWork = true; } } } } if (!haveWork) { // edge case: select is returning 0, but data could still be available managerState = ManagerState.EnqueueReadFallback; lock (readQueue) { foreach (var callback in activeCallbacks) { if (callback.IsDataAvailable) { readQueue.Enqueue(callback); } } } } if (ready >= 5) // number of sockets we should attempt to process by ourself before asking for help { // seek help, work in parallel, then synchronize var obj = new QueueDrainSyncLock(this); lock (obj) { managerState = ManagerState.RequestAssistance; ThreadPool.QueueUserWorkItem(HelpProcessItems, obj); managerState = ManagerState.ProcessQueues; ProcessItems(true); if (!obj.Consume()) { // then our worker arrived and picked up work; we need // to let it finish; note that if it *didn't* get that far // yet, the Consume() call will mean that it never tries Monitor.Wait(obj); } } } else { // just do it ourself managerState = ManagerState.ProcessQueues; ProcessItems(true); } } }
/// <summary> /// Message callback function /// Send user data back based on first connect or message /// </summary> /// <param name="AR"></param> private static void ReceiveCallback(IAsyncResult AR) { Socket current = (Socket)AR.AsyncState; int received; if (!current.Connected) { return; } try { received = current.EndReceive(AR); } catch (SocketException) { Console.WriteLine("Client forcefully disconnected"); // Don't shutdown because the socket may be disposed and its disconnected anyway. current.Close(); SocketPair socketToRemove = null; foreach (SocketPair s in clientSockets) { if (s.socket.Equals(current)) { socketToRemove = s; break; } } if (socketToRemove != null) { clientSockets.Remove(socketToRemove); T2SClientMessage otherClient = new T2SClientMessage() { Connected = false, MacAddr = socketToRemove.MacAddr }; byte[] otherClientBuffer = MainWindow.ObjectToByteArray(otherClient); byte[] otherClientBufferMessage = new byte[otherClientBuffer.Length + 33]; //message to send; appends length of header string otherClientHeader = otherClientBuffer.Length.ToString(); for (int i = otherClientHeader.Length; i < 32; i++) { otherClientHeader += " "; //Append empty spaces until header is max length (32) } otherClientHeader += "|"; Array.Copy(Encoding.ASCII.GetBytes(otherClientHeader), otherClientBufferMessage, 33); Array.Copy(otherClientBuffer, 0, otherClientBufferMessage, 33, otherClientBuffer.Length); //Sendto everyone foreach (SocketPair s in clientSockets) { s.socket.Send(otherClientBufferMessage); } } return; } if (received == 0) { Console.WriteLine("No bytes received; closing socket"); SocketPair socketToRemove = null; foreach (SocketPair s in clientSockets) { if (s.socket.Equals(current)) { socketToRemove = s; break; } } if (socketToRemove.socket.Connected) { socketToRemove.socket.Close(); } clientSockets.Remove(socketToRemove); T2SClientMessage otherClient = new T2SClientMessage() { Connected = false, MacAddr = socketToRemove.MacAddr }; byte[] otherClientBuffer = MainWindow.ObjectToByteArray(otherClient); byte[] otherClientBufferMessage = new byte[otherClientBuffer.Length + 33]; //message to send; appends length of header string otherClientHeader = otherClientBuffer.Length.ToString(); for (int i = otherClientHeader.Length; i < 32; i++) { otherClientHeader += " "; //Append empty spaces until header is max length (32) } otherClientHeader += "|"; Array.Copy(Encoding.ASCII.GetBytes(otherClientHeader), otherClientBufferMessage, 33); Array.Copy(otherClientBuffer, 0, otherClientBufferMessage, 33, otherClientBuffer.Length); //Sendto everyone foreach (SocketPair s in clientSockets) { if (s.socket.Connected) { s.socket.Send(otherClientBufferMessage); } } return; } byte[] recBuf = new byte[received]; //Received buffer which should be the header to tell us the buffer length of the json message (should be length 33 with pipe at the end) Array.Copy(buffer, recBuf, received); //Get until header is filled while (received < 33) { byte[] tempBuffer = new byte[33 - received]; int appendableBytes = current.Receive(tempBuffer, 33 - received, SocketFlags.None); Array.Copy(tempBuffer, 0, recBuf, received, tempBuffer.Length); received += appendableBytes; } int headerReceived; if (Int32.TryParse(Encoding.ASCII.GetString(recBuf).Split('|')[0], out headerReceived)) { recBuf = new byte[headerReceived]; received = current.Receive(recBuf, headerReceived, SocketFlags.None); //Get until object is filled while (received < headerReceived) { byte[] tempBuffer = new byte[headerReceived - received]; int appendableBytes = current.Receive(tempBuffer, headerReceived - received, SocketFlags.None); Array.Copy(tempBuffer, 0, recBuf, received, tempBuffer.Length); received += appendableBytes; } } byte[] temp = new byte[recBuf.Length]; Array.Copy(recBuf, temp, temp.Length); string header = recBuf.Length.ToString(); //If the header length is larger than the maximum length, we're gonna assume that the dude is trying to destroy someone with a fat receive. //There's no reason for something to be this large //Therefore, just let the sender know that their message is waaaay too big if (header.Length < 32) { for (int i = header.Length; i < 32; i++) { header += " "; //Append empty spaces until header is max length (32) } byte[] headerBytes = Encoding.ASCII.GetBytes(header + "|"); T2SClientMessage clientMessage = (T2SClientMessage)MainWindow.ByteArrayToObject(recBuf); temp = MainWindow.ObjectToByteArray(clientMessage); recBuf = new byte[temp.Length + headerBytes.Length]; Array.Copy(headerBytes, recBuf, headerBytes.Length); Array.Copy(temp, 0, recBuf, 33, temp.Length); byte[] message = recBuf; //Append message with the header //Send to all connected sockets except self foreach (SocketPair s in clientSockets) { if (s.socket != current) { s.socket.Send(message); } } if (clientMessage.UpdateProfile) { foreach (SocketPair s in clientSockets) { if (s.MacAddr == clientMessage.MacAddr) { s.ProfilePicture = (clientMessage.ProfilePicture == null) ? s.ProfilePicture : clientMessage.ProfilePicture; s.Username = clientMessage.Username; break; } } } //If this is the first connection, we need to update our socketpair MacAddr for audit (also just send back to client) if (clientMessage.FirstConnect) { Console.WriteLine("First connect: " + clientMessage.Username); foreach (SocketPair s in clientSockets) { if (s.socket == current) { s.MacAddr = clientMessage.MacAddr; s.Username = clientMessage.Username; s.ProfilePicture = clientMessage.ProfilePicture; } else { T2SClientMessage otherClient = new T2SClientMessage() { FirstConnect = true, ProfilePicture = s.ProfilePicture, Username = s.Username, MacAddr = s.MacAddr }; byte[] otherClientBuffer = MainWindow.ObjectToByteArray(otherClient); byte[] otherClientBufferMessage = new byte[otherClientBuffer.Length + 33]; //message to send; appends length of header string otherClientHeader = otherClientBuffer.Length.ToString(); for (int i = otherClientHeader.Length; i < 32; i++) { otherClientHeader += " "; //Append empty spaces until header is max length (32) } otherClientHeader += "|"; Array.Copy(Encoding.ASCII.GetBytes(otherClientHeader), otherClientBufferMessage, 33); Array.Copy(otherClientBuffer, 0, otherClientBufferMessage, 33, otherClientBuffer.Length); current.Send(otherClientBufferMessage); } } current.Send(message); //Send the profile back to themself } } else { Console.WriteLine("HEADER TOO LARGE!!! Header length: " + header.Length); } current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current); }