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
6bool 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
25int 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
37int CNetClient::Disconnect(const char *pReason)
38{
39 //dbg_msg("netclient", "disconnected. reason=\"%s\"", pReason);
40 m_Connection.Disconnect(pReason);
41 return 0;
42}
43
44int 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
53int CNetClient::Connect(const NETADDR *pAddr, int NumAddrs)
54{
55 m_Connection.Connect(pAddr, NumAddrs);
56 return 0;
57}
58
59int CNetClient::ResetErrorString()
60{
61 m_Connection.ResetErrorString();
62 return 0;
63}
64
65int 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
114int 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
144int 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
153int CNetClient::Flush()
154{
155 return m_Connection.Flush();
156}
157
158int CNetClient::GotProblems(int64_t MaxLatency) const
159{
160 if(time_get() - m_Connection.LastRecvTime() > MaxLatency)
161 return 1;
162 return 0;
163}
164
165const char *CNetClient::ErrorString() const
166{
167 return m_Connection.ErrorString();
168}
169
170void CNetClient::FeedStunServer(NETADDR StunServer)
171{
172 m_pStun->FeedStunServer(StunServer);
173}
174
175void CNetClient::RefreshStun()
176{
177 m_pStun->Refresh();
178}
179
180CONNECTIVITY CNetClient::GetConnectivity(int NetType, NETADDR *pGlobalAddr)
181{
182 return m_pStun->GetConnectivity(NetType, pGlobalAddr);
183}
184