/
TCPHelper.cpp
239 lines (181 loc) · 5.24 KB
/
TCPHelper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#include "TCPHelper.h"
bool socket_iswouldblock(int socketError)
{
#if defined(_WIN32)
return socketError == WSAEWOULDBLOCK;
#else
return socketError == EWOULDBLOCK || socketError == EAGAIN;
#endif
}
struct TCPHelper
{
int m_socket;
int m_lastError;
int m_sendBufferSize;
int m_sendBufferCapacity;
char* m_sendBuffer;
int m_recvBufferSize;
int m_recvBufferCapacity;
char* m_recvBuffer;
};
TCPHelper* TCPHelper_Create(int sendBufferSize, int recvBufferSize)
{
char* memory = (char*) malloc(sizeof(TCPHelper) + sendBufferSize + recvBufferSize);
if (!memory)
return NULL;
TCPHelper* socket = (TCPHelper*) memory;
socket->m_socket = 0;
socket->m_lastError = 0;
memory += sizeof(TCPHelper);
socket->m_sendBufferCapacity = sendBufferSize;
socket->m_sendBufferSize = 0;
socket->m_sendBuffer = sendBufferSize ? memory : NULL;
memory += sendBufferSize;
socket->m_recvBufferCapacity = recvBufferSize;
socket->m_recvBufferSize = 0;
socket->m_recvBuffer = recvBufferSize ? memory : NULL;
return socket;
}
void TCPHelper_Destroy(TCPHelper* socket)
{
free(socket);
}
void TCPHelper_Reset(TCPHelper* socket, int sock)
{
socket->m_socket = sock;
socket->m_lastError = 0;
socket->m_sendBufferSize = 0;
socket->m_recvBufferSize = 0;
}
int TCPHelper_GetSocket(TCPHelper* socket)
{
return socket->m_socket;
}
bool TCPHelper_IsError(TCPHelper* socket, int& socketErr)
{
socketErr = socket->m_lastError;
return socketErr != 0;
}
bool TCPHelper_BufferSend(TCPHelper* socket, const void* data, int dataSize, int& socketErr)
{
if (socket->m_sendBufferSize + dataSize > socket->m_sendBufferCapacity)
return false;
memcpy(socket->m_sendBuffer + socket->m_sendBufferSize, data, dataSize);
return true;
}
bool TCPHelper_SendImmediately(TCPHelper* socket, const void* data, int dataSize, int& socketErr)
{
// Send
socketErr = send(socket->m_socket, data, dataSize, 0);
if (socketErr < 0)
{
if (socket_iswouldblock(socketErr))
socketErr = 0;
else
socket->m_lastError = socketErr;
return false;
}
// If failed to send everything, put the rest into buffer
if (socketErr < dataSize)
memcpy(socket->m_sendBuffer + socket->m_sendBufferSize, (char*) data + socketErr, dataSize - socketErr);
// Indicate no error
socketErr = 0;
return true;
}
bool TCPHelper_Send(TCPHelper* socket, const void* data, int dataSize, int& socketErr)
{
assert(dataSize <= socket->m_sendBufferCapacity);
if (socket->m_lastError)
{
socketErr = socket->m_lastError;
return false;
}
// Send old messages
TCPHelper_TickSend(socket, socketErr);
if (socketErr < 0)
return false;
// Try to send immediately (only if there's no pending data)
if (socket->m_sendBufferSize == 0)
return TCPHelper_SendImmediately(socket, data, dataSize, socketErr);
// Otherwise store data in intermediate buffer
if (!TCPHelper_BufferSend(socket, data, dataSize, socketErr))
return false;
// Try sending again
TCPHelper_TickSend(socket, socketErr);
if (socketErr < 0)
return false;
return true;
}
void TCPHelper_TickSend(TCPHelper* socket, int& socketErr)
{
if (socket->m_lastError)
{
socketErr = socket->m_lastError;
return;
}
// Nothing to send?
if (socket->m_sendBufferSize == 0)
{
socketErr = 0;
return;
}
// Send
socketErr = send(socket->m_socket, socket->m_sendBuffer, socket->m_sendBufferSize, 0);
if (socketErr < 0)
{
if (socket_iswouldblock(socketErr))
socketErr = 0;
else
socket->m_lastError = socketErr;
return;
}
// Pop the rest of pending send data to the beginning of the buffer
socket->m_sendBufferSize -= socketErr;
if (socket->m_sendBufferSize > 0)
memmove(socket->m_sendBuffer, socket->m_sendBuffer + socketErr, socket->m_sendBufferSize);
// Indicate no error
socketErr = 0;
}
bool TCPHelper_WouldRecv(TCPHelper* socket, int numBytes, int& socketErr)
{
assert(numBytes <= socket->m_recvBufferCapacity);
if (socket->m_lastError)
{
socketErr = socket->m_lastError;
return false;
}
// Check if we've already received enough data
if (numBytes <= socket->m_recvBufferSize)
return true;
// Attempt to receive the data
socketErr = recv(socket->m_socket, socket->m_recvBuffer + socket->m_recvBufferSize, numBytes - socket->m_recvBufferSize, 0);
if (socketErr < 0)
{
if (socket_iswouldblock(socketErr))
socketErr = 0;
else
socket->m_lastError = socketErr;
return false;
}
// Received some data
socket->m_recvBufferSize += socketErr;
return numBytes <= socket->m_recvBufferSize;
}
bool TCPHelper_Recv(TCPHelper* socket, void* buffer, int numBytes, int& socketErr)
{
if (socket->m_lastError)
{
socketErr = socket->m_lastError;
return false;
}
// Check if we'd receive all requested bytes
if (!TCPHelper_WouldRecv(socket, numBytes, socketErr))
return false;
// Copy result
memcpy(buffer, socket->m_recvBuffer, numBytes);
// Pop the rest of pending received data to the beginning of the buffer
socket->m_recvBufferSize -= numBytes;
if (socket->m_recvBufferSize > 0)
memmove(socket->m_recvBuffer, socket->m_recvBuffer + numBytes, socket->m_recvBufferSize);
return true;
}