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 <base/system.h>
4
5#include "netban.h"
6#include "network.h"
7
8bool CNetConsole::Open(NETADDR BindAddr, CNetBan *pNetBan)
9{
10 // zero out the whole structure
11 *this = CNetConsole{};
12 m_pNetBan = pNetBan;
13
14 // open socket
15 m_Socket = net_tcp_create(bindaddr: BindAddr);
16 if(!m_Socket)
17 return false;
18 if(net_tcp_listen(sock: m_Socket, backlog: NET_MAX_CONSOLE_CLIENTS))
19 return false;
20 net_set_non_blocking(sock: m_Socket);
21
22 for(auto &Slot : m_aSlots)
23 Slot.m_Connection.Reset();
24
25 return true;
26}
27
28void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT_CON pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
29{
30 m_pfnNewClient = pfnNewClient;
31 m_pfnDelClient = pfnDelClient;
32 m_pUser = pUser;
33}
34
35int CNetConsole::Close()
36{
37 for(auto &Slot : m_aSlots)
38 Slot.m_Connection.Disconnect(pReason: "closing console");
39
40 net_tcp_close(sock: m_Socket);
41
42 return 0;
43}
44
45int CNetConsole::Drop(int ClientId, const char *pReason)
46{
47 if(m_pfnDelClient)
48 m_pfnDelClient(ClientId, pReason, m_pUser);
49
50 m_aSlots[ClientId].m_Connection.Disconnect(pReason);
51
52 return 0;
53}
54
55int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr)
56{
57 char aError[256] = {0};
58 int FreeSlot = -1;
59
60 // look for free slot or multiple client
61 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
62 {
63 if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
64 FreeSlot = i;
65 if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
66 {
67 if(net_addr_comp(a: pAddr, b: m_aSlots[i].m_Connection.PeerAddress()) == 0)
68 {
69 str_copy(dst&: aError, src: "only one client per IP allowed");
70 break;
71 }
72 }
73 }
74
75 // accept client
76 if(!aError[0] && FreeSlot != -1)
77 {
78 m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr);
79 if(m_pfnNewClient)
80 m_pfnNewClient(FreeSlot, m_pUser);
81 return 0;
82 }
83
84 // reject client
85 if(!aError[0])
86 str_copy(dst&: aError, src: "no free slot available");
87
88 net_tcp_send(sock: Socket, data: aError, size: str_length(str: aError));
89 net_tcp_close(sock: Socket);
90
91 return -1;
92}
93
94int CNetConsole::Update()
95{
96 NETSOCKET Socket;
97 NETADDR Addr;
98
99 if(net_tcp_accept(sock: m_Socket, new_sock: &Socket, addr: &Addr) > 0)
100 {
101 // check if we just should drop the packet
102 char aBuf[128];
103 if(NetBan() && NetBan()->IsBanned(pOrigAddr: &Addr, pBuf: aBuf, BufferSize: sizeof(aBuf)))
104 {
105 // banned, reply with a message and drop
106 net_tcp_send(sock: Socket, data: aBuf, size: str_length(str: aBuf));
107 net_tcp_close(sock: Socket);
108 }
109 else
110 AcceptClient(Socket, pAddr: &Addr);
111 }
112
113 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
114 {
115 if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE)
116 m_aSlots[i].m_Connection.Update();
117 if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
118 Drop(ClientId: i, pReason: m_aSlots[i].m_Connection.ErrorString());
119 }
120
121 return 0;
122}
123
124int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientId)
125{
126 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
127 {
128 if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE && m_aSlots[i].m_Connection.Recv(pLine, MaxLength))
129 {
130 if(pClientId)
131 *pClientId = i;
132 return 1;
133 }
134 }
135 return 0;
136}
137
138int CNetConsole::Send(int ClientId, const char *pLine)
139{
140 if(m_aSlots[ClientId].m_Connection.State() == NET_CONNSTATE_ONLINE)
141 return m_aSlots[ClientId].m_Connection.Send(pLine);
142 else
143 return -1;
144}
145