1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
3 | #include "network.h" |
4 | #include <base/system.h> |
5 | |
6 | bool CNetClient::Open(NETADDR BindAddr) |
7 | { |
8 | // open socket |
9 | NETSOCKET Socket; |
10 | Socket = net_udp_create(bindaddr: BindAddr); |
11 | if(!Socket) |
12 | return false; |
13 | |
14 | // clean it |
15 | *this = CNetClient{}; |
16 | |
17 | // init |
18 | m_Socket = Socket; |
19 | m_pStun = new CStun(m_Socket); |
20 | m_Connection.Init(Socket: m_Socket, BlockCloseMsg: false); |
21 | |
22 | return true; |
23 | } |
24 | |
25 | int CNetClient::Close() |
26 | { |
27 | if(!m_Socket) |
28 | return 0; |
29 | if(m_pStun) |
30 | { |
31 | delete m_pStun; |
32 | m_pStun = nullptr; |
33 | } |
34 | return net_udp_close(sock: m_Socket); |
35 | } |
36 | |
37 | int CNetClient::Disconnect(const char *pReason) |
38 | { |
39 | //dbg_msg("netclient", "disconnected. reason=\"%s\"", pReason); |
40 | m_Connection.Disconnect(pReason); |
41 | return 0; |
42 | } |
43 | |
44 | int CNetClient::Update() |
45 | { |
46 | m_Connection.Update(); |
47 | if(m_Connection.State() == NET_CONNSTATE_ERROR) |
48 | Disconnect(pReason: m_Connection.ErrorString()); |
49 | m_pStun->Update(); |
50 | return 0; |
51 | } |
52 | |
53 | int CNetClient::Connect(const NETADDR *pAddr, int NumAddrs) |
54 | { |
55 | m_Connection.Connect(pAddr, NumAddrs); |
56 | return 0; |
57 | } |
58 | |
59 | int CNetClient::ResetErrorString() |
60 | { |
61 | m_Connection.ResetErrorString(); |
62 | return 0; |
63 | } |
64 | |
65 | int CNetClient::Recv(CNetChunk *pChunk) |
66 | { |
67 | while(true) |
68 | { |
69 | // check for a chunk |
70 | if(m_RecvUnpacker.FetchChunk(pChunk)) |
71 | return 1; |
72 | |
73 | // TODO: empty the recvinfo |
74 | NETADDR Addr; |
75 | unsigned char *pData; |
76 | int Bytes = net_udp_recv(sock: m_Socket, addr: &Addr, data: &pData); |
77 | |
78 | // no more packets for now |
79 | if(Bytes <= 0) |
80 | break; |
81 | |
82 | if(m_pStun->OnPacket(Addr, pData, DataSize: Bytes)) |
83 | { |
84 | continue; |
85 | } |
86 | |
87 | bool Sixup = false; |
88 | if(CNetBase::UnpackPacket(pBuffer: pData, Size: Bytes, pPacket: &m_RecvUnpacker.m_Data, Sixup) == 0) |
89 | { |
90 | if(m_RecvUnpacker.m_Data.m_Flags & NET_PACKETFLAG_CONNLESS) |
91 | { |
92 | pChunk->m_Flags = NETSENDFLAG_CONNLESS; |
93 | pChunk->m_ClientId = -1; |
94 | pChunk->m_Address = Addr; |
95 | pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize; |
96 | pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData; |
97 | if(m_RecvUnpacker.m_Data.m_Flags & NET_PACKETFLAG_EXTENDED) |
98 | { |
99 | pChunk->m_Flags |= NETSENDFLAG_EXTENDED; |
100 | mem_copy(dest: pChunk->m_aExtraData, source: m_RecvUnpacker.m_Data.m_aExtraData, size: sizeof(pChunk->m_aExtraData)); |
101 | } |
102 | return 1; |
103 | } |
104 | else |
105 | { |
106 | if(m_Connection.State() != NET_CONNSTATE_OFFLINE && m_Connection.State() != NET_CONNSTATE_ERROR && m_Connection.Feed(pPacket: &m_RecvUnpacker.m_Data, pAddr: &Addr)) |
107 | m_RecvUnpacker.Start(pAddr: &Addr, pConnection: &m_Connection, ClientId: 0); |
108 | } |
109 | } |
110 | } |
111 | return 0; |
112 | } |
113 | |
114 | int CNetClient::Send(CNetChunk *pChunk) |
115 | { |
116 | if(pChunk->m_DataSize >= NET_MAX_PAYLOAD) |
117 | { |
118 | dbg_msg(sys: "netclient" , fmt: "chunk payload too big. %d. dropping chunk" , pChunk->m_DataSize); |
119 | return -1; |
120 | } |
121 | |
122 | if(pChunk->m_Flags & NETSENDFLAG_CONNLESS) |
123 | { |
124 | // send connectionless packet |
125 | CNetBase::SendPacketConnless(Socket: m_Socket, pAddr: &pChunk->m_Address, pData: pChunk->m_pData, DataSize: pChunk->m_DataSize, |
126 | Extended: pChunk->m_Flags & NETSENDFLAG_EXTENDED, aExtra: pChunk->m_aExtraData); |
127 | } |
128 | else |
129 | { |
130 | int Flags = 0; |
131 | dbg_assert(pChunk->m_ClientId == 0, "erroneous client id" ); |
132 | |
133 | if(pChunk->m_Flags & NETSENDFLAG_VITAL) |
134 | Flags = NET_CHUNKFLAG_VITAL; |
135 | |
136 | m_Connection.QueueChunk(Flags, DataSize: pChunk->m_DataSize, pData: pChunk->m_pData); |
137 | |
138 | if(pChunk->m_Flags & NETSENDFLAG_FLUSH) |
139 | m_Connection.Flush(); |
140 | } |
141 | return 0; |
142 | } |
143 | |
144 | int CNetClient::State() |
145 | { |
146 | if(m_Connection.State() == NET_CONNSTATE_ONLINE) |
147 | return NETSTATE_ONLINE; |
148 | if(m_Connection.State() == NET_CONNSTATE_OFFLINE) |
149 | return NETSTATE_OFFLINE; |
150 | return NETSTATE_CONNECTING; |
151 | } |
152 | |
153 | int CNetClient::Flush() |
154 | { |
155 | return m_Connection.Flush(); |
156 | } |
157 | |
158 | int CNetClient::GotProblems(int64_t MaxLatency) const |
159 | { |
160 | if(time_get() - m_Connection.LastRecvTime() > MaxLatency) |
161 | return 1; |
162 | return 0; |
163 | } |
164 | |
165 | const char *CNetClient::ErrorString() const |
166 | { |
167 | return m_Connection.ErrorString(); |
168 | } |
169 | |
170 | void CNetClient::FeedStunServer(NETADDR StunServer) |
171 | { |
172 | m_pStun->FeedStunServer(StunServer); |
173 | } |
174 | |
175 | void CNetClient::RefreshStun() |
176 | { |
177 | m_pStun->Refresh(); |
178 | } |
179 | |
180 | CONNECTIVITY CNetClient::GetConnectivity(int NetType, NETADDR *pGlobalAddr) |
181 | { |
182 | return m_pStun->GetConnectivity(NetType, pGlobalAddr); |
183 | } |
184 | |