/** * @return A printable error string for the most recent OS-level network error. */ const char *Net_GetErrorString(void) { #if defined(_WIN32) static char s[MAX_STRING_CHARS] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Net_GetError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), s, sizeof(s), NULL); return s; #else return strerror(Net_GetError()); #endif }
/** * @brief Send data to the specified TCP stream. */ _Bool Net_SendStream(int32_t sock, const void *data, size_t len) { mem_buf_t buf; byte buffer[MAX_MSG_SIZE]; Mem_InitBuffer(&buf, buffer, sizeof(buffer)); // write the packet length Net_WriteLong(&buf, (int32_t) len); // and copy the payload Net_WriteData(&buf, data, len); ssize_t sent = 0; while ((size_t) sent < buf.size) { const ssize_t s = send(sock, (void *)(buf.data + sent), buf.size - sent, 0); if (s == -1) { if (Net_GetError() != EWOULDBLOCK) { Com_Warn("%s\n", Net_GetErrorString()); return false; } } sent += s; } return sent == (ssize_t) buf.size; }
/** * @brief Receive data from the specified TCP stream. */ _Bool Net_ReceiveStream(int32_t sock, mem_buf_t *buf) { buf->size = buf->read = 0; const ssize_t received = recv(sock, (void *) buf->data, buf->max_size, 0); if (received == -1) { if (Net_GetError() == EWOULDBLOCK) { return false; // no data, don't crap our pants } Com_Warn("%s\n", Net_GetErrorString()); return false; } buf->size = received; // check the packet length return Net_ReadLong(buf) > -1; }
/* * @brief */ _Bool Net_GetPacket(net_src_t source, net_addr_t *from, size_buf_t *message) { ssize_t ret; int32_t err; struct sockaddr_in from_addr; socklen_t from_len; char *s; if (Net_GetLocalPacket(source, from, message)) return true; if (!ip_sockets[source]) return false; from_len = sizeof(from_addr); ret = recvfrom(ip_sockets[source], (void *) message->data, message->max_size, 0, (struct sockaddr *) &from_addr, &from_len); Net_SockaddrToNetaddr(&from_addr, from); if (ret == -1) { err = Net_GetError(); if (err == EWOULDBLOCK || err == ECONNREFUSED) return false; // not terribly abnormal s = source == NS_SERVER ? "server" : "client"; Com_Warn("%s: %s from %s\n", s, Net_ErrorString(), Net_NetaddrToString(*from)); return false; } if (ret == ((ssize_t) message->max_size)) { Com_Warn("Oversized packet from %s\n", Net_NetaddrToString(*from)); return false; } message->size = (uint32_t) ret; return true; }
/** * @brief Establishes a TCP connection to the specified host. * * @param host The host to connect to. See Net_StringToNetaddr. */ int32_t Net_Connect(const char *host, struct timeval *timeout) { int32_t sock = Net_Socket(NA_STREAM, NULL, 0); struct sockaddr_in to; Net_StringToSockaddr(host, &to); if (connect(sock, (const struct sockaddr *) &to, sizeof(to)) == -1) { if (Net_GetError() == EINPROGRESS) { fd_set w_set; FD_ZERO(&w_set); FD_SET((uint32_t) sock, &w_set); if (select(sock + 1, NULL, &w_set, NULL, timeout) < 1) { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } int32_t error = -1; socklen_t len = sizeof(error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &len) < 0) { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } if (error) { Com_Error(ERROR_DROP, "%s\n", strerror(error)); } } else { Com_Error(ERROR_DROP, "%s\n", Net_GetErrorString()); } } return sock; }
/* * @brief */ static const char *Net_ErrorString(void) { const int32_t code = Net_GetError(); return strerror(code); }
/* * @return A printable error string for the most recent OS-level network error. */ const char *Net_GetErrorString(void) { return strerror(Net_GetError()); }