Skip to content

Commit 543c256

Browse files
committed
Fix partial send
1 parent c8cc443 commit 543c256

File tree

4 files changed

+118
-96
lines changed

4 files changed

+118
-96
lines changed

include/slick_socket/tcp_client_unix.h

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -208,38 +208,43 @@ inline bool TCPClientBase<DerivedT, LoggerT>::send_data(const std::vector<uint8_
208208
return false;
209209
}
210210

211-
// Send data to server (non-blocking)
212-
ssize_t sent = send(socket_, data.data(), data.size(), MSG_NOSIGNAL);
213-
if (sent < 0)
211+
size_t total_sent = 0;
212+
size_t data_size = data.size();
213+
const uint8_t* buffer = data.data();
214+
215+
// Keep sending until all data is sent
216+
while (total_sent < data_size)
214217
{
215-
// Check for non-blocking specific errors
216-
if (errno == EAGAIN || errno == EWOULDBLOCK)
218+
ssize_t sent = send(socket_, buffer + total_sent, data_size - total_sent, MSG_NOSIGNAL);
219+
if (sent < 0)
217220
{
218-
logger_.logWarning("Send would block - socket buffer full");
221+
// Check for non-blocking specific errors
222+
if (errno == EAGAIN || errno == EWOULDBLOCK)
223+
{
224+
// Socket buffer is full, retry immediately
225+
continue;
226+
}
227+
228+
logger_.logError("Failed to send data: {}", std::strerror(errno));
229+
230+
// Check if connection is broken
231+
if (errno == ECONNRESET || errno == EPIPE || errno == ENOTCONN)
232+
{
233+
logger_.logInfo("Connection lost during send, disconnecting");
234+
disconnect();
235+
}
219236
return false;
220237
}
221238

222-
logger_.logError("Failed to send data: {}", std::strerror(errno));
223-
224-
// Check if connection is broken
225-
if (errno == ECONNRESET || errno == EPIPE || errno == ENOTCONN)
239+
total_sent += sent;
240+
241+
if (sent > 0 && total_sent < data_size)
226242
{
227-
logger_.logInfo("Connection lost during send, disconnecting");
228-
disconnect();
243+
logger_.logTrace("Partial send: sent {} bytes, {} remaining", sent, data_size - total_sent);
229244
}
230-
return false;
231-
}
232-
233-
if (sent != static_cast<ssize_t>(data.size()))
234-
{
235-
size_t data_size = data.size();
236-
logger_.logWarning("Partial send: sent {} bytes out of {}", sent, data_size);
237-
// In non-blocking mode, partial sends can happen when socket buffer is full
238-
// For now, we consider this a failure and let caller retry
239-
return false;
240245
}
241246

242-
logger_.logTrace("Successfully sent {} bytes to server", sent);
247+
logger_.logTrace("Successfully sent {} bytes to server", total_sent);
243248
return true;
244249
}
245250

include/slick_socket/tcp_client_win32.h

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -199,40 +199,45 @@ inline bool TCPClientBase<DerivedT, LoggerT>::send_data(const std::vector<uint8_
199199
return false;
200200
}
201201

202-
// Send data to server (non-blocking)
203-
int sent = send(socket_, (char*)data.data(), (int)data.size(), 0);
204-
if (sent == SOCKET_ERROR)
205-
{
206-
int error = WSAGetLastError();
202+
size_t total_sent = 0;
203+
size_t data_size = data.size();
204+
const char* buffer = reinterpret_cast<const char*>(data.data());
207205

208-
// Check for non-blocking specific errors
209-
if (error == WSAEWOULDBLOCK)
206+
// Keep sending until all data is sent
207+
while (total_sent < data_size)
208+
{
209+
int sent = send(socket_, buffer + total_sent, static_cast<int>(data_size - total_sent), 0);
210+
if (sent == SOCKET_ERROR)
210211
{
211-
logger_.logWarning("Send would block - socket buffer full");
212+
int error = WSAGetLastError();
213+
214+
// Check for non-blocking specific errors
215+
if (error == WSAEWOULDBLOCK)
216+
{
217+
// Socket buffer is full, retry immediately
218+
continue;
219+
}
220+
221+
logger_.logError("Failed to send data: error {}", error);
222+
223+
// Check if connection is broken
224+
if (error == WSAECONNRESET || error == WSAECONNABORTED || error == WSAENOTCONN)
225+
{
226+
logger_.logInfo("Connection lost during send, disconnecting");
227+
disconnect();
228+
}
212229
return false;
213230
}
214231

215-
logger_.logError("Failed to send data: error {}", error);
216-
217-
// Check if connection is broken
218-
if (error == WSAECONNRESET || error == WSAECONNABORTED || error == WSAENOTCONN)
232+
total_sent += sent;
233+
234+
if (sent > 0 && total_sent < data_size)
219235
{
220-
logger_.logInfo("Connection lost during send, disconnecting");
221-
disconnect();
236+
logger_.logTrace("Partial send: sent {} bytes, {} remaining", sent, data_size - total_sent);
222237
}
223-
return false;
224-
}
225-
226-
if (sent != (int)data.size())
227-
{
228-
size_t data_size = data.size();
229-
logger_.logWarning("Partial send: sent {} bytes out of {}", sent, data_size);
230-
// In non-blocking mode, partial sends can happen when socket buffer is full
231-
// For now, we consider this a failure and let caller retry
232-
return false;
233238
}
234239

235-
logger_.logTrace("Successfully sent {} bytes to server", sent);
240+
logger_.logTrace("Successfully sent {} bytes to server", total_sent);
236241
return true;
237242
}
238243

include/slick_socket/tcp_server_unix.h

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -139,38 +139,44 @@ inline bool TCPServerBase<DrivedT, LoggerT>::send_data(int client_id, const std:
139139
return false;
140140
}
141141

