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
6void CConsoleNetConnection::Reset()
7{
8 m_State = NET_CONNSTATE_OFFLINE;
9 mem_zero(block: &m_PeerAddr, size: sizeof(m_PeerAddr));
10 m_aErrorString[0] = 0;
11
12 m_Socket = nullptr;
13 m_aBuffer[0] = 0;
14 m_BufferOffset = 0;
15
16 m_LineEndingDetected = false;
17#if defined(CONF_FAMILY_WINDOWS)
18 m_aLineEnding[0] = '\r';
19 m_aLineEnding[1] = '\n';
20 m_aLineEnding[2] = 0;
21#else
22 m_aLineEnding[0] = '\n';
23 m_aLineEnding[1] = 0;
24 m_aLineEnding[2] = 0;
25#endif
26}
27
28void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr)
29{
30 Reset();
31
32 m_Socket = Socket;
33 net_set_non_blocking(sock: m_Socket);
34
35 m_PeerAddr = *pAddr;
36 m_State = NET_CONNSTATE_ONLINE;
37}
38
39void CConsoleNetConnection::Disconnect(const char *pReason)
40{
41 if(State() == NET_CONNSTATE_OFFLINE)
42 return;
43
44 if(pReason && pReason[0])
45 Send(pLine: pReason);
46
47 net_tcp_close(sock: m_Socket);
48
49 Reset();
50}
51
52int CConsoleNetConnection::Update()
53{
54 if(State() == NET_CONNSTATE_ONLINE)
55 {
56 if((int)(sizeof(m_aBuffer)) <= m_BufferOffset)
57 {
58 m_State = NET_CONNSTATE_ERROR;
59 str_copy(dst&: m_aErrorString, src: "too weak connection (out of buffer)");
60 return -1;
61 }
62
63 int Bytes = net_tcp_recv(sock: m_Socket, data: m_aBuffer + m_BufferOffset, maxsize: (int)(sizeof(m_aBuffer)) - m_BufferOffset);
64
65 if(Bytes > 0)
66 {
67 m_BufferOffset += Bytes;
68 }
69 else if(Bytes < 0)
70 {
71 if(net_would_block()) // no data received
72 return 0;
73
74 m_State = NET_CONNSTATE_ERROR; // error
75 str_copy(dst&: m_aErrorString, src: "connection failure");
76 return -1;
77 }
78 else
79 {
80 m_State = NET_CONNSTATE_ERROR;
81 str_copy(dst&: m_aErrorString, src: "remote end closed the connection");
82 return -1;
83 }
84 }
85
86 return 0;
87}
88
89int CConsoleNetConnection::Recv(char *pLine, int MaxLength)
90{
91 if(State() == NET_CONNSTATE_ONLINE)
92 {
93 if(m_BufferOffset)
94 {
95 // find message start
96 int StartOffset = 0;
97 while(m_aBuffer[StartOffset] == '\r' || m_aBuffer[StartOffset] == '\n')
98 {
99 // detect clients line ending format
100 if(!m_LineEndingDetected)
101 {
102 m_aLineEnding[0] = m_aBuffer[StartOffset];
103 if(StartOffset + 1 < m_BufferOffset && (m_aBuffer[StartOffset + 1] == '\r' || m_aBuffer[StartOffset + 1] == '\n') &&
104 m_aBuffer[StartOffset] != m_aBuffer[StartOffset + 1])
105 m_aLineEnding[1] = m_aBuffer[StartOffset + 1];
106 m_LineEndingDetected = true;
107 }
108
109 if(++StartOffset >= m_BufferOffset)
110 {
111 m_BufferOffset = 0;
112 return 0;
113 }
114 }
115
116 // find message end
117 int EndOffset = StartOffset;
118 while(m_aBuffer[EndOffset] != '\r' && m_aBuffer[EndOffset] != '\n')
119 {
120 if(++EndOffset >= m_BufferOffset)
121 {
122 if(StartOffset > 0)
123 {
124 mem_move(dest: m_aBuffer, source: m_aBuffer + StartOffset, size: m_BufferOffset - StartOffset);
125 m_BufferOffset -= StartOffset;
126 }
127 return 0;
128 }
129 }
130
131 // extract message and update buffer
132 if(MaxLength - 1 < EndOffset - StartOffset)
133 {
134 if(StartOffset > 0)
135 {
136 mem_move(dest: m_aBuffer, source: m_aBuffer + StartOffset, size: m_BufferOffset - StartOffset);
137 m_BufferOffset -= StartOffset;
138 }
139 return 0;
140 }
141 mem_copy(dest: pLine, source: m_aBuffer + StartOffset, size: EndOffset - StartOffset);
142 pLine[EndOffset - StartOffset] = 0;
143 str_sanitize_cc(str: pLine);
144 mem_move(dest: m_aBuffer, source: m_aBuffer + EndOffset, size: m_BufferOffset - EndOffset);
145 m_BufferOffset -= EndOffset;
146 return str_utf8_check(str: pLine);
147 }
148 }
149 return 0;
150}
151
152int CConsoleNetConnection::Send(const char *pLine)
153{
154 if(State() != NET_CONNSTATE_ONLINE)
155 return -1;
156
157 char aBuf[1024];
158 str_copy(dst: aBuf, src: pLine, dst_size: (int)(sizeof(aBuf)) - 2);
159 int Length = str_length(str: aBuf);
160 aBuf[Length] = m_aLineEnding[0];
161 aBuf[Length + 1] = m_aLineEnding[1];
162 aBuf[Length + 2] = m_aLineEnding[2];
163 Length += 3;
164 const char *pData = aBuf;
165
166 while(true)
167 {
168 int Send = net_tcp_send(sock: m_Socket, data: pData, size: Length);
169 if(Send < 0)
170 {
171 m_State = NET_CONNSTATE_ERROR;
172 str_copy(dst&: m_aErrorString, src: "failed to send packet");
173 return -1;
174 }
175
176 if(Send >= Length)
177 break;
178
179 pData += Send;
180 Length -= Send;
181 }
182
183 return 0;
184}
185