├── README.md ├── examples ├── echoz.c └── tcp_echoz.c └── zed_net.h /README.md: -------------------------------------------------------------------------------- 1 | # zed_net 2 | zed_net is a single file, public domain library that provides a simple wrapper around BSD sockets (Winsock 2.2 on Windows), intended primary for use in games. Only UDP sockets are supported at this time, but this may later expand to include TCP. 3 | 4 | This is my first library, and any suggestions/concerns are welcomed! ([@TheZedZull](https://twitter.com/TheZedZull) or thezedzull -at- gmail -dot- com) 5 | -------------------------------------------------------------------------------- /examples/echoz.c: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // This is a quick and dirty implementation of an echo client/server. 4 | // It isn't written to reflect best practices! 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define ZED_NET_IMPLEMENTATION 12 | #include "zed_net.h" 13 | 14 | int run_server(unsigned short port) { 15 | zed_net_init(); 16 | 17 | zed_net_socket_t socket; 18 | if (zed_net_udp_socket_open(&socket, port, 0)) { 19 | printf("Error: %s\n", zed_net_get_error()); 20 | return -1; 21 | } 22 | printf("Running echo server on port %d!\n", port); 23 | 24 | char buffer[256]; 25 | 26 | while (strcmp(buffer, "done") != 0) { 27 | zed_net_address_t sender; 28 | 29 | int bytes_read = zed_net_udp_socket_receive(&socket, &sender, &buffer, sizeof(buffer)); 30 | if (bytes_read) { 31 | printf("Received %d bytes from %s:%d: %s\n", bytes_read, zed_net_host_to_str(sender.host), sender.port, buffer); 32 | 33 | printf("Echoing...\n"); 34 | zed_net_udp_socket_send(&socket, sender, buffer, sizeof(buffer)); 35 | } 36 | } 37 | 38 | printf("Done!\n"); 39 | zed_net_socket_close(&socket); 40 | 41 | zed_net_shutdown(); 42 | 43 | return 0; 44 | } 45 | 46 | int run_client(const char *host, unsigned short port) { 47 | zed_net_init(); 48 | 49 | zed_net_socket_t socket; 50 | if (zed_net_udp_socket_open(&socket, 0, 0)) { 51 | printf("Error: %s\n", zed_net_get_error()); 52 | return -1; 53 | } 54 | 55 | zed_net_address_t address; 56 | if (zed_net_get_address(&address, host, port) != 0) { 57 | printf("Error: %s\n", zed_net_get_error()); 58 | 59 | zed_net_socket_close(&socket); 60 | zed_net_shutdown(); 61 | 62 | return -1; 63 | } 64 | 65 | printf("Running client! Type \"done\" to exit.\n"); 66 | 67 | char buffer[256]; 68 | 69 | while (strcmp(buffer, "done") != 0) { 70 | printf("Message: "); 71 | 72 | fgets(buffer, 256, stdin); 73 | buffer[strlen(buffer) - 1] = '\0'; 74 | 75 | printf("Sending...\n"); 76 | zed_net_udp_socket_send(&socket, address, buffer, sizeof(buffer)); 77 | 78 | zed_net_address_t sender; 79 | 80 | int bytes_read = zed_net_udp_socket_receive(&socket, &sender, &buffer, sizeof(buffer)); 81 | if (bytes_read) { 82 | printf("Received %d bytes from %s:%d: %s\n", bytes_read, zed_net_host_to_str(sender.host), sender.port, buffer); 83 | } 84 | } 85 | 86 | printf("Done!\n"); 87 | zed_net_socket_close(&socket); 88 | 89 | zed_net_shutdown(); 90 | 91 | return 0; 92 | } 93 | 94 | int main(int argc, char **argv) { 95 | if (argc == 3 && strcmp(argv[1], "-server") == 0) { 96 | return run_server((unsigned short) atoi(argv[2])); 97 | } else if (argc == 4 && strcmp(argv[1], "-client") == 0) { 98 | return run_client(argv[2], (unsigned short) atoi(argv[3])); 99 | } 100 | 101 | printf("Usage: echoz [-server [port] or -client [host] [port]\n"); 102 | 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /examples/tcp_echoz.c: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // This is a quick and dirty implementation of an echo client/server. TCP modification. 4 | // It isn't written to reflect best practices! 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define ZED_NET_IMPLEMENTATION 12 | #include "zed_net.h" 13 | 14 | int run_server(unsigned short port) { 15 | zed_net_init(); 16 | 17 | const char *host; 18 | zed_net_address_t remote_addr; 19 | zed_net_socket_t socket, remote_socket; 20 | zed_net_tcp_socket_open(&socket, port, 0, 1), 21 | printf("Running echo server on port %d!\n", port); 22 | 23 | char buffer[256]; 24 | 25 | if (zed_net_tcp_accept(&socket, &remote_socket, &remote_addr)) { 26 | printf("Failed to accept connection\n"); 27 | } 28 | 29 | host = zed_net_host_to_str(remote_addr.host); 30 | printf("Accepted connection from %s:%d\n", host, remote_addr.port); 31 | 32 | while (strcmp(buffer, "done") != 0) { 33 | int bytes_read = zed_net_tcp_socket_receive(&remote_socket, &buffer, sizeof(buffer)); 34 | if (bytes_read) { 35 | printf("Received %d bytes from %s:%d: %s\n", bytes_read, host, remote_addr.port, buffer); 36 | 37 | printf("Echoing...\n"); 38 | zed_net_tcp_socket_send(&remote_socket, buffer, sizeof(buffer)); 39 | } 40 | } 41 | 42 | printf("Done!\n"); 43 | zed_net_socket_close(&remote_socket); 44 | zed_net_socket_close(&socket); 45 | 46 | zed_net_shutdown(); 47 | 48 | return 0; 49 | } 50 | 51 | int run_client(const char *host, unsigned short port) { 52 | zed_net_init(); 53 | 54 | zed_net_socket_t socket; 55 | zed_net_tcp_socket_open(&socket, 0, 0, 0); 56 | 57 | zed_net_address_t address; 58 | if (zed_net_get_address(&address, host, port) != 0) { 59 | printf("Error: %s\n", zed_net_get_error()); 60 | 61 | zed_net_socket_close(&socket); 62 | zed_net_shutdown(); 63 | 64 | return -1; 65 | } 66 | 67 | printf("Running client! Type \"done\" to exit.\n"); 68 | 69 | if (zed_net_tcp_connect(&socket, address)) { 70 | printf("Failed to connect to %s:%d\n", host, port); 71 | return -1; 72 | } 73 | printf("Connected to %s:%d\n", host, port); 74 | 75 | char buffer[256]; 76 | 77 | while (strcmp(buffer, "done") != 0) { 78 | printf("Message: "); 79 | 80 | fgets(buffer, 256, stdin); 81 | buffer[strlen(buffer) - 1] = '\0'; 82 | 83 | printf("Sending...\n"); 84 | zed_net_tcp_socket_send(&socket, buffer, sizeof(buffer)); 85 | 86 | int bytes_read = zed_net_tcp_socket_receive(&socket, &buffer, sizeof(buffer)); 87 | if (bytes_read) { 88 | printf("Received %d bytes from %s:%d: %s\n", bytes_read, host, port, buffer); 89 | } 90 | } 91 | 92 | printf("Done!\n"); 93 | zed_net_socket_close(&socket); 94 | 95 | zed_net_shutdown(); 96 | 97 | return 0; 98 | } 99 | 100 | int main(int argc, char **argv) { 101 | if (argc == 3 && strcmp(argv[1], "-server") == 0) { 102 | return run_server((unsigned short) atoi(argv[2])); 103 | } else if (argc == 4 && strcmp(argv[1], "-client") == 0) { 104 | return run_client(argv[2], (unsigned short) atoi(argv[3])); 105 | } 106 | 107 | printf("Usage: echoz [-server [port] or -client [host] [port]\n"); 108 | 109 | return 0; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /zed_net.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // zed_net - v0.21 - public domain networking library 4 | // (inspired by the excellent stb libraries: https://github.com/nothings/stb) 5 | // 6 | // This library is intended primarily for use in games and provides a simple wrapper 7 | // around BSD sockets (Winsock 2.2 on Windows). Sockets can be set to be blocking or 8 | // non-blocking. 9 | // 10 | // Only UDP sockets are supported at this time, but this may later expand to include TCP. 11 | // 12 | // VERSION HISTORY 13 | // 14 | // 0.21 (14/01/2021) Win compilation fixes. 15 | // 0.20 (7/28/2019) OSX compilation fixes. 16 | // 0.19 (3/4/2016) TCP added and malloc/free calls removed. 17 | // Not backwards compatible. - Ian T. Jacobsen (itjac.me) 18 | // 0.18 (9/13/2015) minor polishing 19 | // 0.17 (8/8/2015) initial release 20 | // 21 | // LICENSE 22 | // 23 | // This software is in the public domain. Where that dedication is not recognized, you 24 | // are granted a perpetual, irrevocable license to copy, distribute, and modify this 25 | // file as you see fit. 26 | // 27 | // USAGE 28 | // 29 | // #define the symbol ZED_NET_IMPLEMENTATION in *one* C/C++ file before the #include 30 | // of this file; the implementation will be generated in that file. 31 | // 32 | // If you define the symbol ZED_NET_STATIC, then the implementation will be private to 33 | // that file. 34 | // 35 | // Immediately after this block comment is the "header file" section. This section 36 | // includes documentation for each API function. 37 | // 38 | 39 | #ifndef INCLUDE_ZED_NET_H 40 | #define INCLUDE_ZED_NET_H 41 | 42 | #ifdef ZED_NET_STATIC 43 | #define ZED_NET_DEF static 44 | #else 45 | #define ZED_NET_DEF extern 46 | #endif 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | ///////////////////////////////////////////////////////////////////////////////////////// 53 | // 54 | // INITIALIZATION AND SHUTDOWN 55 | // 56 | 57 | // Get a brief reason for failure 58 | ZED_NET_DEF const char *zed_net_get_error(void); 59 | 60 | // Perform platform-specific socket initialization; 61 | // *must* be called before using any other function 62 | // 63 | // Returns 0 on success, -1 otherwise (call 'zed_net_get_error' for more info) 64 | ZED_NET_DEF int zed_net_init(void); 65 | 66 | // Perform platform-specific socket de-initialization; 67 | // *must* be called when finished using the other functions 68 | ZED_NET_DEF void zed_net_shutdown(void); 69 | 70 | ///////////////////////////////////////////////////////////////////////////////////////// 71 | // 72 | // INTERNET ADDRESS API 73 | // 74 | 75 | // Represents an internet address usable by sockets 76 | typedef struct { 77 | unsigned int host; 78 | unsigned short port; 79 | } zed_net_address_t; 80 | 81 | // Obtain an address from a host name and a port 82 | // 83 | // 'host' may contain a decimal formatted IP (such as "127.0.0.1"), a human readable 84 | // name (such as "localhost"), or NULL for the default address 85 | // 86 | // Returns 0 on success, -1 otherwise (call 'zed_net_get_error' for more info) 87 | ZED_NET_DEF int zed_net_get_address(zed_net_address_t *address, const char *host, unsigned short port); 88 | 89 | // Converts an address's host name into a decimal formatted string 90 | // 91 | // Returns NULL on failure (call 'zed_net_get_error' for more info) 92 | ZED_NET_DEF const char *zed_net_host_to_str(unsigned int host); 93 | 94 | ///////////////////////////////////////////////////////////////////////////////////////// 95 | // 96 | // SOCKET HANDLE API 97 | // 98 | 99 | // Wraps the system handle for a UDP/TCP socket 100 | typedef struct { 101 | int handle; 102 | unsigned long non_blocking; 103 | int ready; 104 | } zed_net_socket_t; 105 | 106 | // Closes a previously opened socket 107 | ZED_NET_DEF void zed_net_socket_close(zed_net_socket_t *socket); 108 | 109 | ///////////////////////////////////////////////////////////////////////////////////////// 110 | // 111 | // UDP SOCKETS API 112 | // 113 | 114 | // Opens a UDP socket and binds it to a specified port 115 | // (use 0 to select a random open port) 116 | // 117 | // Socket will not block if 'non-blocking' is non-zero 118 | // 119 | // Returns 0 on success 120 | // Returns -1 on failure (call 'zed_net_get_error' for more info) 121 | ZED_NET_DEF int zed_net_udp_socket_open(zed_net_socket_t *socket, unsigned int port, unsigned long non_blocking); 122 | 123 | // Sends a specific amount of data to 'destination' 124 | // 125 | // Returns 0 on success, -1 otherwise (call 'zed_net_get_error' for more info) 126 | ZED_NET_DEF int zed_net_udp_socket_send(zed_net_socket_t *socket, zed_net_address_t destination, const void *data, int size); 127 | 128 | // Receives a specific amount of data from 'sender' 129 | // 130 | // Returns the number of bytes received, -1 otherwise (call 'zed_net_get_error' for more info) 131 | ZED_NET_DEF int zed_net_udp_socket_receive(zed_net_socket_t *socket, zed_net_address_t *sender, void *data, int size); 132 | 133 | ///////////////////////////////////////////////////////////////////////////////////////// 134 | // 135 | // TCP SOCKETS API 136 | // 137 | 138 | // Opens a TCP socket and binds it to a specified port 139 | // (use 0 to select a random open port) 140 | // 141 | // Socket will not block if 'non-blocking' is non-zero 142 | // 143 | // Returns NULL on failure (call 'zed_net_get_error' for more info) 144 | // Socket will listen for incoming connections if 'listen_socket' is non-zero 145 | // Returns 0 on success 146 | // Returns -1 on failure (call 'zed_net_get_error' for more info) 147 | ZED_NET_DEF int zed_net_tcp_socket_open(zed_net_socket_t *socket, unsigned int port, unsigned long non_blocking, int listen_socket); 148 | 149 | // Connect to a remote endpoint 150 | // Returns 0 on success. 151 | // if the socket is non-blocking, then this can return 1 if the socket isn't ready 152 | // returns -1 otherwise. (call 'zed_net_get_error' for more info) 153 | ZED_NET_DEF int zed_net_tcp_connect(zed_net_socket_t *socket, zed_net_address_t remote_addr); 154 | 155 | // Accept connection 156 | // New remote_socket inherits non-blocking from listening_socket 157 | // Returns 0 on success. 158 | // if the socket is non-blocking, then this can return 1 if the socket isn't ready 159 | // if the socket is non_blocking and there was no connection to accept, returns 2 160 | // returns -1 otherwise. (call 'zed_net_get_error' for more info) 161 | ZED_NET_DEF int zed_net_tcp_accept(zed_net_socket_t *listening_socket, zed_net_socket_t *remote_socket, zed_net_address_t *remote_addr); 162 | 163 | // Returns 0 on success. 164 | // if the socket is non-blocking, then this can return 1 if the socket isn't ready 165 | // returns -1 otherwise. (call 'zed_net_get_error' for more info) 166 | ZED_NET_DEF int zed_net_tcp_socket_send(zed_net_socket_t *remote_socket, const void *data, int size); 167 | 168 | // Returns 0 on success. 169 | // if the socket is non-blocking, then this can return 1 if the socket isn't ready 170 | // returns -1 otherwise. (call 'zed_net_get_error' for more info) 171 | ZED_NET_DEF int zed_net_tcp_socket_receive(zed_net_socket_t *remote_socket, void *data, int size); 172 | 173 | // Blocks until the TCP socket is ready. Only makes sense for non-blocking socket. 174 | // Returns 0 on success. 175 | // returns -1 otherwise. (call 'zed_net_get_error' for more info) 176 | ZED_NET_DEF int zed_net_tcp_make_socket_ready(zed_net_socket_t *socket); 177 | 178 | #ifdef __cplusplus 179 | } 180 | #endif 181 | 182 | #endif // INCLUDE_ZED_NET_H 183 | 184 | #ifdef ZED_NET_IMPLEMENTATION 185 | 186 | #include 187 | #include 188 | #include 189 | 190 | #ifdef _WIN32 191 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 192 | #include 193 | #pragma comment(lib, "wsock32.lib") 194 | #define ZED_NET_SOCKET_ERROR SOCKET_ERROR 195 | #define ZED_NET_INVALID_SOCKET INVALID_SOCKET 196 | #else 197 | #include 198 | #include 199 | #include 200 | #include 201 | #include 202 | #include 203 | #define ZED_NET_SOCKET_ERROR -1 204 | #define ZED_NET_INVALID_SOCKET -1 205 | #endif 206 | 207 | static const char *zed_net__g_error; 208 | 209 | static int zed_net__error(const char *message) { 210 | zed_net__g_error = message; 211 | 212 | return -1; 213 | } 214 | 215 | ZED_NET_DEF const char *zed_net_get_error(void) { 216 | return zed_net__g_error; 217 | } 218 | 219 | ZED_NET_DEF int zed_net_init(void) { 220 | #ifdef _WIN32 221 | WSADATA wsa_data; 222 | if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) 223 | { 224 | return zed_net__error("Windows Sockets failed to start"); 225 | } 226 | 227 | return 0; 228 | #else 229 | return 0; 230 | #endif 231 | } 232 | 233 | ZED_NET_DEF void zed_net_shutdown(void) { 234 | #ifdef _WIN32 235 | WSACleanup(); 236 | #endif 237 | } 238 | 239 | ZED_NET_DEF int zed_net_get_address(zed_net_address_t *address, const char *host, unsigned short port) { 240 | if (host == NULL) { 241 | address->host = INADDR_ANY; 242 | } else { 243 | address->host = inet_addr(host); 244 | if (address->host == INADDR_NONE) { 245 | struct hostent *hostent = gethostbyname(host); 246 | if (hostent) { 247 | memcpy(&address->host, hostent->h_addr, hostent->h_length); 248 | } else { 249 | return zed_net__error("Invalid host name"); 250 | } 251 | } 252 | } 253 | 254 | address->port = port; 255 | 256 | return 0; 257 | } 258 | 259 | ZED_NET_DEF const char *zed_net_host_to_str(unsigned int host) { 260 | struct in_addr in; 261 | in.s_addr = host; 262 | 263 | return inet_ntoa(in); 264 | } 265 | 266 | ZED_NET_DEF int zed_net_udp_socket_open(zed_net_socket_t *sock, unsigned int port, unsigned long non_blocking) { 267 | if (!sock) 268 | return zed_net__error("Socket is NULL"); 269 | 270 | // Create the socket 271 | sock->handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 272 | if (sock->handle <= 0) { 273 | zed_net_socket_close(sock); 274 | return zed_net__error("Failed to create socket"); 275 | } 276 | 277 | // Bind the socket to the port 278 | struct sockaddr_in address; 279 | address.sin_family = AF_INET; 280 | address.sin_addr.s_addr = INADDR_ANY; 281 | address.sin_port = htons(port); 282 | 283 | if (bind(sock->handle, (const struct sockaddr *) &address, sizeof(struct sockaddr_in)) != 0) { 284 | zed_net_socket_close(sock); 285 | return zed_net__error("Failed to bind socket"); 286 | } 287 | 288 | // Set the socket to non-blocking if neccessary 289 | if (non_blocking) { 290 | #ifdef _WIN32 291 | if (ioctlsocket(sock->handle, FIONBIO, &non_blocking) != 0) { 292 | zed_net_socket_close(sock); 293 | return zed_net__error("Failed to set socket to non-blocking"); 294 | } 295 | #else 296 | if (fcntl(sock->handle, F_SETFL, O_NONBLOCK, non_blocking) != 0) { 297 | zed_net_socket_close(sock); 298 | return zed_net__error("Failed to set socket to non-blocking"); 299 | } 300 | #endif 301 | } 302 | 303 | sock->non_blocking = non_blocking; 304 | 305 | return 0; 306 | } 307 | 308 | ZED_NET_DEF int zed_net_tcp_socket_open(zed_net_socket_t *sock, unsigned int port, unsigned long non_blocking, int listen_socket) { 309 | if (!sock) 310 | return zed_net__error("Socket is NULL"); 311 | 312 | // Create the socket 313 | sock->handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 314 | if (sock->handle <= 0) { 315 | zed_net_socket_close(sock); 316 | return zed_net__error("Failed to create socket"); 317 | } 318 | 319 | // Bind the socket to the port 320 | struct sockaddr_in address; 321 | address.sin_family = AF_INET; 322 | address.sin_addr.s_addr = INADDR_ANY; 323 | address.sin_port = htons(port); 324 | 325 | if (bind(sock->handle, (const struct sockaddr *) &address, sizeof(struct sockaddr_in)) != 0) { 326 | zed_net_socket_close(sock); 327 | return zed_net__error("Failed to bind socket"); 328 | } 329 | 330 | // Set the socket to non-blocking if neccessary 331 | if (non_blocking) { 332 | #ifdef _WIN32 333 | if (ioctlsocket(sock->handle, FIONBIO, &non_blocking) != 0) { 334 | zed_net_socket_close(sock); 335 | return zed_net__error("Failed to set socket to non-blocking"); 336 | } 337 | #else 338 | if (fcntl(sock->handle, F_SETFL, O_NONBLOCK, non_blocking) != 0) { 339 | zed_net_socket_close(sock); 340 | return zed_net__error("Failed to set socket to non-blocking"); 341 | } 342 | #endif 343 | sock->ready = 0; 344 | } 345 | 346 | if (listen_socket) { 347 | #ifndef SOMAXCONN 348 | #define SOMAXCONN 10 349 | #endif 350 | if (listen(sock->handle, SOMAXCONN) != 0) { 351 | zed_net_socket_close(sock); 352 | return zed_net__error("Failed make socket listen"); 353 | } 354 | } 355 | sock->non_blocking = non_blocking; 356 | 357 | return 0; 358 | } 359 | 360 | // Returns 1 if it would block, <0 if there's an error. 361 | ZED_NET_DEF int zed_net_check_would_block(zed_net_socket_t *socket) { 362 | struct timeval timer; 363 | fd_set writefd; 364 | int retval; 365 | 366 | if (socket->non_blocking && !socket->ready) { 367 | FD_ZERO(&writefd); 368 | FD_SET(socket->handle, &writefd); 369 | timer.tv_sec = 0; 370 | timer.tv_usec = 0; 371 | retval = select(0, NULL, &writefd, NULL, &timer); 372 | if (retval == 0) 373 | return 1; 374 | else if (retval == ZED_NET_SOCKET_ERROR) { 375 | zed_net_socket_close(socket); 376 | return zed_net__error("Got socket error from select()"); 377 | } 378 | socket->ready = 1; 379 | } 380 | 381 | return 0; 382 | } 383 | 384 | ZED_NET_DEF int zed_net_tcp_make_socket_ready(zed_net_socket_t *socket) { 385 | if (!socket->non_blocking) 386 | return 0; 387 | if (socket->ready) 388 | return 0; 389 | 390 | fd_set writefd; 391 | int retval; 392 | 393 | FD_ZERO(&writefd); 394 | FD_SET(socket->handle, &writefd); 395 | retval = select(0, NULL, &writefd, NULL, NULL); 396 | if (retval != 1) 397 | return zed_net__error("Failed to make non-blocking socket ready"); 398 | 399 | socket->ready = 1; 400 | 401 | return 0; 402 | } 403 | 404 | ZED_NET_DEF int zed_net_tcp_connect(zed_net_socket_t *socket, zed_net_address_t remote_addr) { 405 | struct sockaddr_in address; 406 | int retval; 407 | 408 | if (!socket) 409 | return zed_net__error("Socket is NULL"); 410 | 411 | retval = zed_net_check_would_block(socket); 412 | if (retval == 1) 413 | return 1; 414 | else if (retval) 415 | return -1; 416 | 417 | address.sin_family = AF_INET; 418 | address.sin_addr.s_addr = remote_addr.host; 419 | address.sin_port = htons(remote_addr.port); 420 | 421 | retval = connect(socket->handle, (const struct sockaddr *) &address, sizeof(address)); 422 | if (retval == ZED_NET_SOCKET_ERROR) { 423 | zed_net_socket_close(socket); 424 | return zed_net__error("Failed to connect socket"); 425 | } 426 | 427 | return 0; 428 | } 429 | 430 | ZED_NET_DEF int zed_net_tcp_accept(zed_net_socket_t *listening_socket, zed_net_socket_t *remote_socket, zed_net_address_t *remote_addr) { 431 | struct sockaddr_in address; 432 | int retval, handle; 433 | 434 | if (!listening_socket) 435 | return zed_net__error("Listening socket is NULL"); 436 | if (!remote_socket) 437 | return zed_net__error("Remote socket is NULL"); 438 | if (!remote_addr) 439 | return zed_net__error("Address pointer is NULL"); 440 | 441 | retval = zed_net_check_would_block(listening_socket); 442 | if (retval == 1) 443 | return 1; 444 | else if (retval) 445 | return -1; 446 | #ifdef _WIN32 447 | typedef int socklen_t; 448 | #endif 449 | socklen_t addrlen = sizeof(address); 450 | handle = accept(listening_socket->handle, (struct sockaddr *)&address, &addrlen); 451 | 452 | if (handle == ZED_NET_INVALID_SOCKET) 453 | return 2; 454 | 455 | remote_addr->host = address.sin_addr.s_addr; 456 | remote_addr->port = ntohs(address.sin_port); 457 | remote_socket->non_blocking = listening_socket->non_blocking; 458 | remote_socket->ready = 0; 459 | remote_socket->handle = handle; 460 | 461 | return 0; 462 | } 463 | 464 | ZED_NET_DEF void zed_net_socket_close(zed_net_socket_t *socket) { 465 | if (!socket) { 466 | return; 467 | } 468 | 469 | if (socket->handle) { 470 | #ifdef _WIN32 471 | closesocket(socket->handle); 472 | #else 473 | close(socket->handle); 474 | #endif 475 | } 476 | } 477 | 478 | ZED_NET_DEF int zed_net_udp_socket_send(zed_net_socket_t *socket, zed_net_address_t destination, const void *data, int size) { 479 | if (!socket) { 480 | return zed_net__error("Socket is NULL"); 481 | } 482 | 483 | struct sockaddr_in address; 484 | address.sin_family = AF_INET; 485 | address.sin_addr.s_addr = destination.host; 486 | address.sin_port = htons(destination.port); 487 | 488 | int sent_bytes = sendto(socket->handle, (const char *) data, size, 0, (const struct sockaddr *) &address, sizeof(struct sockaddr_in)); 489 | if (sent_bytes != size) { 490 | return zed_net__error("Failed to send data"); 491 | } 492 | 493 | return 0; 494 | } 495 | 496 | ZED_NET_DEF int zed_net_udp_socket_receive(zed_net_socket_t *socket, zed_net_address_t *sender, void *data, int size) { 497 | if (!socket) { 498 | return zed_net__error("Socket is NULL"); 499 | } 500 | 501 | #ifdef _WIN32 502 | typedef int socklen_t; 503 | #endif 504 | 505 | struct sockaddr_in from; 506 | socklen_t from_length = sizeof(from); 507 | 508 | int received_bytes = recvfrom(socket->handle, (char *) data, size, 0, (struct sockaddr *) &from, &from_length); 509 | if (received_bytes <= 0) { 510 | return 0; 511 | } 512 | 513 | sender->host = from.sin_addr.s_addr; 514 | sender->port = ntohs(from.sin_port); 515 | 516 | return received_bytes; 517 | } 518 | 519 | ZED_NET_DEF int zed_net_tcp_socket_send(zed_net_socket_t *remote_socket, const void *data, int size) { 520 | int retval; 521 | 522 | if (!remote_socket) { 523 | return zed_net__error("Socket is NULL"); 524 | } 525 | 526 | retval = zed_net_check_would_block(remote_socket); 527 | if (retval == 1) 528 | return 1; 529 | else if (retval) 530 | return -1; 531 | 532 | int sent_bytes = send(remote_socket->handle, (const char *) data, size, 0); 533 | if (sent_bytes != size) { 534 | return zed_net__error("Failed to send data"); 535 | } 536 | 537 | return 0; 538 | } 539 | 540 | ZED_NET_DEF int zed_net_tcp_socket_receive(zed_net_socket_t *remote_socket, void *data, int size) { 541 | int retval; 542 | 543 | if (!remote_socket) { 544 | return zed_net__error("Socket is NULL"); 545 | } 546 | 547 | retval = zed_net_check_would_block(remote_socket); 548 | if (retval == 1) 549 | return 1; 550 | else if (retval) 551 | return -1; 552 | 553 | #ifdef _WIN32 554 | typedef int socklen_t; 555 | #endif 556 | 557 | int received_bytes = recv(remote_socket->handle, (char *) data, size, 0); 558 | if (received_bytes <= 0) { 559 | return 0; 560 | } 561 | return received_bytes; 562 | } 563 | 564 | #endif // ZED_NET_IMPLEMENTATION 565 | 566 | // vim: tabstop=4 shiftwidth=4 expandtab 567 | --------------------------------------------------------------------------------