1 /*
2     SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #include "utpprotocol.h"
7 #include <util/functions.h>
8 
9 namespace utp
10 {
TypeToString(bt::Uint8 type)11 QString TypeToString(bt::Uint8 type)
12 {
13     switch (type) {
14     case ST_DATA:
15         return QStringLiteral("DATA");
16     case ST_FIN:
17         return QStringLiteral("FIN");
18     case ST_STATE:
19         return QStringLiteral("STATE");
20     case ST_RESET:
21         return QStringLiteral("RESET");
22     case ST_SYN:
23         return QStringLiteral("SYN");
24     default:
25         return QStringLiteral("UNKNOWN");
26     }
27 }
28 
read(const bt::Uint8 * data)29 void Header::read(const bt::Uint8 *data)
30 {
31     type = (data[0] & 0xF0) >> 4;
32     version = data[0] & 0x0F;
33     extension = data[1];
34     connection_id = bt::ReadUint16(data, 2);
35     timestamp_microseconds = bt::ReadUint32(data, 4);
36     timestamp_difference_microseconds = bt::ReadUint32(data, 8);
37     wnd_size = bt::ReadUint32(data, 12);
38     seq_nr = bt::ReadUint16(data, 16);
39     ack_nr = bt::ReadUint16(data, 18);
40 }
41 
write(bt::Uint8 * data) const42 void Header::write(bt::Uint8 *data) const
43 {
44     data[0] = ((type << 4) & 0xF0) | (version & 0x0F);
45     data[1] = extension;
46     bt::WriteUint16(data, 2, connection_id);
47     bt::WriteUint32(data, 4, timestamp_microseconds);
48     bt::WriteUint32(data, 8, timestamp_difference_microseconds);
49     bt::WriteUint32(data, 12, wnd_size);
50     bt::WriteUint16(data, 16, seq_nr);
51     bt::WriteUint16(data, 18, ack_nr);
52 }
53 
size()54 bt::Uint32 Header::size()
55 {
56     return 20;
57 }
58 
PacketParser(const QByteArray & pkt)59 PacketParser::PacketParser(const QByteArray &pkt)
60     : packet((const bt::Uint8 *)pkt.data())
61     , sack_found(false)
62     , size(pkt.size())
63     , data_off(0)
64     , data_size(0)
65 {
66     hdr.read(packet);
67 }
68 
PacketParser(const bt::Uint8 * packet,bt::Uint32 size)69 PacketParser::PacketParser(const bt::Uint8 *packet, bt::Uint32 size)
70     : packet(packet)
71     , sack_found(false)
72     , size(size)
73     , data_off(0)
74     , data_size(0)
75 {
76     hdr.read(packet);
77 }
78 
~PacketParser()79 PacketParser::~PacketParser()
80 {
81 }
82 
parse()83 bool PacketParser::parse()
84 {
85     if (size < Header::size())
86         return false;
87 
88     data_off = Header::size();
89 
90     // go over all header extensions to increase the data offset and watch out for selective acks
91     int ext_id = hdr.extension;
92     while (data_off < size && ext_id != 0) {
93         const bt::Uint8 *ptr = packet + data_off;
94         if (ext_id == SELECTIVE_ACK_ID) {
95             sack_found = true;
96             sack.extension = ptr[0];
97             sack.length = ptr[1];
98             if (data_off + 2 + sack.length > size)
99                 return false;
100             sack.bitmask = (bt::Uint8 *)ptr + 2;
101         }
102 
103         data_off += 2 + ptr[1];
104         ext_id = ptr[0];
105     }
106 
107     data_size = size - data_off;
108     return true;
109 }
110 
selectiveAck() const111 const utp::SelectiveAck *PacketParser::selectiveAck() const
112 {
113     return sack_found ? &sack : nullptr;
114 }
115 
116 }
117