implemented socket_TCP_enableAliveChecks
This commit is contained in:
parent
ebab072835
commit
13ccfc7ff9
@ -13,6 +13,7 @@
|
|||||||
// include OS-dependent socket headers
|
// include OS-dependent socket headers
|
||||||
#if KN_USE_WINSOCK
|
#if KN_USE_WINSOCK
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2ipdef.h>
|
||||||
// There you can see what error codes mean.
|
// There you can see what error codes mean.
|
||||||
#include <winerror.h>
|
#include <winerror.h>
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -13,13 +13,9 @@ Result(void) network_init(){
|
|||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) network_deinit(){
|
void network_deinit(){
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
// Deinitialize Winsock
|
// Deinitialize Winsock
|
||||||
int result = WSACleanup();
|
(void)WSACleanup();
|
||||||
if (result != 0) {
|
|
||||||
return RESULT_ERROR_FMT("WSACleanup failed with error code 0x%X", result);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return RESULT_VOID;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,4 +2,4 @@
|
|||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
Result(void) network_init();
|
Result(void) network_init();
|
||||||
Result(void) network_deinit();
|
void network_deinit();
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
Result(Socket) socket_open_TCP(){
|
Result(Socket) socket_open_TCP(){
|
||||||
Socket s = socket(AF_INET, SOCK_STREAM, 0);
|
Socket s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if(s == -1){
|
if(s == -1){
|
||||||
return RESULT_ERROR_SOCKET();
|
return RESULT_ERROR_SOCKET();
|
||||||
}
|
}
|
||||||
@ -25,29 +25,6 @@ Result(void) socket_shutdown(Socket s, SocketShutdownType direction){
|
|||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) socket_setTimeout(Socket s, u32 ms){
|
|
||||||
void* opt;
|
|
||||||
u32 optlen;
|
|
||||||
|
|
||||||
#if KN_USE_WINSOCK
|
|
||||||
opt = &ms;
|
|
||||||
optlen = sizeof(ms);
|
|
||||||
#else
|
|
||||||
struct timeval tv = {
|
|
||||||
.tv_sec = ms/1000,
|
|
||||||
.tv_usec = (ms%1000)*1000
|
|
||||||
};
|
|
||||||
opt = &tv;
|
|
||||||
optlen = sizeof(tv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, opt, optlen) != 0)
|
|
||||||
return RESULT_ERROR_SOCKET();
|
|
||||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, opt, optlen) != 0)
|
|
||||||
return RESULT_ERROR_SOCKET();
|
|
||||||
return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(void) socket_bind(Socket s, EndpointIPv4 local_end){
|
Result(void) socket_bind(Socket s, EndpointIPv4 local_end){
|
||||||
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end);
|
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end);
|
||||||
if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
||||||
@ -146,3 +123,60 @@ Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, SocketRecvFlag flags, NU
|
|||||||
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
|
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
|
||||||
return RESULT_VALUE(i, r);
|
return RESULT_VALUE(i, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define try_setsockopt(socket, level, OPT){ \
|
||||||
|
if(setsockopt(socket, level, OPT, (void*)&opt_##OPT, sizeof(opt_##OPT)) != 0)\
|
||||||
|
return RESULT_ERROR_SOCKET();\
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) socket_TCP_enableAliveChecks(Socket s,
|
||||||
|
sec_t first_check_time, u32 checks_count, sec_t checks_interval)
|
||||||
|
{
|
||||||
|
#if KN_USE_WINSOCK
|
||||||
|
BOOL opt_SO_KEEPALIVE = 1; // enable keepalives
|
||||||
|
DWORD opt_TCP_KEEPIDLE = first_check_time;
|
||||||
|
DWORD opt_TCP_KEEPCNT = checks_count;
|
||||||
|
DWORD opt_TCP_KEEPINTVL = checks_interval;
|
||||||
|
try_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL);
|
||||||
|
|
||||||
|
// timeout for connect()
|
||||||
|
DWORD opt_TCP_MAXRT = checks_count * checks_interval;
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_MAXRT);
|
||||||
|
#else
|
||||||
|
int opt_SO_KEEPALIVE = 1; // enable keepalives
|
||||||
|
int opt_TCP_KEEPIDLE = first_check_time;
|
||||||
|
int opt_TCP_KEEPCNT = checks_count;
|
||||||
|
int opt_TCP_KEEPINTVL = checks_interval;
|
||||||
|
try_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT);
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL);
|
||||||
|
|
||||||
|
// read more in the article
|
||||||
|
int opt_TCP_USER_TIMEOUT = checks_count * checks_interval * 1000;
|
||||||
|
try_setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT);
|
||||||
|
#endif
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) socket_setTimeout(Socket s, u32 ms){
|
||||||
|
#if KN_USE_WINSOCK
|
||||||
|
DWORD opt_SO_SNDTIMEO = ms;
|
||||||
|
DWORD opt_SO_RCVTIMEO = opt_SO_SNDTIMEO;
|
||||||
|
#else
|
||||||
|
struct timeval opt_SO_SNDTIMEO = {
|
||||||
|
.tv_sec = ms/1000,
|
||||||
|
.tv_usec = (ms%1000)*1000
|
||||||
|
};
|
||||||
|
struct timeval opt_SO_RCVTIMEO = opt_SO_SNDTIMEO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try_setsockopt(s, SOL_SOCKET, SO_SNDTIMEO);
|
||||||
|
try_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO);
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
|
#include "tlibc/time.h"
|
||||||
#include "tlibc/collections/Array.h"
|
#include "tlibc/collections/Array.h"
|
||||||
|
|
||||||
typedef enum SocketShutdownType {
|
typedef enum SocketShutdownType {
|
||||||
@ -17,13 +18,9 @@ typedef enum SocketRecvFlag {
|
|||||||
|
|
||||||
typedef i64 Socket;
|
typedef i64 Socket;
|
||||||
|
|
||||||
#define SOCKET_TIMEOUT_MS_DEFAULT 5000
|
|
||||||
#define SOCKET_TIMEOUT_MS_INFINITE 0
|
|
||||||
|
|
||||||
Result(Socket) socket_open_TCP();
|
Result(Socket) socket_open_TCP();
|
||||||
void socket_close(Socket s);
|
void socket_close(Socket s);
|
||||||
Result(void) socket_shutdown(Socket s, SocketShutdownType direction);
|
Result(void) socket_shutdown(Socket s, SocketShutdownType direction);
|
||||||
Result(void) socket_setTimeout(Socket s, u32 ms);
|
|
||||||
|
|
||||||
Result(void) socket_bind(Socket s, EndpointIPv4 local_end);
|
Result(void) socket_bind(Socket s, EndpointIPv4 local_end);
|
||||||
Result(void) socket_listen(Socket s, i32 backlog);
|
Result(void) socket_listen(Socket s, i32 backlog);
|
||||||
@ -34,3 +31,18 @@ Result(void) socket_send(Socket s, Array(u8) buffer);
|
|||||||
Result(void) socket_sendto(Socket s, Array(u8) buffer, EndpointIPv4 dst);
|
Result(void) socket_sendto(Socket s, Array(u8) buffer, EndpointIPv4 dst);
|
||||||
Result(i32) socket_recv(Socket s, Array(u8) buffer, SocketRecvFlag flags);
|
Result(i32) socket_recv(Socket s, Array(u8) buffer, SocketRecvFlag flags);
|
||||||
Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, SocketRecvFlag flags, NULLABLE(EndpointIPv4*) remote_end);
|
Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, SocketRecvFlag flags, NULLABLE(EndpointIPv4*) remote_end);
|
||||||
|
|
||||||
|
/// Enables sending SO_KEEPALIVE packets when socket is idling.
|
||||||
|
/// Also enables TCP_USER_TIMEOUT to handle situations
|
||||||
|
/// when socket is not sending KEEPALIVE packets.
|
||||||
|
/// Read more: https://blog.cloudflare.com/when-tcp-sockets-refuse-to-die/
|
||||||
|
/// RU translaton: https://habr.com/ru/articles/700470/
|
||||||
|
Result(void) socket_TCP_enableAliveChecks(Socket s,
|
||||||
|
sec_t first_check_time, u32 checks_count, sec_t checks_interval);
|
||||||
|
#define socket_TCP_enableAliveChecks_default(socket) \
|
||||||
|
socket_TCP_enableAliveChecks(socket, 1, 4, 5)
|
||||||
|
|
||||||
|
#define SOCKET_TIMEOUT_MS_DEFAULT 5000
|
||||||
|
#define SOCKET_TIMEOUT_MS_INFINITE 0
|
||||||
|
/// @brief sets general timeout for send() and recv()
|
||||||
|
Result(void) socket_setTimeout(Socket s, u32 ms);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user