/// <summary> /// Unmarshals a byte array into a FLAP header /// </summary> /// <param name="buffer">A byte array</param> /// <returns>A populated FLAP header</returns> /// <remarks> /// This method always assumes that the FLAP header is at the beginning of /// the buffer. The FLAP header is always the first six bytes of a communication /// frame coming from the server, and it is read into a six-byte buffer by /// itself at the beginning of a socket read operation. /// </remarks> private static FLAPHeader GetFLAPHeader(byte[] buffer) { FLAPHeader retval = new FLAPHeader(); if (buffer != null) { retval.Channel = buffer[1]; retval.DatagramSequenceNumber = (ushort)((buffer[2] << 8) | buffer[3]); retval.DataSize = (ushort)((buffer[4] << 8) | buffer[5]); } return(retval); }
/// <summary> /// Prepends a <see cref="FLAPHeader"/> and a <see cref="SNACHeader"/> into the byte stream /// </summary> public void PrependOscarHeaders(FLAPHeader flap, SNACHeader snac) { lock (this) { dataSegments.Insert(0, new FlapSegment(flap)); byteCount += 6; if (snac != null) { dataSegments.Insert(1, new SnacSegment(snac)); byteCount += 10; } } }
public FlapSegment(FLAPHeader value) { this.value = value; }
/// <summary> /// Processes the asynchronous receipt of a FLAP /// </summary> /// <param name="res">The <see cref="IAsyncResult"/> of a BeginReceive call</param> private void ProcessFLAP(IAsyncResult res) { int bytesreceived = 0; int receiveindex = 0; byte[] flapbuffer = null; try { lock (socket) { bytesreceived = socket.EndRead(res); if (bytesreceived == 0) { throw new Exception("Socket receive returned 0 bytes read"); } flapbuffer = (byte[])res.AsyncState; receiveindex = bytesreceived; while (receiveindex < flapbuffer.Length) { bytesreceived = socket.Read(flapbuffer, receiveindex, flapbuffer.Length - receiveindex); if (bytesreceived == 0) { throw new Exception("Socket receive returned 0 bytes read"); } receiveindex += bytesreceived; } } } catch (Exception ex) { if (!isDisconnecting) { Logging.WriteString("Receive error in ProcessFLAP: {0}, connection {1}", ex.Message, ID); DisconnectFromServer(true); } return; } if (flapbuffer[0] == 0xFF) { int badcount = 0; for (badcount = 0; badcount < flapbuffer.Length && flapbuffer[badcount] == 0xFF; badcount++) { ; } // SOMEHOW there are two bytes of 0xFF occuring when requesting // SNAC family 0x10 and receiving SNAC(01,03). So that has to stop for (int i = badcount; i < flapbuffer.Length; i++) { flapbuffer[i - badcount] = flapbuffer[i]; } socket.Read(flapbuffer, flapbuffer.Length - badcount, badcount); } // Get the FLAP header out of the async result FLAPHeader flap = GetFLAPHeader(flapbuffer); ByteStream stream = ReadPacket(flap.DataSize); if (stream == null) { return; } // The full packet is here, so we can chuck it out for processing DataPacket dp; switch (flap.Channel) { case 0x01: // New connection negotiation // This will not occur, FLAP 0x01 is handled in ConnectToServer break; case 0x02: // SNAC data if (stream.GetByteCount() < 10) { break; // Don't return, don't disconnect, just keep on keeping on } dp = stream.CreateDataPacket(); dp.FLAP = flap; dp.ParentConnection = this; dp.ParentSession = parent; Processor.Enqueue(dp); break; case 0x03: // FLAP error // Session error: FLAP error, bailing out Logging.WriteString("Received error FLAP"); DisconnectFromServer(true); return; case 0x04: // Close connection negotiation //KSD-SYSTEMS - added at 27.11.2009 if (stream.GetByteCount() > 10) { dp = stream.CreateDataPacket(); if (((SNACFamily)dp.SNAC.FamilyServiceID) == SNACFamily.PrivacyManagementService) { PrivacyManagementService sub = (PrivacyManagementService)dp.SNAC.FamilySubtypeID; if (sub == PrivacyManagementService.ServiceParametersRequest) { parent.OnError(ServerErrorCode.ExternalClientRequest, dp); } } } Logging.WriteString("Received close connection FLAP"); DisconnectFromServer(false); return; case 0x05: // Keepalive packet Logging.WriteString("Received keepalive FLAP"); SendKeepalive(null); break; default: break; } // Shine on, you crazy connection keepAliveTimer.Change(60000, Timeout.Infinite); ReadHeader(); }