Added the ability to set write timeouts

Similar to read timeouts.
This commit is contained in:
Fred Nicolson 2019-04-02 10:34:31 +01:00
parent 6814219cbb
commit 00f13e41e7
No known key found for this signature in database
GPG Key ID: 78C1DD87B47797D2
5 changed files with 58 additions and 10 deletions

View File

@ -19,7 +19,7 @@ namespace fr
* sockets. * sockets.
* *
* @param socket The socket to send through * @param socket The socket to send through
* @return Status indicating if the send succeeded or not. * @return Status indicating if the send succeeded or not. This is dependent on the underlying type.
*/ */
virtual Socket::Status send(Socket *socket) const = 0; virtual Socket::Status send(Socket *socket) const = 0;
@ -29,7 +29,7 @@ namespace fr
* sockets. * sockets.
* *
* @param socket The socket to send through * @param socket The socket to send through
* @return Status indicating if the send succeeded or not. * @return Status indicating if the send succeeded or not. This is dependent on the underlying type.
*/ */
virtual Socket::Status receive(Socket *socket) = 0; virtual Socket::Status receive(Socket *socket) = 0;
}; };

View File

@ -39,7 +39,8 @@ namespace fr
ReceiveError = 17, ReceiveError = 17,
AcceptError = 18, AcceptError = 18,
SSLError = 19, SSLError = 19,
NoRouteToHost = 20 NoRouteToHost = 20,
Timeout = 21,
//Remember to update status_to_string if more are added //Remember to update status_to_string if more are added
}; };
@ -134,7 +135,7 @@ namespace fr
* Send a Sendable object through the socket * Send a Sendable object through the socket
* *
* @param obj The object to send * @param obj The object to send
* @return The status of the send * @return The status of the send. This is dependant type being sent.
*/ */
virtual Status send(const Sendable &obj); virtual Status send(const Sendable &obj);
@ -229,11 +230,38 @@ namespace fr
reconfigure_socket(); reconfigure_socket();
} }
/*!
* Gets the socket receive timeout.
*
* @return Socket timeout in milliseconds. 0 if none.
*/
inline uint32_t get_receive_timeout() const inline uint32_t get_receive_timeout() const
{ {
return socket_read_timeout; return socket_read_timeout;
} }
/*!
* Sets a timeout which applies when sending data.
*
* @param timeout The maximum number of milliseconds to wait on a socket write before returning. Pass
* 0 (default) for no timeout.
*/
inline void set_send_timeout(uint32_t timeout)
{
socket_write_timeout = timeout;
reconfigure_socket();
}
/*!
* Gets the socket send timeout.
*
* @return Socket send timeout in milliseconds. 0 if none.
*/
inline uint32_t get_send_timeout() const
{
return socket_write_timeout;
}
/*! /*!
* Gets the max packet size. See set_max_packet_size * Gets the max packet size. See set_max_packet_size
* for more information. If this returns 0, then * for more information. If this returns 0, then
@ -282,6 +310,7 @@ namespace fr
int ai_family; int ai_family;
uint32_t max_receive_size; uint32_t max_receive_size;
uint32_t socket_read_timeout; uint32_t socket_read_timeout;
uint32_t socket_write_timeout;
}; };
} }

View File

@ -78,7 +78,7 @@ namespace fr
{ {
if(is_blocking) if(is_blocking)
{ {
continue; return Socket::Status::Timeout;
} }
return Socket::Status::WouldBlock; return Socket::Status::WouldBlock;
} }
@ -111,7 +111,7 @@ namespace fr
{ {
if(is_blocking) if(is_blocking)
{ {
return Socket::Status::WouldBlock; return Socket::Status::Timeout;
} }
continue; continue;
} }

View File

@ -18,7 +18,8 @@ namespace fr
Socket::Socket() Socket::Socket()
: ai_family(AF_UNSPEC), : ai_family(AF_UNSPEC),
max_receive_size(0), max_receive_size(0),
socket_read_timeout(0) socket_read_timeout(0),
socket_write_timeout(0)
{ {
init_wsa(); init_wsa();
} }
@ -157,7 +158,8 @@ namespace fr
} }
case NoRouteToHost: case NoRouteToHost:
return "No Route To Host"; return "No Route To Host";
break; case Timeout:
return "Timeout";
default: default:
return "Unknown"; return "Unknown";
} }

View File

@ -29,7 +29,7 @@ namespace fr
while(sent < size) while(sent < size)
{ {
int64_t status = ::send(socket_descriptor, data + sent, size - sent, 0); int64_t status = ::send(socket_descriptor, data + sent, size - sent, 0);
if(status > 0) if(status >= 0)
{ {
sent += status; sent += status;
continue; continue;
@ -37,6 +37,10 @@ namespace fr
if(errno == EWOULDBLOCK) if(errno == EWOULDBLOCK)
{ {
if(is_blocking)
{
return Socket::Status::Timeout;
}
return Socket::Status::WouldBlock; return Socket::Status::WouldBlock;
} }
else if(errno == EINTR) else if(errno == EINTR)
@ -74,6 +78,10 @@ namespace fr
{ {
if(errno == EWOULDBLOCK) if(errno == EWOULDBLOCK)
{ {
if(is_blocking)
{
return Socket::Status::Timeout;
}
return Socket::Status::WouldBlock; return Socket::Status::WouldBlock;
} }
else if(errno == EINTR) else if(errno == EINTR)
@ -220,6 +228,11 @@ namespace fr
tv.tv_sec = get_receive_timeout() / 1000; tv.tv_sec = get_receive_timeout() / 1000;
tv.tv_usec = (get_receive_timeout() % 1000) * 1000; tv.tv_usec = (get_receive_timeout() % 1000) * 1000;
setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
//Apply send timeout
tv.tv_sec = get_send_timeout() / 1000;
tv.tv_usec = (get_send_timeout() % 1000) * 1000;
setsockopt(socket_descriptor, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
#else #else
//Disable Nagle's algorithm //Disable Nagle's algorithm
setsockopt(get_socket_descriptor(), IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)); setsockopt(get_socket_descriptor(), IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
@ -228,6 +241,10 @@ namespace fr
//Apply receive timeout //Apply receive timeout
DWORD timeout_dword = static_cast<DWORD>(get_receive_timeout()); DWORD timeout_dword = static_cast<DWORD>(get_receive_timeout());
setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_dword, sizeof timeout_dword); setsockopt(socket_descriptor, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_dword, sizeof timeout_dword);
//Apply send timeout
timeout_dword = static_cast<DWORD>(get_send_timeout());
setsockopt(socket_descriptor, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout_dword, sizeof timeout_dword);
#endif #endif
} }