/// <summary> /// Handles the <see cref="AsyncSocket.DidAccept"/> event. /// </summary> /// <param name="sender">The listening <see cref="AsyncSocket"/></param> /// <param name="newSocket">The new <see cref="AsyncSocket"/> that was accepted</param> private void listenSocket_DidAccept(AsyncSocket sender, AsyncSocket newSocket) { LogInfo("Accepted client {0}:{1}", newSocket.RemoteAddress, newSocket.RemotePort); // check origin bool isLocal = IPAddress.IsLoopback(newSocket.RemoteAddress); bool isLAN = Growl.CoreLibrary.IPUtilities.IsInSameSubnet(newSocket.LocalAddress, newSocket.RemoteAddress); if (!this.allowNetworkNotifications && !isLocal) { // remote connections not allowed - Should we return a GNTP error response? i think this is better (no reply at all) LogInfo("Blocked network request from '{0}'", newSocket.RemoteAddress); newSocket.Close(); return; } bool passwordRequired = true; if (isLocal && !this.RequireLocalPassword) passwordRequired = false; else if (isLAN && !this.RequireLANPassword) passwordRequired = false; // SUPER IMPORTANT newSocket.AllowMultithreadedCallbacks = true; MessageHandler mh = new MessageHandler(this.serverName, this.passwordManager, passwordRequired, this.logFolder, this.loggingEnabled, this.allowNetworkNotifications, this.allowWebNotifications, this.allowSubscriptions); newSocket.DidClose += new AsyncSocket.SocketDidClose(newSocket_DidClose); mh.MessageParsed += new MessageHandler.MessageHandlerMessageParsedEventHandler(mh_MessageParsed); mh.Error += new MessageHandler.MessageHandlerErrorEventHandler(mh_Error); mh.SocketUsageComplete += new MessageHandler.MessageHandlerSocketUsageCompleteEventHandler(mh_SocketUsageComplete); // lock here since in very rare cases, we can get flooded with so many incoming sockets that // the Add() throws an IndexOutOfRange exception (only ever happened when running GrowlHammer with loads of // simultaneous connections) lock (syncLock) { connectedSockets.Add(new ConnectedSocket(newSocket)); connectedHandlers.Add(newSocket, mh); } mh.InitialRead(newSocket); }
/// <summary> /// Handles the socket's DidRead event. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> protected override void SocketDidRead(AsyncSocket socket, byte[] readBytes, long tag) { try { int numberOfBytesToReadNext = 0; long nextTag = 0; if (tag == CONNECTION_ESTABLISHED_TAG) { // wait for a frame and read the first two bytes (containing the FIN, opcode, masking info, and payload length) this.Socket.Read(2, TIMEOUT_UNLIMITED, BEGIN_FRAMING_TAG); } else if (tag == BEGIN_FRAMING_TAG) { // reset this this.AlreadyReceivedData.Remove(0, this.AlreadyReceivedData.Length); this.ParserTag = 1; //TODO: byte bFrameControl = readBytes[0]; byte bDataControl = readBytes[1]; bool end = (bFrameControl & BYTE_FIN_FINAL) == BYTE_FIN_FINAL; // TODO: handle fragments if ((bFrameControl & BYTE_OPCODE_PONG) == BYTE_OPCODE_PONG) { // unsolicited Pong - we dont need to do anything } else if ((bFrameControl & BYTE_OPCODE_PING) == BYTE_OPCODE_PING) { // need to response with Pong // TODO: handle this case } else if ((bFrameControl & BYTE_OPCODE_CLOSE) == BYTE_OPCODE_CLOSE) { // we dont really care about this } else if ((bFrameControl & BYTE_OPCODE_BINARY) == BYTE_OPCODE_BINARY) { // we dont really care about this } else if ((bFrameControl & BYTE_OPCODE_TEXT) == BYTE_OPCODE_TEXT) { // we dont really care about this } else if ((bFrameControl & BYTE_OPCODE_CONTINUATION) == BYTE_OPCODE_CONTINUATION) { // TODO: handle fragments } masked = (bDataControl & BYTE_MASKED_YES) == BYTE_MASKED_YES; int length = (int)(bDataControl & ~BYTE_MASKED_YES); if ((bDataControl & BYTE_LENGTH_16) == BYTE_LENGTH_16) { // read next two bytes for length numberOfBytesToReadNext = 2; nextTag = PAYLOAD_LENGTH_TAG; } else if ((bDataControl & BYTE_LENGTH_64) == BYTE_LENGTH_64) { // read next 8 bytes for length numberOfBytesToReadNext = 8; nextTag = PAYLOAD_LENGTH_TAG; } else { if (masked) { // read 4 byte masking key numberOfBytesToReadNext = 4; nextTag = MASKING_KEY_TAG; payloadRemainingLength = length; } else { numberOfBytesToReadNext = length; nextTag = GNTP_DATA_TAG; payloadRemainingLength = 0; // handle zero-length payload if (numberOfBytesToReadNext == 0) { numberOfBytesToReadNext = 2; nextTag = BEGIN_FRAMING_TAG; } } } // read next chunk of data this.Socket.Read(numberOfBytesToReadNext, TIMEOUT_FRAME, nextTag); } else if (tag == PAYLOAD_LENGTH_TAG) { long length = 0; if (readBytes.Length == 2) { short s = BitConverter.ToInt16(readBytes, 0); s = System.Net.IPAddress.NetworkToHostOrder(s); length = s; } else if (readBytes.Length == 8) { long l = BitConverter.ToInt64(readBytes, 0); l = System.Net.IPAddress.NetworkToHostOrder(l); length = l; } if (masked) { // read 4 byte masking key numberOfBytesToReadNext = 4; nextTag = MASKING_KEY_TAG; payloadRemainingLength = length; } else { if (length > int.MaxValue) { numberOfBytesToReadNext = int.MaxValue; payloadRemainingLength = length - numberOfBytesToReadNext; } else { numberOfBytesToReadNext = (int)length; payloadRemainingLength = 0; } nextTag = GNTP_DATA_TAG; // handle zero-length payload if (numberOfBytesToReadNext == 0) { numberOfBytesToReadNext = 2; nextTag = BEGIN_FRAMING_TAG; } } // read next chunk of data this.Socket.Read(numberOfBytesToReadNext, TIMEOUT_FRAME, nextTag); } else if (tag == MASKING_KEY_TAG) { mask = readBytes; if (payloadRemainingLength > int.MaxValue) { numberOfBytesToReadNext = int.MaxValue; payloadRemainingLength = payloadRemainingLength - numberOfBytesToReadNext; } else { numberOfBytesToReadNext = (int)payloadRemainingLength; payloadRemainingLength = 0; } nextTag = GNTP_DATA_TAG; // handle zero-length payload if (numberOfBytesToReadNext == 0) { numberOfBytesToReadNext = 2; nextTag = BEGIN_FRAMING_TAG; } // read next chunk of data this.Socket.Read(numberOfBytesToReadNext, TIMEOUT_FRAME, nextTag); } else if (tag == GNTP_DATA_TAG) { byte[] unmaskedBytes = null; if (masked) { unmaskedBytes = new byte[readBytes.Length]; for(int i=0;i<readBytes.Length;i++) { int b = i % 4; byte unmaskedByte = (byte) (readBytes[i] ^ mask[b]); unmaskedBytes[i] = unmaskedByte; } } else { unmaskedBytes = readBytes; } parser.Parse(unmaskedBytes); // normally we would want to kick off another socket.Read() here (looking for the next BEGIN_FRAME_TAG), but we currently only allow one request per socket connection } else { // we can only get here if there was some unaccounted-for data. that is bad, so lets close the socket socket.Close(); } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }