unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
socket.c (38815B)
1 /* 2 * Unreal Internet Relay Chat Daemon, src/socket.c 3 * Copyright (C) 1990 Jarkko Oikarinen and 4 * University of Oulu, Computing Center 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 1, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 /** @file 22 * @brief Socket functions such as reading, writing, connecting. 23 * 24 * The actual data parsing functions (for incoming data) are in 25 * src/parse.c. 26 */ 27 28 #include "unrealircd.h" 29 #include "dns.h" 30 31 int OpenFiles = 0; /* GLOBAL - number of files currently open */ 32 int readcalls = 0; 33 34 void completed_connection(int, int, void *); 35 void set_sock_opts(int, Client *, SocketType); 36 void set_ipv6_opts(int); 37 void close_listener(ConfigItem_listen *listener); 38 static char readbuf[BUFSIZE]; 39 char zlinebuf[BUFSIZE]; 40 extern char *version; 41 MODVAR time_t last_allinuse = 0; 42 43 void start_of_normal_client_handshake(Client *client); 44 void proceed_normal_client_handshake(Client *client, struct hostent *he); 45 46 /** Close all connections - only used when we terminate the server (eg: /DIE or SIGTERM) */ 47 void close_connections(void) 48 { 49 Client *client; 50 51 list_for_each_entry(client, &lclient_list, lclient_node) 52 { 53 if (client->local->fd >= 0) 54 { 55 fd_close(client->local->fd); 56 client->local->fd = -2; 57 } 58 } 59 60 list_for_each_entry(client, &unknown_list, lclient_node) 61 { 62 if (client->local->fd >= 0) 63 { 64 fd_close(client->local->fd); 65 client->local->fd = -2; 66 } 67 68 if (client->local->authfd >= 0) 69 { 70 fd_close(client->local->authfd); 71 client->local->fd = -1; 72 } 73 } 74 75 list_for_each_entry(client, &control_list, lclient_node) 76 { 77 if (client->local->fd >= 0) 78 { 79 fd_close(client->local->fd); 80 client->local->fd = -2; 81 } 82 } 83 84 close_unbound_listeners(); 85 86 OpenFiles = 0; 87 88 #ifdef _WIN32 89 WSACleanup(); 90 #endif 91 } 92 93 /** Accept an incoming connection. 94 * @param listener The listen { } block configuration data. 95 * @returns 1 if the connection was accepted (even if it was rejected), 96 * 0 if there is no more work to do (accept returned an error). 97 */ 98 static int listener_accept_wrapper(ConfigItem_listen *listener) 99 { 100 int cli_fd; 101 102 if ((cli_fd = fd_accept(listener->fd)) < 0) 103 { 104 if ((ERRNO != P_EWOULDBLOCK) && (ERRNO != P_ECONNABORTED)) 105 { 106 /* Trouble! accept() returns a strange error. 107 * Previously in such a case we would just log/broadcast the error and return, 108 * causing this message to be triggered at a rate of XYZ per second (100% CPU). 109 * Now we close & re-start the listener. 110 * Of course the underlying cause of this issue should be investigated, as this 111 * is very much a workaround. 112 */ 113 if (listener->file) 114 { 115 unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR", NULL, "Cannot accept incoming connection on file $file: $socket_error", 116 log_data_socket_error(listener->fd), 117 log_data_string("file", listener->file)); 118 } else { 119 unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: $socket_error", 120 log_data_socket_error(listener->fd), 121 log_data_string("listen_ip", listener->ip), 122 log_data_integer("listen_port", listener->port)); 123 } 124 close_listener(listener); 125 start_listeners(); 126 } 127 return 0; 128 } 129 130 ircstats.is_ac++; 131 132 set_sock_opts(cli_fd, NULL, listener->socket_type); 133 134 /* Allow connections to the control socket, even if maxclients is reached */ 135 if (listener->options & LISTENER_CONTROL) 136 { 137 /* ... but not unlimited ;) */ 138 if ((++OpenFiles >= maxclients+(CLIENTS_RESERVE/2)) || (cli_fd >= maxclients+(CLIENTS_RESERVE/2))) 139 { 140 ircstats.is_ref++; 141 if (last_allinuse < TStime() - 15) 142 { 143 unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on file $file: All connections in use", 144 log_data_string("file", listener->file)); 145 last_allinuse = TStime(); 146 } 147 fd_close(cli_fd); 148 --OpenFiles; 149 return 1; 150 } 151 } else 152 { 153 if ((++OpenFiles >= maxclients) || (cli_fd >= maxclients)) 154 { 155 ircstats.is_ref++; 156 if (last_allinuse < TStime() - 15) 157 { 158 if (listener->file) 159 { 160 unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on file $file: All connections in use", 161 log_data_string("file", listener->file)); 162 } else { 163 unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: All connections in use", 164 log_data_string("listen_ip", listener->ip), 165 log_data_integer("listen_port", listener->port)); 166 } 167 last_allinuse = TStime(); 168 } 169 170 (void)send(cli_fd, "ERROR :All connections in use\r\n", 31, 0); 171 172 fd_close(cli_fd); 173 --OpenFiles; 174 return 1; 175 } 176 } 177 178 /* add_connection() may fail. we just don't care. */ 179 add_connection(listener, cli_fd); 180 return 1; 181 } 182 183 /** Accept an incoming connection. 184 * @param listener_fd The file descriptor of a listen() socket. 185 * @param data The listen { } block configuration data. 186 */ 187 static void listener_accept(int listener_fd, int revents, void *data) 188 { 189 int i; 190 191 /* Accept clients, but only up to a maximum in each run, 192 * as to allow some CPU available to existing clients. 193 * Better refuse or lag a few new clients than become 194 * unresponse to existing clients. 195 */ 196 for (i=0; i < 100; i++) 197 if (!listener_accept_wrapper((ConfigItem_listen *)data)) 198 break; 199 } 200 201 int unreal_listen_inet(ConfigItem_listen *listener) 202 { 203 const char *ip = listener->ip; 204 int port = listener->port; 205 206 if (BadPtr(ip)) 207 ip = "*"; 208 209 if (*ip == '*') 210 { 211 if (listener->socket_type == SOCKET_TYPE_IPV6) 212 ip = "::"; 213 else 214 ip = "0.0.0.0"; 215 } 216 217 /* At first, open a new socket */ 218 if (listener->fd >= 0) 219 abort(); /* Socket already exists but we are asked to create and listen on one. Bad! */ 220 221 if (port == 0) 222 abort(); /* Impossible as well, right? */ 223 224 listener->fd = fd_socket(listener->socket_type == SOCKET_TYPE_IPV6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0, "Listener socket"); 225 if (listener->fd < 0) 226 { 227 unreal_log(ULOG_FATAL, "listen", "LISTEN_SOCKET_ERROR", NULL, 228 "Could not listen on IP \"$listen_ip\" on port $listen_port: $socket_error", 229 log_data_socket_error(-1), 230 log_data_string("listen_ip", ip), 231 log_data_integer("listen_port", port)); 232 return -1; 233 } 234 235 if (++OpenFiles >= maxclients) 236 { 237 unreal_log(ULOG_FATAL, "listen", "LISTEN_ERROR_MAXCLIENTS", NULL, 238 "Could not listen on IP \"$listen_ip\" on port $listen_port: all connections in use", 239 log_data_string("listen_ip", ip), 240 log_data_integer("listen_port", port)); 241 fd_close(listener->fd); 242 listener->fd = -1; 243 --OpenFiles; 244 return -1; 245 } 246 247 set_sock_opts(listener->fd, NULL, listener->socket_type); 248 249 if (!unreal_bind(listener->fd, ip, port, listener->socket_type)) 250 { 251 unreal_log(ULOG_FATAL, "listen", "LISTEN_BIND_ERROR", NULL, 252 "Could not listen on IP \"$listen_ip\" on port $listen_port: $socket_error", 253 log_data_socket_error(listener->fd), 254 log_data_string("listen_ip", ip), 255 log_data_integer("listen_port", port)); 256 fd_close(listener->fd); 257 listener->fd = -1; 258 --OpenFiles; 259 return -1; 260 } 261 262 if (listen(listener->fd, LISTEN_SIZE) < 0) 263 { 264 unreal_log(ULOG_FATAL, "listen", "LISTEN_LISTEN_ERROR", NULL, 265 "Could not listen on IP \"$listen_ip\" on port $listen_port: $socket_error", 266 log_data_socket_error(listener->fd), 267 log_data_string("listen_ip", ip), 268 log_data_integer("listen_port", port)); 269 fd_close(listener->fd); 270 listener->fd = -1; 271 --OpenFiles; 272 return -1; 273 } 274 275 #ifdef TCP_DEFER_ACCEPT 276 if (listener->options & LISTENER_DEFER_ACCEPT) 277 { 278 int yes = 1; 279 280 (void)setsockopt(listener->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &yes, sizeof(int)); 281 } 282 #endif 283 284 #ifdef SO_ACCEPTFILTER 285 if (listener->options & LISTENER_DEFER_ACCEPT) 286 { 287 struct accept_filter_arg afa; 288 289 memset(&afa, '\0', sizeof afa); 290 strlcpy(afa.af_name, "dataready", sizeof afa.af_name); 291 (void)setsockopt(listener->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof afa); 292 } 293 #endif 294 295 fd_setselect(listener->fd, FD_SELECT_READ, listener_accept, listener); 296 297 return 0; 298 } 299 300 int unreal_listen_unix(ConfigItem_listen *listener) 301 { 302 if (listener->socket_type != SOCKET_TYPE_UNIX) 303 abort(); /* "impossible" */ 304 305 /* At first, open a new socket */ 306 if (listener->fd >= 0) 307 abort(); /* Socket already exists but we are asked to create and listen on one. Bad! */ 308 309 listener->fd = fd_socket(AF_UNIX, SOCK_STREAM, 0, "Listener socket (UNIX)"); 310 if (listener->fd < 0) 311 { 312 unreal_log(ULOG_FATAL, "listen", "LISTEN_SOCKET_ERROR", NULL, 313 "Could not create UNIX domain socket for $file: $socket_error", 314 log_data_socket_error(-1), 315 log_data_string("file", listener->file)); 316 return -1; 317 } 318 319 if (++OpenFiles >= maxclients) 320 { 321 unreal_log(ULOG_FATAL, "listen", "LISTEN_ERROR_MAXCLIENTS", NULL, 322 "Could not create UNIX domain socket for $file: all connections in use", 323 log_data_string("file", listener->file)); 324 fd_close(listener->fd); 325 listener->fd = -1; 326 --OpenFiles; 327 return -1; 328 } 329 330 set_sock_opts(listener->fd, NULL, listener->socket_type); 331 332 if (!unreal_bind(listener->fd, listener->file, listener->mode, SOCKET_TYPE_UNIX)) 333 { 334 unreal_log(ULOG_FATAL, "listen", "LISTEN_BIND_ERROR", NULL, 335 "Could not listen on UNIX domain socket $file: $socket_error", 336 log_data_socket_error(listener->fd), 337 log_data_string("file", listener->file)); 338 fd_close(listener->fd); 339 listener->fd = -1; 340 --OpenFiles; 341 return -1; 342 } 343 344 if (listen(listener->fd, LISTEN_SIZE) < 0) 345 { 346 unreal_log(ULOG_FATAL, "listen", "LISTEN_LISTEN_ERROR", NULL, 347 "Could not listen on UNIX domain socket $file: $socket_error", 348 log_data_socket_error(listener->fd), 349 log_data_string("file", listener->file)); 350 fd_close(listener->fd); 351 listener->fd = -1; 352 --OpenFiles; 353 return -1; 354 } 355 356 fd_setselect(listener->fd, FD_SELECT_READ, listener_accept, listener); 357 358 return 0; 359 } 360 361 /** Create a listener port. 362 * @param listener The listen { } block configuration 363 * @returns 0 on success and <0 on error. Yeah, confusing. 364 */ 365 int unreal_listen(ConfigItem_listen *listener) 366 { 367 if ((listener->socket_type == SOCKET_TYPE_IPV4) || (listener->socket_type == SOCKET_TYPE_IPV6)) 368 return unreal_listen_inet(listener); 369 return unreal_listen_unix(listener); 370 } 371 372 /** Activate a listen { } block */ 373 int add_listener(ConfigItem_listen *listener) 374 { 375 if (unreal_listen(listener)) 376 { 377 /* Error is already handled upstream */ 378 listener->fd = -2; 379 } 380 381 if (listener->fd >= 0) 382 { 383 listener->options |= LISTENER_BOUND; 384 return 1; 385 } 386 else 387 { 388 listener->fd = -1; 389 return -1; 390 } 391 } 392 393 /** Close the listener socket, but do not free it (yet). 394 * This will only close the socket so no new clients are accepted. 395 * It also marks the listener as no longer "bound". 396 * Once the last client exits the listener will actually be freed. 397 * @param listener The listen { } block. 398 */ 399 void close_listener(ConfigItem_listen *listener) 400 { 401 if (listener->fd >= 0) 402 { 403 unreal_log(ULOG_INFO, "listen", "LISTEN_REMOVED", NULL, 404 "UnrealIRCd is now no longer listening on $listen_ip:$listen_port", 405 log_data_string("listen_ip", listener->ip), 406 log_data_integer("listen_port", listener->port)); 407 fd_close(listener->fd); 408 --OpenFiles; 409 } 410 411 listener->options &= ~LISTENER_BOUND; 412 listener->fd = -1; 413 /* We can already free the TLS context, since it is only 414 * used for new connections, which we no longer accept. 415 */ 416 if (listener->ssl_ctx) 417 { 418 SSL_CTX_free(listener->ssl_ctx); 419 listener->ssl_ctx = NULL; 420 } 421 } 422 423 /** Close all listeners that were pending to be closed. */ 424 void close_unbound_listeners(void) 425 { 426 ConfigItem_listen *aconf, *aconf_next; 427 428 /* close all 'extra' listening ports we have */ 429 for (aconf = conf_listen; aconf != NULL; aconf = aconf_next) 430 { 431 aconf_next = aconf->next; 432 if (aconf->flag.temporary) 433 close_listener(aconf); 434 } 435 } 436 437 int maxclients = 1024 - CLIENTS_RESERVE; 438 439 /** Check the maximum number of sockets (users) that we can handle - called on startup. 440 */ 441 void check_user_limit(void) 442 { 443 #ifdef RLIMIT_FD_MAX 444 struct rlimit limit; 445 long m; 446 447 if (!getrlimit(RLIMIT_FD_MAX, &limit)) 448 { 449 if (limit.rlim_max < MAXCONNECTIONS) 450 m = limit.rlim_max; 451 else 452 m = MAXCONNECTIONS; 453 454 /* Adjust soft limit (if necessary, which is often the case) */ 455 if (m != limit.rlim_cur) 456 { 457 limit.rlim_cur = limit.rlim_max = m; 458 if (setrlimit(RLIMIT_FD_MAX, &limit) == -1) 459 { 460 /* HACK: if it's mac os X then don't error... */ 461 #ifndef OSXTIGER 462 fprintf(stderr, "error setting maximum number of open files to %ld\n", 463 (long)limit.rlim_cur); 464 exit(-1); 465 #endif // OSXTIGER 466 } 467 } 468 /* This can only happen if it is due to resource limits (./Config already rejects <100) */ 469 if (m < 100) 470 { 471 fprintf(stderr, "\nERROR: Your OS has a limit placed on this account.\n" 472 "This machine only allows UnrealIRCd to handle a maximum of %ld open connections/files, which is VERY LOW.\n" 473 "Please check with your system administrator to bump this limit.\n" 474 "The recommended ulimit -n setting is at least 1024 and " 475 "preferably 4096.\n" 476 "Note that this error is often seen on small web shells that are not meant for running IRC servers.\n", 477 m); 478 exit(-1); 479 } 480 maxclients = m - CLIENTS_RESERVE; 481 } 482 #endif // RLIMIT_FD_MAX 483 484 #ifndef _WIN32 485 #ifdef BACKEND_SELECT 486 if (MAXCONNECTIONS > FD_SETSIZE) 487 { 488 fprintf(stderr, "MAXCONNECTIONS (%d) is higher than FD_SETSIZE (%d)\n", MAXCONNECTIONS, FD_SETSIZE); 489 fprintf(stderr, "You should not see this error on Linux or FreeBSD\n"); 490 fprintf(stderr, "You might need to recompile the IRCd and answer a lower value to the MAXCONNECTIONS question in ./Config\n"); 491 exit(-1); 492 } 493 #endif 494 #endif 495 #ifdef _WIN32 496 maxclients = MAXCONNECTIONS - CLIENTS_RESERVE; 497 #endif 498 } 499 500 /** Initialize some systems - called on startup */ 501 void init_sys(void) 502 { 503 #ifndef _WIN32 504 /* Create new session / set process group */ 505 (void)setsid(); 506 #endif 507 508 init_resolver(1); 509 return; 510 } 511 512 /** Replace a file descriptor (*NIX only). 513 * See close_std_descriptors() as for why. 514 * @param oldfd: the old FD to close and re-use 515 * @param name: descriptive string of the old fd, eg: "stdin". 516 * @param mode: an open() mode, such as O_WRONLY. 517 */ 518 void replacefd(int oldfd, char *name, int mode) 519 { 520 #ifndef _WIN32 521 int newfd = open("/dev/null", mode); 522 if (newfd < 0) 523 { 524 fprintf(stderr, "Warning: could not open /dev/null\n"); 525 return; 526 } 527 if (oldfd < 0) 528 { 529 fprintf(stderr, "Warning: could not replace %s (invalid fd)\n", name); 530 return; 531 } 532 if (dup2(newfd, oldfd) < 0) 533 { 534 fprintf(stderr, "Warning: could not replace %s (dup2 error)\n", name); 535 return; 536 } 537 #endif 538 } 539 540 /** Mass close standard file descriptors (stdin, stdout, stderr). 541 * We used to really just close them here (or in init_sys() actually), 542 * making the fd's available for other purposes such as internet sockets. 543 * For safety we now dup2() them to /dev/null. This in case someone 544 * accidentally does a fprintf(stderr,..) somewhere in the code or some 545 * library outputs error messages to stderr (such as libc with heap 546 * errors). We don't want any IRC client to receive such a thing! 547 */ 548 void close_std_descriptors(void) 549 { 550 #if !defined(_WIN32) && !defined(NOCLOSEFD) 551 replacefd(fileno(stdin), "stdin", O_RDONLY); 552 replacefd(fileno(stdout), "stdout", O_WRONLY); 553 replacefd(fileno(stderr), "stderr", O_WRONLY); 554 #endif 555 } 556 557 /** Do an ident lookup if necessary. 558 * @param client The incoming client 559 */ 560 void consider_ident_lookup(Client *client) 561 { 562 char buf[BUFSIZE]; 563 564 /* If ident checking is disabled or it's an outgoing connect, then no ident check */ 565 if ((IDENT_CHECK == 0) || (client->server && IsHandshake(client)) || IsUnixSocket(client)) 566 { 567 ClearIdentLookupSent(client); 568 ClearIdentLookup(client); 569 return; 570 } 571 RunHook(HOOKTYPE_IDENT_LOOKUP, client); 572 573 return; 574 } 575 576 577 /** Called when TCP/IP connection is established (outgoing server connect) */ 578 void completed_connection(int fd, int revents, void *data) 579 { 580 Client *client = data; 581 ConfigItem_link *aconf = client->server ? client->server->conf : NULL; 582 583 if (IsHandshake(client)) 584 { 585 /* Due to delayed unreal_tls_connect call */ 586 start_server_handshake(client); 587 fd_setselect(fd, FD_SELECT_READ, read_packet, client); 588 return; 589 } 590 591 SetHandshake(client); 592 593 if (!aconf) 594 { 595 unreal_log(ULOG_ERROR, "link", "BUG_LOST_CONFIGURATION_ON_CONNECT", client, 596 "Lost configuration while connecting to $client.details"); 597 return; 598 } 599 600 if (!client->local->ssl && !(aconf->outgoing.options & CONNECT_INSECURE)) 601 { 602 sendto_one(client, NULL, "STARTTLS"); 603 } else 604 { 605 start_server_handshake(client); 606 } 607 608 if (!IsDeadSocket(client)) 609 consider_ident_lookup(client); 610 611 fd_setselect(fd, FD_SELECT_READ, read_packet, client); 612 } 613 614 /** Close the physical connection. 615 * @param client The client connection to close (LOCAL!) 616 */ 617 void close_connection(Client *client) 618 { 619 RunHook(HOOKTYPE_CLOSE_CONNECTION, client); 620 /* This function must make MyConnect(client) == FALSE, 621 * and set client->direction == NULL. 622 */ 623 if (IsServer(client)) 624 { 625 ircstats.is_sv++; 626 ircstats.is_sti += TStime() - client->local->creationtime; 627 } 628 else if (IsUser(client)) 629 { 630 ircstats.is_cl++; 631 ircstats.is_cti += TStime() - client->local->creationtime; 632 } 633 else 634 ircstats.is_ni++; 635 636 /* 637 * remove outstanding DNS queries. 638 */ 639 unrealdns_delreq_bycptr(client); 640 641 if (client->local->authfd >= 0) 642 { 643 fd_close(client->local->authfd); 644 client->local->authfd = -1; 645 --OpenFiles; 646 } 647 648 if (client->local->fd >= 0) 649 { 650 send_queued(client); 651 if (IsTLS(client) && client->local->ssl) { 652 SSL_set_shutdown(client->local->ssl, SSL_RECEIVED_SHUTDOWN); 653 SSL_smart_shutdown(client->local->ssl); 654 SSL_free(client->local->ssl); 655 client->local->ssl = NULL; 656 } 657 fd_close(client->local->fd); 658 client->local->fd = -2; 659 --OpenFiles; 660 DBufClear(&client->local->sendQ); 661 DBufClear(&client->local->recvQ); 662 } 663 664 client->direction = NULL; 665 } 666 667 /** Set IPv6 socket options, if possible. */ 668 void set_ipv6_opts(int fd) 669 { 670 #if defined(IPV6_V6ONLY) 671 int opt = 1; 672 (void)setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&opt, sizeof(opt)); 673 #endif 674 } 675 676 /** This sets the *OS* socket buffers. 677 * This shouldn't be needed anymore, but I've left the function here. 678 */ 679 void set_socket_buffers(int fd, int rcvbuf, int sndbuf) 680 { 681 int opt; 682 683 opt = rcvbuf; 684 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&opt, sizeof(opt)); 685 686 opt = sndbuf; 687 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&opt, sizeof(opt)); 688 } 689 690 /** Set the appropriate socket options */ 691 void set_sock_opts(int fd, Client *client, SocketType socket_type) 692 { 693 int opt; 694 695 if (socket_type == SOCKET_TYPE_IPV6) 696 set_ipv6_opts(fd); 697 698 if ((socket_type == SOCKET_TYPE_IPV4) || (socket_type == SOCKET_TYPE_IPV6)) 699 { 700 #ifdef SO_REUSEADDR 701 opt = 1; 702 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0) 703 { 704 unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client, 705 "Could not setsockopt(SO_REUSEADDR): $socket_error", 706 log_data_socket_error(-1)); 707 } 708 #endif 709 710 #if defined(SO_USELOOPBACK) && !defined(_WIN32) 711 opt = 1; 712 if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, (void *)&opt, sizeof(opt)) < 0) 713 { 714 unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client, 715 "Could not setsockopt(SO_USELOOPBACK): $socket_error", 716 log_data_socket_error(-1)); 717 } 718 #endif 719 720 } 721 722 /* The following code applies to all socket types: IPv4, IPv6, UNIX domain sockets */ 723 724 /* Set to non blocking: */ 725 #if !defined(_WIN32) 726 if ((opt = fcntl(fd, F_GETFL, 0)) == -1) 727 { 728 if (client) 729 { 730 unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client, 731 "Could not get socket options (F_GETFL): $socket_error", 732 log_data_socket_error(-1)); 733 } 734 } 735 else if (fcntl(fd, F_SETFL, opt | O_NONBLOCK) == -1) 736 { 737 if (client) 738 { 739 unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client, 740 "Could not get socket options (F_SETFL): $socket_error", 741 log_data_socket_error(-1)); 742 } 743 } 744 #else 745 opt = 1; 746 if (ioctlsocket(fd, FIONBIO, &opt) < 0) 747 { 748 if (client) 749 { 750 unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client, 751 "Could not ioctlsocket FIONBIO: $socket_error", 752 log_data_socket_error(-1)); 753 } 754 } 755 #endif 756 } 757 758 /** Returns 1 if using a loopback IP (127.0.0.1) or 759 * using a local IP number on the same machine (effectively the same; 760 * no network traffic travels outside this machine). 761 * @param ip The IP address to check 762 * @returns 1 if loopback, 0 if not. 763 */ 764 int is_loopback_ip(char *ip) 765 { 766 ConfigItem_listen *e; 767 768 if (!strcmp(ip, "127.0.0.1") || !strcmp(ip, "0:0:0:0:0:0:0:1") || !strcmp(ip, "0:0:0:0:0:ffff:127.0.0.1")) 769 return 1; 770 771 for (e = conf_listen; e; e = e->next) 772 { 773 if ((e->options & LISTENER_BOUND) && e->ip && !strcmp(ip, e->ip)) 774 return 1; 775 } 776 return 0; 777 } 778 779 /** Retrieve the remote IP address and port of a socket. 780 * @param client Client to check 781 * @param fd File descriptor 782 * @param port Remote port (will be written) 783 * @returns The IP address 784 */ 785 const char *getpeerip(Client *client, int fd, int *port) 786 { 787 static char ret[HOSTLEN+1]; 788 789 if (IsIPV6(client)) 790 { 791 struct sockaddr_in6 addr; 792 int len = sizeof(addr); 793 794 if (getpeername(fd, (struct sockaddr *)&addr, &len) < 0) 795 return NULL; 796 *port = ntohs(addr.sin6_port); 797 return inetntop(AF_INET6, &addr.sin6_addr.s6_addr, ret, sizeof(ret)); 798 } else 799 { 800 struct sockaddr_in addr; 801 int len = sizeof(addr); 802 803 if (getpeername(fd, (struct sockaddr *)&addr, &len) < 0) 804 return NULL; 805 *port = ntohs(addr.sin_port); 806 return inetntop(AF_INET, &addr.sin_addr.s_addr, ret, sizeof(ret)); 807 } 808 } 809 810 /** Process the incoming connection which has just been accepted. 811 * This creates a client structure for the user. 812 * The sockhost field is initialized with the ip# of the host. 813 * The client is added to the linked list of clients but isnt added to any 814 * hash tables yuet since it doesnt have a name. 815 * @param listener The listen { } block on which the client was accepted. 816 * @param fd The file descriptor of the client 817 * @returns The new client, or NULL in case of trouble. 818 * @note When NULL is returned, the client at socket 'fd' will be 819 * closed by this function and OpenFiles is adjusted appropriately. 820 */ 821 Client *add_connection(ConfigItem_listen *listener, int fd) 822 { 823 Client *client; 824 const char *ip; 825 int port = 0; 826 Hook *h; 827 828 client = make_client(NULL, &me); 829 client->local->socket_type = listener->socket_type; 830 client->local->listener = listener; 831 client->local->listener->clients++; 832 833 if (listener->socket_type == SOCKET_TYPE_UNIX) 834 ip = listener->spoof_ip ? listener->spoof_ip : "127.0.0.1"; 835 else 836 ip = getpeerip(client, fd, &port); 837 838 if (!ip) 839 { 840 /* On Linux 2.4 and FreeBSD the socket may just have been disconnected 841 * so it's not a serious error and can happen quite frequently -- Syzop 842 */ 843 if (ERRNO != P_ENOTCONN) 844 { 845 unreal_log(ULOG_ERROR, "listen", "ACCEPT_ERROR", NULL, 846 "Failed to accept new client: unable to get IP address: $socket_error", 847 log_data_socket_error(fd), 848 log_data_string("listen_ip", listener->ip), 849 log_data_integer("listen_port", listener->port)); 850 } 851 refuse_client: 852 ircstats.is_ref++; 853 client->local->fd = -2; 854 if (!list_empty(&client->client_node)) 855 list_del(&client->client_node); 856 if (!list_empty(&client->lclient_node)) 857 list_del(&client->lclient_node); 858 free_client(client); 859 fd_close(fd); 860 --OpenFiles; 861 return NULL; 862 } 863 864 /* Fill in sockhost & ip ASAP */ 865 set_sockhost(client, ip); 866 safe_strdup(client->ip, ip); 867 client->local->port = port; 868 client->local->fd = fd; 869 870 /* Tag loopback connections */ 871 if (is_loopback_ip(client->ip)) 872 { 873 ircstats.is_loc++; 874 SetLocalhost(client); 875 } 876 877 add_client_to_list(client); 878 irccounts.unknown++; 879 client->status = CLIENT_STATUS_UNKNOWN; 880 list_add(&client->lclient_node, &unknown_list); 881 882 for (h = Hooks[HOOKTYPE_ACCEPT]; h; h = h->next) 883 { 884 int value = (*(h->func.intfunc))(client); 885 if (value == HOOK_DENY) 886 { 887 irccounts.unknown--; 888 goto refuse_client; 889 } 890 if (value != HOOK_CONTINUE) 891 break; 892 } 893 894 if ((listener->options & LISTENER_TLS) && ctx_server) 895 { 896 SSL_CTX *ctx = listener->ssl_ctx ? listener->ssl_ctx : ctx_server; 897 898 if (ctx) 899 { 900 SetTLSAcceptHandshake(client); 901 if ((client->local->ssl = SSL_new(ctx)) == NULL) 902 { 903 irccounts.unknown--; 904 goto refuse_client; 905 } 906 SetTLS(client); 907 SSL_set_fd(client->local->ssl, fd); 908 SSL_set_nonblocking(client->local->ssl); 909 SSL_set_ex_data(client->local->ssl, tls_client_index, client); 910 if (!unreal_tls_accept(client, fd)) 911 { 912 SSL_set_shutdown(client->local->ssl, SSL_RECEIVED_SHUTDOWN); 913 SSL_smart_shutdown(client->local->ssl); 914 SSL_free(client->local->ssl); 915 irccounts.unknown--; 916 goto refuse_client; 917 } 918 } 919 } else 920 { 921 listener->start_handshake(client); 922 } 923 return client; 924 } 925 926 /** Start of normal client handshake - DNS and ident lookups, etc. 927 * @param client The client 928 * @note This is called directly after accept() -> add_connection() for plaintext. 929 * For TLS connections this is called after the TLS handshake is completed. 930 */ 931 void start_of_normal_client_handshake(Client *client) 932 { 933 struct hostent *he; 934 935 client->status = CLIENT_STATUS_UNKNOWN; /* reset, to be sure (TLS handshake has ended) */ 936 937 RunHook(HOOKTYPE_HANDSHAKE, client); 938 939 if (!DONT_RESOLVE && !IsUnixSocket(client)) 940 { 941 if (should_show_connect_info(client)) 942 sendto_one(client, NULL, ":%s %s", me.name, REPORT_DO_DNS); 943 he = unrealdns_doclient(client); 944 945 if (client->local->hostp) 946 goto doauth; /* Race condition detected, DNS has been done, continue with auth */ 947 948 if (!he) 949 { 950 /* Resolving in progress */ 951 SetDNSLookup(client); 952 } else { 953 /* Host was in our cache */ 954 client->local->hostp = he; 955 if (should_show_connect_info(client)) 956 sendto_one(client, NULL, ":%s %s", me.name, REPORT_FIN_DNSC); 957 } 958 } 959 960 doauth: 961 consider_ident_lookup(client); 962 fd_setselect(client->local->fd, FD_SELECT_READ, read_packet, client); 963 } 964 965 /** Called when DNS lookup has been completed and we can proceed with the client handshake. 966 * @param client The client 967 * @param he The resolved or unresolved host 968 */ 969 void proceed_normal_client_handshake(Client *client, struct hostent *he) 970 { 971 ClearDNSLookup(client); 972 client->local->hostp = he; 973 if (should_show_connect_info(client)) 974 { 975 sendto_one(client, NULL, ":%s %s", 976 me.name, 977 client->local->hostp ? REPORT_FIN_DNS : REPORT_FAIL_DNS); 978 } 979 } 980 981 /** Read a packet from a client. 982 * @param fd File descriptor 983 * @param revents Read events (ignored) 984 * @param data Associated data (the client) 985 */ 986 void read_packet(int fd, int revents, void *data) 987 { 988 Client *client = data; 989 int length = 0; 990 time_t now = TStime(); 991 Hook *h; 992 int processdata; 993 994 /* Don't read from dead sockets */ 995 if (IsDeadSocket(client)) 996 { 997 fd_setselect(fd, FD_SELECT_READ, NULL, client); 998 return; 999 } 1000 1001 SET_ERRNO(0); 1002 1003 fd_setselect(fd, FD_SELECT_READ, read_packet, client); 1004 /* Restore handling of writes towards send_queued_cb(), since 1005 * it may be overwritten in an earlier call to read_packet(), 1006 * to handle (TLS) writes by read_packet(), see below under 1007 * SSL_ERROR_WANT_WRITE. 1008 */ 1009 fd_setselect(fd, FD_SELECT_WRITE, send_queued_cb, client); 1010 1011 while (1) 1012 { 1013 if (IsTLS(client) && client->local->ssl != NULL) 1014 { 1015 length = SSL_read(client->local->ssl, readbuf, sizeof(readbuf)); 1016 1017 if (length < 0) 1018 { 1019 int err = SSL_get_error(client->local->ssl, length); 1020 1021 switch (err) 1022 { 1023 case SSL_ERROR_WANT_WRITE: 1024 fd_setselect(fd, FD_SELECT_READ, NULL, client); 1025 fd_setselect(fd, FD_SELECT_WRITE, read_packet, client); 1026 length = -1; 1027 SET_ERRNO(P_EWOULDBLOCK); 1028 break; 1029 case SSL_ERROR_WANT_READ: 1030 fd_setselect(fd, FD_SELECT_READ, read_packet, client); 1031 length = -1; 1032 SET_ERRNO(P_EWOULDBLOCK); 1033 break; 1034 case SSL_ERROR_SYSCALL: 1035 break; 1036 case SSL_ERROR_SSL: 1037 if (ERRNO == P_EAGAIN) 1038 break; 1039 default: 1040 /*length = 0; 1041 SET_ERRNO(0); 1042 ^^ why this? we should error. -- todo: is errno correct? 1043 */ 1044 break; 1045 } 1046 } 1047 } 1048 else 1049 length = recv(client->local->fd, readbuf, sizeof(readbuf), 0); 1050 1051 if (length <= 0) 1052 { 1053 if (length < 0 && ((ERRNO == P_EWOULDBLOCK) || (ERRNO == P_EAGAIN) || (ERRNO == P_EINTR))) 1054 return; 1055 1056 if (IsServer(client) || client->server) /* server or outgoing connection */ 1057 lost_server_link(client, NULL); 1058 1059 exit_client(client, NULL, ERRNO ? "Read error" : "Connection closed"); 1060 return; 1061 } 1062 1063 client->local->last_msg_received = now; 1064 if (client->local->last_msg_received > client->local->fake_lag) 1065 client->local->fake_lag = client->local->last_msg_received; 1066 /* FIXME: Is this correct? I have my doubts. */ 1067 ClearPingSent(client); 1068 1069 ClearPingWarning(client); 1070 1071 processdata = 1; 1072 for (h = Hooks[HOOKTYPE_RAWPACKET_IN]; h; h = h->next) 1073 { 1074 processdata = (*(h->func.intfunc))(client, readbuf, &length); 1075 if (processdata == 0) 1076 break; /* if hook tells to ignore the data, then break now */ 1077 if (processdata < 0) 1078 return; /* if hook tells client is dead, return now */ 1079 } 1080 1081 if (processdata && !process_packet(client, readbuf, length, 0)) 1082 return; 1083 1084 /* bail on short read! */ 1085 if (length < sizeof(readbuf)) 1086 return; 1087 } 1088 } 1089 1090 /** Process input from clients that may have been deliberately delayed due to fake lag */ 1091 void process_clients(void) 1092 { 1093 Client *client; 1094 1095 /* Problem: 1096 * When processing a client, that current client may exit due to eg QUIT. 1097 * Similarly, current->next may be killed due to /KILL. 1098 * When a client is killed, in the past we were not allowed to touch it anymore 1099 * so that was a bit problematic. Now we can touch current->next, but it may 1100 * have been removed from the lclient_list or unknown_list. 1101 * In other words, current->next->next may be NULL even though there are more 1102 * clients on the list. 1103 * This is why the whole thing is wrapped in an additional do { } while() loop 1104 * to make sure we re-run the list if we ended prematurely. 1105 * We could use some kind of 'tagging' to mark already processed clients. 1106 * However, parse_client_queued() already takes care not to read (fake) lagged 1107 * clients, and we don't actually read/recv anything in the meantime, so clients 1108 * in the beginning of the list won't benefit, they won't get higher prio. 1109 * Another alternative is not to run the loop again, but that WOULD be 1110 * unfair to clients later in the list which wouldn't be processed then 1111 * under a heavy (kill) load scenario. 1112 * I think the chosen solution is best, though it remains silly. -- Syzop 1113 */ 1114 1115 do { 1116 list_for_each_entry(client, &lclient_list, lclient_node) 1117 { 1118 if ((client->local->fd >= 0) && DBufLength(&client->local->recvQ) && !IsDead(client)) 1119 { 1120 parse_client_queued(client); 1121 if (IsDead(client)) 1122 break; 1123 } 1124 } 1125 } while(&client->lclient_node != &lclient_list); 1126 1127 do { 1128 list_for_each_entry(client, &unknown_list, lclient_node) 1129 { 1130 if ((client->local->fd >= 0) && DBufLength(&client->local->recvQ) && !IsDead(client)) 1131 { 1132 parse_client_queued(client); 1133 if (IsDead(client) || (client->status > CLIENT_STATUS_UNKNOWN)) 1134 break; 1135 } 1136 } 1137 } while(&client->lclient_node != &unknown_list); 1138 1139 do { 1140 list_for_each_entry(client, &control_list, lclient_node) 1141 { 1142 if ((client->local->fd >= 0) && DBufLength(&client->local->recvQ) && !IsDead(client)) 1143 { 1144 parse_client_queued(client); 1145 if (IsDead(client)) 1146 break; 1147 } 1148 } 1149 } while(&client->lclient_node != &control_list); 1150 1151 1152 } 1153 1154 /** Check if 'ip' is a valid IP address, and if so what type. 1155 * @param ip The IP address 1156 * @retval 4 Valid IPv4 address 1157 * @retval 6 Valid IPv6 address 1158 * @retval 0 Invalid IP address (eg: a hostname) 1159 */ 1160 int is_valid_ip(const char *ip) 1161 { 1162 char scratch[64]; 1163 1164 if (BadPtr(ip)) 1165 return 0; 1166 1167 if (inet_pton(AF_INET, ip, scratch) == 1) 1168 return 4; /* IPv4 */ 1169 1170 if (inet_pton(AF_INET6, ip, scratch) == 1) 1171 return 6; /* IPv6 */ 1172 1173 return 0; /* not an IP address */ 1174 } 1175 1176 /** Checks if the system is IPv6 capable. 1177 * IPv6 is always available at compile time (libs, headers), but the OS may 1178 * not have IPv6 enabled (or ipv6 kernel module not loaded). So we better check.. 1179 */ 1180 int ipv6_capable(void) 1181 { 1182 int s = socket(AF_INET6, SOCK_STREAM, 0); 1183 if (s < 0) 1184 return 0; /* NO ipv6 */ 1185 1186 CLOSE_SOCK(s); 1187 return 1; /* YES */ 1188 } 1189 1190 /** Return 1 if UNIX sockets of type SOCK_STREAM are supported, and 0 otherwise */ 1191 int unix_sockets_capable(void) 1192 { 1193 int fd = fd_socket(AF_UNIX, SOCK_STREAM, 0, "Testing UNIX socket"); 1194 if (fd < 0) 1195 return 0; 1196 fd_close(fd); 1197 return 1; 1198 } 1199 1200 /** Attempt to deliver data to a client. 1201 * This function is only called from send_queued() and will deal 1202 * with sending to the TLS or plaintext connection. 1203 * @param cptr The client 1204 * @param str The string to send 1205 * @param len The length of the string 1206 * @param want_read In case of TLS it may happen that SSL_write() 1207 * needs to READ data. If this happens then this 1208 * function will set *want_read to 1. 1209 * The upper layer should then call us again when 1210 * there is data ready to be READ. 1211 * @retval <0 Some fatal error occurred, (but not EWOULDBLOCK). 1212 * This return is a request to close the socket and 1213 * clean up the link. 1214 * @retval >=0 No real error occurred, returns the number of 1215 * bytes actually transferred. EWOULDBLOCK and other 1216 * possibly similar conditions should be mapped to 1217 * zero return. Upper level routine will have to 1218 * decide what to do with those unwritten bytes... 1219 */ 1220 int deliver_it(Client *client, char *str, int len, int *want_read) 1221 { 1222 int retval; 1223 1224 *want_read = 0; 1225 1226 if (IsDeadSocket(client) || 1227 (!IsServer(client) && !IsUser(client) && !IsHandshake(client) && 1228 !IsTLSHandshake(client) && !IsUnknown(client) && 1229 !IsControl(client) && !IsRPC(client))) 1230 { 1231 return -1; 1232 } 1233 1234 if (IsTLS(client) && client->local->ssl != NULL) 1235 { 1236 retval = SSL_write(client->local->ssl, str, len); 1237 1238 if (retval < 0) 1239 { 1240 switch (SSL_get_error(client->local->ssl, retval)) 1241 { 1242 case SSL_ERROR_WANT_READ: 1243 SET_ERRNO(P_EWOULDBLOCK); 1244 *want_read = 1; 1245 return 0; 1246 case SSL_ERROR_WANT_WRITE: 1247 SET_ERRNO(P_EWOULDBLOCK); 1248 break; 1249 case SSL_ERROR_SYSCALL: 1250 break; 1251 case SSL_ERROR_SSL: 1252 if (ERRNO == P_EAGAIN) 1253 break; 1254 /* FALLTHROUGH */ 1255 default: 1256 return -1; /* hm.. why was this 0?? we have an error! */ 1257 } 1258 } 1259 } 1260 else 1261 retval = send(client->local->fd, str, len, 0); 1262 /* 1263 ** Convert WOULDBLOCK to a return of "0 bytes moved". This 1264 ** should occur only if socket was non-blocking. Note, that 1265 ** all is Ok, if the 'write' just returns '0' instead of an 1266 ** error and errno=EWOULDBLOCK. 1267 ** 1268 ** ...now, would this work on VMS too? --msa 1269 */ 1270 # ifndef _WIN32 1271 if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || 1272 errno == ENOBUFS)) 1273 # else 1274 if (retval < 0 && (WSAGetLastError() == WSAEWOULDBLOCK || 1275 WSAGetLastError() == WSAENOBUFS)) 1276 # endif 1277 retval = 0; 1278 1279 if (retval > 0) 1280 { 1281 client->local->traffic.bytes_sent += retval; 1282 me.local->traffic.bytes_sent += retval; 1283 } 1284 1285 return (retval); 1286 } 1287 1288 /** Initiate an outgoing connection, the actual connect() call. */ 1289 int unreal_connect(int fd, const char *ip, int port, SocketType socket_type) 1290 { 1291 int n; 1292 1293 if (socket_type == SOCKET_TYPE_IPV6) 1294 { 1295 struct sockaddr_in6 server; 1296 memset(&server, 0, sizeof(server)); 1297 server.sin6_family = AF_INET6; 1298 inet_pton(AF_INET6, ip, &server.sin6_addr); 1299 server.sin6_port = htons(port); 1300 n = connect(fd, (struct sockaddr *)&server, sizeof(server)); 1301 } 1302 else if (socket_type == SOCKET_TYPE_IPV4) 1303 { 1304 struct sockaddr_in server; 1305 memset(&server, 0, sizeof(server)); 1306 server.sin_family = AF_INET; 1307 inet_pton(AF_INET, ip, &server.sin_addr); 1308 server.sin_port = htons(port); 1309 n = connect(fd, (struct sockaddr *)&server, sizeof(server)); 1310 } else 1311 { 1312 struct sockaddr_un server; 1313 memset(&server, 0, sizeof(server)); 1314 server.sun_family = AF_UNIX; 1315 strlcpy(server.sun_path, ip, sizeof(server.sun_path)); 1316 n = connect(fd, (struct sockaddr *)&server, sizeof(server)); 1317 } 1318 1319 #ifndef _WIN32 1320 if (n < 0 && (errno != EINPROGRESS)) 1321 #else 1322 if (n < 0 && (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK)) 1323 #endif 1324 { 1325 return 0; /* FATAL ERROR */ 1326 } 1327 1328 return 1; /* SUCCESS (probably still in progress) */ 1329 } 1330 1331 /** Bind to an IP/port (port may be 0 for auto). 1332 * @returns 0 on failure, other on success. 1333 */ 1334 int unreal_bind(int fd, const char *ip, int port, SocketType socket_type) 1335 { 1336 if (socket_type == SOCKET_TYPE_IPV4) 1337 { 1338 struct sockaddr_in server; 1339 memset(&server, 0, sizeof(server)); 1340 server.sin_family = AF_INET; 1341 server.sin_port = htons(port); 1342 if (inet_pton(AF_INET, ip, &server.sin_addr.s_addr) != 1) 1343 return 0; 1344 return !bind(fd, (struct sockaddr *)&server, sizeof(server)); 1345 } 1346 else if (socket_type == SOCKET_TYPE_IPV6) 1347 { 1348 struct sockaddr_in6 server; 1349 memset(&server, 0, sizeof(server)); 1350 server.sin6_family = AF_INET6; 1351 server.sin6_port = htons(port); 1352 if (inet_pton(AF_INET6, ip, &server.sin6_addr.s6_addr) != 1) 1353 return 0; 1354 return !bind(fd, (struct sockaddr *)&server, sizeof(server)); 1355 } else 1356 { 1357 struct sockaddr_un server; 1358 mode_t saved_umask, new_umask; 1359 int ret; 1360 1361 if (port == 0) 1362 new_umask = 077; 1363 else 1364 new_umask = port ^ 0777; 1365 1366 unlink(ip); /* (ignore errors) */ 1367 1368 memset(&server, 0, sizeof(server)); 1369 server.sun_family = AF_UNIX; 1370 strlcpy(server.sun_path, ip, sizeof(server.sun_path)); 1371 saved_umask = umask(new_umask); 1372 ret = !bind(fd, (struct sockaddr *)&server, sizeof(server)); 1373 umask(saved_umask); 1374 1375 return ret; 1376 } 1377 } 1378 1379 #ifdef _WIN32 1380 void init_winsock(void) 1381 { 1382 WSADATA WSAData; 1383 if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0) 1384 { 1385 MessageBox(NULL, "Unable to initialize WinSock", "UnrealIRCD Initalization Error", MB_OK); 1386 fprintf(stderr, "Unable to initialize WinSock\n"); 1387 exit(1); 1388 } 1389 } 1390 #endif