/// <summary> /// Воссоздает объект FLAPHeader из массива байтов с заголовком в начале. /// </summary> /// <param name="buffer">Массив для обработки</param> /// <param name="flapDataLength">Сообщает размер тела FLAP, следующих за заголовком.</param> /// <param name="checkIDByte"> /// Ожидаемое значение FLAPHeader.ID для этого приложения; при нарушении создается исключение. /// </param> public static FLAPHeader FromBytes(byte[] buffer, out ushort flapDataLength, byte checkIDByte) { var flapHeader = new FLAPHeader { ID = buffer[0], Channel = buffer[1], SequenceNumber = XBitConvert.ToUInt16(buffer, 2) }; flapDataLength = XBitConvert.ToUInt16(buffer, 4); if (flapHeader.ID != checkIDByte) { if (Misc.CompareByteArrays(buffer, InvalidHeaderBytes)) throw new System.IO.IOException("Received invalid/empty FLAP header; or Receive data failed."); else throw new System.Net.ProtocolViolationException("Unexpected FLAPHeader.ID value: " + flapHeader + ". Expected: " + checkIDByte); } return flapHeader; }
public static void Make(ref FLAPHeader flap, ref byte[] packet, sSNACType type, TLVChain tlvs, uint requestID = 0, eSNACFlags snacFlags = eSNACFlags.None) { flap.Channel = (byte)eFLAPChannel.SNACPacket; var snac = new SNAC(type, requestID, snacFlags); snac.Data = (byte[])tlvs; packet = (byte[])snac; }
public static void SRV_HELLO_VALIDATE(ICQClient client, ref FLAPHeader flap, byte[] packet) { if ((eFLAPChannel)flap.Channel != eFLAPChannel.NewConnection) throw new ProtocolViolationException("Unexpected server welcoming packet received; expected: SRV_HELLO"); else if (packet.Length != 4 || XBitConvert.ToUInt32(packet, 0) != 1) client.LogWrite("[WARNING] SRV_HELLO has unexpected body value or body length..."); }
public static void CLI_HELLO(ref FLAPHeader flap, ref byte[] packet) { if (packet == null || packet.Length != 12) packet = new byte[12]; XBitConvert.ToBytes((uint)0x00000001, packet, 0); XBitConvert.ToBytes((ushort)0x8003, packet, 4); XBitConvert.ToBytes((ushort)0x0004, packet, 6); XBitConvert.ToBytes((uint)0x00100000, packet, 8); flap.Channel = (byte)eFLAPChannel.NewConnection; }
public static void CLI_HELLO_BOSS(ref FLAPHeader flap, ref byte[] packet, byte[] bossCookie) { var tlvs = new TLVChain(4) { // BOSS cookie new TLV { TypeID = 0x0006, Value = bossCookie }, #if false Следующие данные идентификации клиента уже не обязательны (изменение 2011 года). 0003 // Метка блока данных со строкой идентификации клиента 0024 // Длина строки идентификации клиента TestBuddy AOL Instant Messenger (SM) // Строка идентификации клиента 0017 // Метка блока данных с мажорной версией клиента 0002 // Длина данных о мажорной версии 0001 // Номер мажорной версии: 1 0018 // Метка блока данных о минорной версии клиента 0002 // Длина данных о минорной версии 0000 // Номер минорной версии: 0 0019 // Метка блока данных о меньшей версии клиента 0002 // Длина данных о меньшей версии 0000 // Номер меньшей версии: 0 001a // Метка блока данных о номере сборки клиента 0002 // Длина данных номера сборки 0001 // Номер сборки клиента: 1 0016 // Метка блока данных идентификатора клиента 0002 // Длина данных идентификатора 010e // Идентификатор клиента (значение: 270) 000f // Метка блока данных о языке клиента 0002 // Длина данных о языке 656e // Язык клиента (значение: en) 000e // Метка блока данных о стране клиента 0002 // Длина данных о стране 7573 // Страна клиента (значение: us) #endif // Unknown TLV, required, new TLV { TypeID = 0x8003, Value = XBitConvert.GetBytes((uint)0x00100000) }, // BOSS reconnect support flag (false?) new TLV { TypeID = 0x0094, Value = new byte[1] { 0x00 } }, // Multiconnections with same UIN support by this client flag (true?) new TLV { TypeID = 0x004a, Value = new byte[1] { 0x01 } }, #if false Дополнения в клиенте ICQ 7 ICQ Client Key=gu19PNBblQjCdbMU // Строка идентификации клиента 00a2 // Метка неизвестного блока данных ^ 0002 // Длина данных 0005 // Неизвестные данные ^ 00a3 // Метка неизвестного блока данных ^ 0002 // Длина данных 0009 // Неизвестные данные ^ 00a4 // Метка неизвестного блока данных ^ 0002 // Длина данных 0002 // Неизвестные данные ^ 00a5 // Метка неизвестного блока данных ^ 0002 // Длина данных 195c // Неизвестные данные ^ 008b // Метка неизвестного блока данных ^ 0002 // Длина данных 0002 // Неизвестные данные ^ 008a // Метка неизвестного блока данных ^ 0020 // Длина данных 7488383beec35874a13a74d64dad6b192fca547335976defd1da9fd985db5a32 009e // Метка неизвестного блока данных ^ 0002 // Длина данных 0002 // Неизвестные данные ^ 009f // Метка неизвестного блока данных ^ 0002 // Длина данных 0001 // Неизвестные данные ^ 00a0 // Метка неизвестного блока данных ^ 0002 // Длина данных 0000 // Неизвестные данные ^ 00a1 // Метка неизвестного блока данных ^ 0002 // Длина данных 09a2 // Неизвестные данные ^ 00b0 // Метка неизвестного блока данных ^ 0000 // Длина данных 00ac // Метка неизвестного блока данных ^ 0001 // Длина данных 00 // Неизвестные данные ^ Дополнения в клиенте AIM: imApp key=ak1TRvqg3Srh_U_F // Строка идентификации клиента 00b4 // Метка неизвестного блока данных ^ 0012 // Длина данных 1 0010 // Длина данных 2 36594535383633354345332438343863 // Неизвестные данные ^ #endif }; using (var mem = new MemoryStream(100)) { // Flag we're connecting to ICQ network (dword, = 1) mem.Write(XBitConvert.GetBytes((uint)1), 0, 4); var tlvsBytes = (byte[])tlvs; mem.Write(tlvsBytes, 0, tlvsBytes.Length); packet = mem.ToArray(); } flap.Channel = (byte)eFLAPChannel.NewConnection; }
private void CheckIncomingPacketSequence(ref FLAPHeader flap) { // Check remote sequence if (m_remoteSequence != 0) { if (m_remoteSequence++ != flap.SequenceNumber) throw new ProtocolViolationException("Remote client violated its expected packet sequence number."); } else m_remoteSequence = (ushort)(flap.SequenceNumber + 1); }
/// <summary> /// Send packet to Socket. /// </summary> /// <param name="to"></param> /// <param name="flap"></param> /// <param name="data"></param> protected void sendPacket(EndPoint to, ref FLAPHeader flap, byte[] data) { var header = new byte[FLAPHeader.FullLength]; flap.ToBytes(header, data.Length); m_socket.SendTo(header, to); m_socket.SendTo(data, to); }
/// <summary> /// Try read packet from Socket. /// </summary> /// <param name="flap"></param> /// <param name="data"></param> /// <returns></returns> protected bool readPacket(ref FLAPHeader flap, out byte[] data) { if (m_socket.Available >= FLAPHeader.FullLength) { // Read header var header = new byte[FLAPHeader.FullLength]; m_socket.Receive(header, FLAPHeader.FullLength, SocketFlags.None); ushort flapDataLength = 0; flap = FLAPHeader.FromBytes(header, out flapDataLength, AppIDByte); // Read data data = new byte[flapDataLength]; if (flapDataLength > 0) { int read = 0; while (read < flapDataLength) read += m_socket.Receive(data, read, flapDataLength - read, SocketFlags.None); } // Done return true; } // Nothing to read data = null; return false; }
/// <summary> /// Добавляет пакет в очередь для отправки, если OSCAR в асинхронном режиме. /// В другом случае, немедленно отправляет пакет. /// </summary> /// <param name="flap">Заголовок FLAP</param> /// <param name="data">Тело пакета FLAP</param> public virtual void Send(ref FLAPHeader flap, byte[] data) { flap.ID = AppIDByte; flap.SequenceNumber = (m_localSequence++); if (m_customSocket || this.IsAsync) { // Buffer send m_sendBuffer.Enqueue(new OSCARQueueEntity { FLAP = flap, Data = data }); } else { // Send right now sendPacket(m_remote, ref flap, data); } }
/// <summary> /// Получает пакет из соединения. /// </summary> /// <param name="flap">Заголовок FLAP</param> /// <param name="data">Тело пакета FLAP</param> /// <param name="block">True, если нужно ждать пакет, даже если он еще недоступен.</param> /// <param name="blockTimeOut">При разрешении блокирования задает тайм-аут ожидания.</param> public virtual bool Receive(ref FLAPHeader flap, out byte[] data, bool block, int blockTimeOut = -1) { #if DEBUG if (this.IsAsync) throw new InvalidOperationException("This OSCAR instance is working in async mode. You cannot use Receive()."); #endif var blockEnter = Environment.TickCount; // Receive recv: bool receiveOK = readPacket(ref flap, out data); // Block? if (!receiveOK) { if (block && this.IsConnected && (blockTimeOut == Timeout.Infinite || (Environment.TickCount - blockEnter) <= blockTimeOut)) { Thread.Sleep(10); goto recv; } } // Check if received if(receiveOK) CheckIncomingPacketSequence(ref flap); return receiveOK; }