diff --git a/src/base/system.c b/src/base/system.c index 61356c429..77ade8dbb 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -1522,29 +1522,80 @@ int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size #endif /* FUZZING */ } -int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize) +void net_init_mmsgs(MMSGS* m) +{ +#if defined(CONF_PLATFORM_LINUX) + m->pos = 0; + m->size = 0; + mem_zero(m->msgs, sizeof(m->msgs)); + mem_zero(m->iovecs, sizeof(m->iovecs)); + mem_zero(m->sockaddrs, sizeof(m->sockaddrs)); + for(int i = 0; i < VLEN; ++i) + { + m->iovecs[i].iov_base = m->bufs[i]; + m->iovecs[i].iov_len = PACKETSIZE; + m->msgs[i].msg_hdr.msg_iov = &m->iovecs[i]; + m->msgs[i].msg_hdr.msg_iovlen = 1; + m->msgs[i].msg_hdr.msg_name = &m->sockaddrs[i]; + m->msgs[i].msg_hdr.msg_namelen = sizeof(&m->sockaddrs[i]); + } +#endif +} + +int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize, MMSGS* m) { #ifndef FUZZING char sockaddrbuf[128]; - socklen_t fromlen;// = sizeof(sockaddrbuf); int bytes = 0; +#if defined(CONF_PLATFORM_LINUX) + if(sock.ipv4sock >= 0) + { + if(m->pos >= m->size) + { + m->size = recvmmsg(sock.ipv4sock, m->msgs, VLEN, 0, NULL); + m->pos = 0; + } + } + + if(sock.ipv6sock >= 0) + { + if(m->pos >= m->size) + { + m->size = recvmmsg(sock.ipv6sock, m->msgs, VLEN, 0, NULL); + m->pos = 0; + } + } + + if(m->pos < m->size) + { + sockaddr_to_netaddr((struct sockaddr *)&(m->sockaddrs[m->pos]), addr); + // TODO: network_stats + //network_stats.recv_bytes += bytes; + //network_stats.recv_packets++; + bytes = m->msgs[m->pos].msg_len; + mem_copy(data, m->bufs[m->pos], bytes); + m->pos++; + return bytes; + } +#else if(bytes == 0 && sock.ipv4sock >= 0) { - fromlen = sizeof(struct sockaddr_in); + int fromlen = sizeof(struct sockaddr_in); bytes = recvfrom(sock.ipv4sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen); } if(bytes <= 0 && sock.ipv6sock >= 0) { - fromlen = sizeof(struct sockaddr_in6); + int fromlen = sizeof(struct sockaddr_in6); bytes = recvfrom(sock.ipv6sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen); } +#endif #if defined(CONF_WEBSOCKETS) if(bytes <= 0 && sock.web_ipv4sock >= 0) { - fromlen = sizeof(struct sockaddr); + int fromlen = sizeof(struct sockaddr); bytes = websocket_recv(sock.web_ipv4sock, data, maxsize, (struct sockaddr_in *)&sockaddrbuf, fromlen); ((struct sockaddr_in *)&sockaddrbuf)->sin_family = AF_WEBSOCKET_INET; } @@ -1560,7 +1611,7 @@ int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize) else if(bytes == 0) return 0; return -1; /* error */ -#else +#else /* ifdef FUZZING */ addr->type = NETTYPE_IPV4; addr->port = 11111; addr->ip[0] = 127; diff --git a/src/base/system.h b/src/base/system.h index 1f4b54e71..fdaa816cf 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -9,6 +9,11 @@ #define BASE_SYSTEM_H #include "detect.h" + +#ifndef __USE_GNU +#define __USE_GNU +#endif + #include #include #include @@ -17,6 +22,10 @@ #include #endif +#ifdef CONF_PLATFORM_LINUX +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -747,6 +756,22 @@ NETSOCKET net_udp_create(NETADDR bindaddr); */ int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size); +#define VLEN 128 +#define PACKETSIZE 1400 +typedef struct +{ +#ifdef CONF_PLATFORM_LINUX + int pos; + int size; + struct mmsghdr msgs[VLEN]; + struct iovec iovecs[VLEN]; + char bufs[VLEN][PACKETSIZE]; + char sockaddrs[VLEN][128]; +#endif +} MMSGS; + +void net_init_mmsgs(MMSGS* m); + /* Function: net_udp_recv Receives a packet over an UDP socket. @@ -761,7 +786,7 @@ int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size On success it returns the number of bytes received. Returns -1 on error. */ -int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize); +int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize, MMSGS* m); /* Function: net_udp_close diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 3d86e842d..7d8c4963b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -2031,6 +2031,13 @@ int CServer::Run() int64 t = time_get(); int x = (TickStartTime(m_CurrentGameTick+1) - t) * 1000000 / time_freq() + 1; + if(x > 3000) + { + // at least sleep 3 ms, reduce number of syscalls in stress situations + thread_sleep(3); + x = (TickStartTime(m_CurrentGameTick+1) - t) * 1000000 / time_freq() + 1; + } + if(x > 0) { net_socket_read_wait(m_NetServer.Socket(), x); diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index 9b6de2b11..cd7ccec2b 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -301,6 +301,7 @@ class CNetServer }; NETSOCKET m_Socket; + MMSGS m_MMSGS; class CNetBan *m_pNetBan; CSlot m_aSlots[NET_MAX_CLIENTS]; int m_MaxClients; @@ -423,6 +424,7 @@ class CNetClient CNetRecvUnpacker m_RecvUnpacker; public: NETSOCKET m_Socket; + MMSGS m_MMSGS; // openness bool Open(NETADDR BindAddr, int Flags); int Close(); diff --git a/src/engine/shared/network_client.cpp b/src/engine/shared/network_client.cpp index 2fc13981e..b3a5208e9 100644 --- a/src/engine/shared/network_client.cpp +++ b/src/engine/shared/network_client.cpp @@ -17,6 +17,8 @@ bool CNetClient::Open(NETADDR BindAddr, int Flags) // init m_Socket = Socket; m_Connection.Init(m_Socket, false); + net_init_mmsgs(&m_MMSGS); + return true; } @@ -64,7 +66,7 @@ int CNetClient::Recv(CNetChunk *pChunk) // TODO: empty the recvinfo NETADDR Addr; - int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE); + int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE, &m_MMSGS); // no more packets for now if(Bytes <= 0) diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index 1d70b1a84..6a57668f9 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -80,6 +80,8 @@ bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int Ma for(int i = 0; i < NET_MAX_CLIENTS; i++) m_aSlots[i].m_Connection.Init(m_Socket, true); + net_init_mmsgs(&m_MMSGS); + return true; } @@ -598,7 +600,7 @@ int CNetServer::Recv(CNetChunk *pChunk) return 1; // TODO: empty the recvinfo - int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE); + int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE, &m_MMSGS); // no more packets for now if(Bytes <= 0)