#ifdef WIN32 #include #else #include #include #include #endif #include #include "shared.h" #include "endian.h" #include "net.h" #include "q2defines.h" #include "utils.h" int UDP_Begin() { #ifdef WIN32 int err; WSADATA wsaData; err = WSAStartup(MAKEWORD(1, 1), &wsaData); if (err) return -1; // make sure WinSock DLL is 1.1 or greater if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) return -1; #endif return 0; } int UDP_End() { #ifdef WIN32 if (WSACleanup() < 0) return -1; #endif return 0; } int UDP_OpenSocket(unsigned short *port) { SOCKET sd; int i; struct sockaddr_in addr; sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sd == -1) return -1; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(*port); i = 1; if (ioctlsocket(sd, FIONBIO, &i) < 0) { closesocket(sd); return -1; } i = 32768; setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof(int)); setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof(int)); if (bind(sd, (void *)&addr, sizeof(addr)) < 0) { closesocket(sd); return -1; } *port = ntohs(addr.sin_port); return sd; } int UDP_CloseSocket(SOCKET sd) { return closesocket(sd); } int UDP_Read(SOCKET sd, void *buf, size_t len, struct sockaddr_in *addr) { int ret, addrlen; addrlen = sizeof(struct sockaddr_in); ret = recvfrom(sd, buf, len, 0, (struct sockaddr *)addr, &addrlen); #ifdef WIN32 if (ret == SOCKET_ERROR) { switch (WSAGetLastError()) { case WSAENETRESET: case WSAEWOULDBLOCK: case WSAEMSGSIZE: case WSAECONNRESET: return 0; default: return -1; } } #else if (ret == -1) { switch(errno) { case EAGAIN: case EINTR: return 0; default: return -1; } } #endif return ret; } int UDP_Write(SOCKET sd, void *buf, size_t len, struct sockaddr_in *addr) { return sendto(sd, buf, len, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); } int UDP_Poll(SOCKET sd, qboolean *readable, qboolean *writeable, qboolean *errors, long msecs) { fd_set readfds, writefds, errorfds; struct timeval tv; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); FD_SET(sd, &readfds); FD_SET(sd, &writefds); FD_SET(sd, &errorfds); tv.tv_sec = 0; tv.tv_usec = msecs * 1000; if (select(sd, (readable ? &readfds : NULL), (writeable ? &writefds : NULL), (errors ? &errorfds : NULL), (msecs >= 0 ? &tv : NULL)) < 0) { return -1; } if (readable) *readable = FD_ISSET(sd, &readfds); if (writeable) *writeable = FD_ISSET(sd, &writefds); if (errors) *errors = FD_ISSET(sd, &errorfds); return 0; } char *UDP_AddrToString(struct sockaddr_in *addr) { static char buffer[22]; int haddr; haddr = ntohl(addr->sin_addr.s_addr); sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(addr->sin_port)); return buffer; } int UDP_AddrCompare(struct sockaddr_in *addr1, struct sockaddr_in *addr2) { if (addr1->sin_family != addr2->sin_family) return -1; if (addr1->sin_addr.s_addr != addr2->sin_addr.s_addr) return -1; if (addr1->sin_port != addr2->sin_port) return 1; return 0; } int UDP_SendConnectionless(SOCKET sd, void *buf, size_t len, struct sockaddr_in *addr) { block_t block; char buffer[MAX_SVSLEN]; BlockInit(&block, buffer, sizeof(buffer)); WriteLong(&block, 0xffffffff); BlockWrite(&block, buf, len); if (WriteOverflow(&block)) return -1; return UDP_Write(sd, block.buffer, block.writeoffset, addr); } int UDP_SendUnreliable(SOCKET sd, void *buf, size_t len, net_t *net) { block_t block; char buffer[MAX_SVSLEN]; int ret; BlockInit(&block, buffer, sizeof(buffer)); WriteLong(&block, net->out_seq++); WriteLong(&block, net->in_seq | net->out_bit); BlockWrite(&block, buf, len); if (WriteOverflow(&block)) return -1; #if 0 printf("SEND %08x %08x%c\n", net->out_seq - 1, net->in_seq, (net->out_bit ? 'R' : ' ')); #endif ret = UDP_Write(sd, block.buffer, block.writeoffset, &net->addr); if (ret != -1) net->keepalive_time = mstime() + KEEPALIVE_TIME; return ret; } int UDP_SendReliable(SOCKET sd, void *buf, size_t len, net_t *net) { block_t block; char buffer[MAX_SVSLEN]; int ret; net->out_reliable_seq = net->out_seq; BlockInit(&block, buffer, sizeof(buffer)); WriteLong(&block, net->out_seq++ | RELIABLE_FLAG); WriteLong(&block, net->in_seq | net->out_bit); BlockWrite(&block, buf, len); if (WriteOverflow(&block)) return -1; #if 0 printf("SEND %08xR %08x%c\n", net->out_seq - 1, net->in_seq, (net->out_bit ? 'R' : ' ')); #endif ret = UDP_Write(sd, block.buffer, block.writeoffset, &net->addr); if (ret != -1) net->keepalive_time = mstime() + KEEPALIVE_TIME; return ret; } int UDP_ResendReliable(SOCKET sd, void *buf, size_t len, net_t *net) { block_t block; char buffer[MAX_SVSLEN]; int ret; BlockInit(&block, buffer, sizeof(buffer)); WriteLong(&block, net->out_reliable_seq | RELIABLE_FLAG); WriteLong(&block, net->in_seq | net->out_bit); BlockWrite(&block, buf, len); if (WriteOverflow(&block)) return -1; #if 0 printf("SEND %08xR %08x%c\n", net->out_reliable_seq, net->in_seq, (net->out_bit ? 'R' : ' ')); #endif ret = UDP_Write(sd, block.buffer, block.writeoffset, &net->addr); if (ret != -1) net->keepalive_time = mstime() + KEEPALIVE_TIME; return ret; }