142-
// Send data to client (non-blocking)
143-
ssize_t sent = send(it->second.socket, data.data(), data.size(), MSG_NOSIGNAL);
144-
if (sent < 0)
142+
size_t total_sent = 0;
143+
size_t data_size = data.size();
144+
const uint8_t* buffer = data.data();
145+
146+
// Keep sending until all data is sent
147+
while (total_sent < data_size)
145148
{
146-
// Check for non-blocking specific errors
147-
if (errno == EAGAIN || errno == EWOULDBLOCK)
149+
ssize_t sent = send(it->second.socket, buffer + total_sent, data_size - total_sent, MSG_NOSIGNAL);
150+
if (sent < 0)
148151
{
149-
logger_.logWarning("Send would block - socket buffer full for client {}", client_id);
152+
// Check for non-blocking specific errors
153+
if (errno == EAGAIN || errno == EWOULDBLOCK)
154+
{
155+
// Socket buffer is full, retry immediately
156+
continue;
157+
}
158+
159+
logger_.logError("Failed to send data to client {}: {}", client_id, std::strerror(errno));
160+
161+
// Check if connection is broken
162+
if (errno == ECONNRESET || errno == EPIPE || errno == ENOTCONN)
163+
{
164+
logger_.logInfo("Connection lost during send to client {}, disconnecting", client_id);
165+
disconnect_client(client_id);
166+
}
150167
return false;
151168
}
152169

153-
logger_.logError("Failed to send data to client {}: {}", client_id, std::strerror(errno));
154-
155-
// Check if connection is broken
156-
if (errno == ECONNRESET || errno == EPIPE || errno == ENOTCONN)
170+
total_sent += sent;
171+
172+
if (sent > 0 && total_sent < data_size)
157173
{
158-
logger_.logInfo("Connection lost during send to client {}, disconnecting", client_id);
159-
disconnect_client(client_id);
174+
logger_.logTrace("Partial send to client {}: sent {} bytes, {} remaining",
175+
client_id, sent, data_size - total_sent);
160176
}
161-
return false;
162-
}
163-
164-
if (sent != static_cast<ssize_t>(data.size()))
165-
{
166-
size_t data_size = data.size();
167-
logger_.logWarning("Partial send to client {}: sent {} bytes out of {}", client_id, sent, data_size);
168-
// In non-blocking mode, partial sends can happen when socket buffer is full
169-
// For now, we consider this a failure and let caller retry
170-
return false;
171177
}
172178

173-
logger_.logTrace("Successfully sent {} bytes to client {}", sent, client_id);
179+
logger_.logTrace("Successfully sent {} bytes to client {}", total_sent, client_id);
174180
return true;
175181
}
176182

include/slick_socket/tcp_server_win32.h

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -137,40 +137,46 @@ inline bool TCPServerBase<DrivedT, LoggerT>::send_data(int client_id, const std:
137137
return false;
138138
}
139139

140-
// Send data to client (non-blocking)
141-
int sent = send(it->second.socket, (char*)data.data(), (int)data.size(), 0);
142-
if (sent == SOCKET_ERROR)
143-
{
144-
int error = WSAGetLastError();
140+
size_t total_sent = 0;
141+
size_t data_size = data.size();
142+
const char* buffer = reinterpret_cast<const char*>(data.data());
145143

146-
// Check for non-blocking specific errors
147-
if (error == WSAEWOULDBLOCK)
144+
// Keep sending until all data is sent
145+
while (total_sent < data_size)
146+
{
147+
int sent = send(it->second.socket, buffer + total_sent, static_cast<int>(data_size - total_sent), 0);
148+
if (sent == SOCKET_ERROR)
148149
{
149-
logger_.logWarning("Send would block - socket buffer full for client {}", client_id);
150+
int error = WSAGetLastError();
151+
152+
// Check for non-blocking specific errors
153+
if (error == WSAEWOULDBLOCK)
154+
{
155+
// Socket buffer is full, retry immediately
156+
continue;
157+
}
158+
159+
logger_.logError("Failed to send data to client {}: error {}", client_id, error);
160+
161+
// Check if connection is broken
162+
if (error == WSAECONNRESET || error == WSAECONNABORTED || error == WSAENOTCONN)
163+
{
164+
logger_.logInfo("Connection lost during send to client {}, disconnecting", client_id);
165+
disconnect_client(client_id);
166+
}
150167
return false;
151168
}
152169

153-
logger_.logError("Failed to send data to client {}: error {}", client_id, error);
154-
155-
// Check if connection is broken
156-
if (error == WSAECONNRESET || error == WSAECONNABORTED || error == WSAENOTCONN)
170+
total_sent += sent;
171+
172+
if (sent > 0 && total_sent < data_size)
157173
{
158-
logger_.logInfo("Connection lost during send to client {}, disconnecting", client_id);
159-
disconnect_client(client_id);
174+
logger_.logTrace("Partial send to client {}: sent {} bytes, {} remaining",
175+
client_id, sent, data_size - total_sent);
160176
}
161-
return false;
162-
}
163-
164-
if (sent != (int)data.size())
165-
{
166-
size_t data_size = data.size();
167-
logger_.logWarning("Partial send to client {}: sent {} bytes out of {}", client_id, sent, data_size);
168-
// In non-blocking mode, partial sends can happen when socket buffer is full
169-
// For now, we consider this a failure and let caller retry
170-
return false;
171177
}
172178

173-
logger_.logTrace("Successfully sent {} bytes to client {}", sent, client_id);
179+
logger_.logTrace("Successfully sent {} bytes to client {}", total_sent, client_id);
174180
return true;
175181
}
176182

0 commit comments

Comments
 (0)