1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // net_main.c 21 22 #include "quakedef.h" 23 #include "net_vcr.h" 24 25 qsocket_t *net_activeSockets = NULL; 26 qsocket_t *net_freeSockets = NULL; 27 int net_numsockets = 0; 28 29 qboolean serialAvailable = false; 30 qboolean ipxAvailable = false; 31 qboolean tcpipAvailable = false; 32 33 int net_hostport; 34 int DEFAULTnet_hostport = 26000; 35 36 char my_ipx_address[NET_NAMELEN]; 37 char my_tcpip_address[NET_NAMELEN]; 38 39 void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem); 40 void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem); 41 void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); 42 void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); 43 44 static qboolean listening = false; 45 46 qboolean slistInProgress = false; 47 qboolean slistSilent = false; 48 qboolean slistLocal = true; 49 static double slistStartTime; 50 static int slistLastShown; 51 52 static void Slist_Send(void*); 53 static void Slist_Poll(void*); 54 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send, NULL}; 55 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll, NULL}; 56 57 58 sizebuf_t net_message; 59 int net_activeconnections = 0; 60 61 int messagesSent = 0; 62 int messagesReceived = 0; 63 int unreliableMessagesSent = 0; 64 int unreliableMessagesReceived = 0; 65 66 cvar_t net_messagetimeout = CVAR2("net_messagetimeout","300"); 67 cvar_t hostname = CVAR2("hostname", "UNNAMED"); 68 69 qboolean configRestored = false; 70 cvar_t config_com_port = CVAR3("_config_com_port", "0x3f8", true); 71 cvar_t config_com_irq = CVAR3("_config_com_irq", "4", true); 72 cvar_t config_com_baud = CVAR3("_config_com_baud", "57600", true); 73 cvar_t config_com_modem = CVAR3("_config_com_modem", "1", true); 74 cvar_t config_modem_dialtype = CVAR3("_config_modem_dialtype", "T", true); 75 cvar_t config_modem_clear = CVAR3("_config_modem_clear", "ATZ", true); 76 cvar_t config_modem_init = CVAR3("_config_modem_init", "", true); 77 cvar_t config_modem_hangup = CVAR3("_config_modem_hangup", "AT H", true); 78 79 #ifdef IDGODS 80 cvar_t idgods = CVAR2("idgods", "0"); 81 #endif 82 83 int vcrFile = -1; 84 qboolean recording = false; 85 86 // these two macros are to make the code more readable 87 #define sfunc net_drivers[sock->driver] 88 #define dfunc net_drivers[net_driverlevel] 89 90 int net_driverlevel; 91 92 93 double net_time; 94 95 double SetNetTime(void) 96 { 97 net_time = Sys_FloatTime(); 98 return net_time; 99 } 100 101 102 /* 103 =================== 104 NET_NewQSocket 105 106 Called by drivers when a new communications endpoint is required 107 The sequence and buffer fields will be filled in properly 108 =================== 109 */ 110 qsocket_t *NET_NewQSocket (void) 111 { 112 qsocket_t *sock; 113 114 if (net_freeSockets == NULL) 115 return NULL; 116 117 if (net_activeconnections >= svs.maxclients) 118 return NULL; 119 120 // get one from free list 121 sock = net_freeSockets; 122 net_freeSockets = sock->next; 123 124 // add it to active list 125 sock->next = net_activeSockets; 126 net_activeSockets = sock; 127 128 sock->disconnected = false; 129 sock->connecttime = net_time; 130 Q_strcpy (sock->address,"UNSET ADDRESS"); 131 sock->driver = net_driverlevel; 132 sock->socket = 0; 133 sock->driverdata = NULL; 134 sock->canSend = true; 135 sock->sendNext = false; 136 sock->lastMessageTime = net_time; 137 sock->ackSequence = 0; 138 sock->sendSequence = 0; 139 sock->unreliableSendSequence = 0; 140 sock->sendMessageLength = 0; 141 sock->receiveSequence = 0; 142 sock->unreliableReceiveSequence = 0; 143 sock->receiveMessageLength = 0; 144 145 return sock; 146 } 147 148 149 void NET_FreeQSocket(qsocket_t *sock) 150 { 151 qsocket_t *s; 152 153 // remove it from active list 154 if (sock == net_activeSockets) 155 net_activeSockets = net_activeSockets->next; 156 else 157 { 158 for (s = net_activeSockets; s; s = s->next) 159 if (s->next == sock) 160 { 161 s->next = sock->next; 162 break; 163 } 164 if (!s) 165 Sys_Error ("NET_FreeQSocket: not active\n"); 166 } 167 168 // add it to free list 169 sock->next = net_freeSockets; 170 net_freeSockets = sock; 171 sock->disconnected = true; 172 } 173 174 175 static void NET_Listen_f (void) 176 { 177 if (Cmd_Argc () != 2) 178 { 179 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0); 180 return; 181 } 182 183 listening = Q_atoi(Cmd_Argv(1)) ? true : false; 184 185 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++) 186 { 187 if (net_drivers[net_driverlevel].initialized == false) 188 continue; 189 dfunc.Listen (listening); 190 } 191 } 192 193 194 static void MaxPlayers_f (void) 195 { 196 int n; 197 198 if (Cmd_Argc () != 2) 199 { 200 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients); 201 return; 202 } 203 204 if (sv.active) 205 { 206 Con_Printf ("maxplayers can not be changed while a server is running.\n"); 207 return; 208 } 209 210 n = Q_atoi(Cmd_Argv(1)); 211 if (n < 1) 212 n = 1; 213 if (n > svs.maxclientslimit) 214 { 215 n = svs.maxclientslimit; 216 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n); 217 } 218 219 if ((n == 1) && listening) 220 Cbuf_AddText ("listen 0\n"); 221 222 if ((n > 1) && (!listening)) 223 Cbuf_AddText ("listen 1\n"); 224 225 svs.maxclients = n; 226 if (n == 1) 227 Cvar_Set ("deathmatch", "0"); 228 else 229 Cvar_Set ("deathmatch", "1"); 230 } 231 232 233 static void NET_Port_f (void) 234 { 235 int n; 236 237 if (Cmd_Argc () != 2) 238 { 239 Con_Printf ("\"port\" is \"%u\"\n", net_hostport); 240 return; 241 } 242 243 n = Q_atoi(Cmd_Argv(1)); 244 if (n < 1 || n > 65534) 245 { 246 Con_Printf ("Bad value, must be between 1 and 65534\n"); 247 return; 248 } 249 250 DEFAULTnet_hostport = n; 251 net_hostport = n; 252 253 if (listening) 254 { 255 // force a change to the new port 256 Cbuf_AddText ("listen 0\n"); 257 Cbuf_AddText ("listen 1\n"); 258 } 259 } 260 261 262 static void PrintSlistHeader(void) 263 { 264 Con_Printf("Server Map Users\n"); 265 Con_Printf("--------------- --------------- -----\n"); 266 slistLastShown = 0; 267 } 268 269 270 static void PrintSlist(void) 271 { 272 int n; 273 274 for (n = slistLastShown; n < hostCacheCount; n++) 275 { 276 if (hostcache[n].maxusers) 277 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); 278 else 279 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); 280 } 281 slistLastShown = n; 282 } 283 284 285 static void PrintSlistTrailer(void) 286 { 287 if (hostCacheCount) 288 Con_Printf("== end list ==\n\n"); 289 else 290 Con_Printf("No Quake servers found.\n\n"); 291 } 292 293 294 void NET_Slist_f (void) 295 { 296 if (slistInProgress) 297 return; 298 299 if (! slistSilent) 300 { 301 Con_Printf("Looking for Quake servers...\n"); 302 PrintSlistHeader(); 303 } 304 305 slistInProgress = true; 306 slistStartTime = Sys_FloatTime(); 307 308 SchedulePollProcedure(&slistSendProcedure, 0.0); 309 SchedulePollProcedure(&slistPollProcedure, 0.1); 310 311 hostCacheCount = 0; 312 } 313 314 315 static void Slist_Send(void* /* arg */) 316 { 317 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) 318 { 319 if (!slistLocal && net_driverlevel == 0) 320 continue; 321 if (net_drivers[net_driverlevel].initialized == false) 322 continue; 323 dfunc.SearchForHosts (true); 324 } 325 326 if ((Sys_FloatTime() - slistStartTime) < 0.5) 327 SchedulePollProcedure(&slistSendProcedure, 0.75); 328 } 329 330 331 static void Slist_Poll(void* /* arg */) 332 { 333 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) 334 { 335 if (!slistLocal && net_driverlevel == 0) 336 continue; 337 if (net_drivers[net_driverlevel].initialized == false) 338 continue; 339 dfunc.SearchForHosts (false); 340 } 341 342 if (! slistSilent) 343 PrintSlist(); 344 345 if ((Sys_FloatTime() - slistStartTime) < 1.5) 346 { 347 SchedulePollProcedure(&slistPollProcedure, 0.1); 348 return; 349 } 350 351 if (! slistSilent) 352 PrintSlistTrailer(); 353 slistInProgress = false; 354 slistSilent = false; 355 slistLocal = true; 356 } 357 358 359 /* 360 =================== 361 NET_Connect 362 =================== 363 */ 364 365 int hostCacheCount = 0; 366 hostcache_t hostcache[HOSTCACHESIZE]; 367 368 qsocket_t *NET_Connect (const char *host) 369 { 370 qsocket_t *ret; 371 int n; 372 int numdrivers = net_numdrivers; 373 374 SetNetTime(); 375 376 if (host && *host == 0) 377 host = NULL; 378 379 if (host) 380 { 381 if (Q_strcasecmp (host, "local") == 0) 382 { 383 numdrivers = 1; 384 goto JustDoIt; 385 } 386 387 if (hostCacheCount) 388 { 389 for (n = 0; n < hostCacheCount; n++) 390 if (Q_strcasecmp (host, hostcache[n].name) == 0) 391 { 392 host = hostcache[n].cname; 393 break; 394 } 395 if (n < hostCacheCount) 396 goto JustDoIt; 397 } 398 } 399 400 slistSilent = host ? true : false; 401 NET_Slist_f (); 402 403 while(slistInProgress) 404 NET_Poll(); 405 406 if (host == NULL) 407 { 408 if (hostCacheCount != 1) 409 return NULL; 410 host = hostcache[0].cname; 411 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host); 412 } 413 414 if (hostCacheCount) 415 for (n = 0; n < hostCacheCount; n++) 416 if (Q_strcasecmp (host, hostcache[n].name) == 0) 417 { 418 host = hostcache[n].cname; 419 break; 420 } 421 422 JustDoIt: 423 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++) 424 { 425 if (net_drivers[net_driverlevel].initialized == false) 426 continue; 427 ret = dfunc.Connect (host); 428 if (ret) 429 return ret; 430 } 431 432 if (host) 433 { 434 Con_Printf("\n"); 435 PrintSlistHeader(); 436 PrintSlist(); 437 PrintSlistTrailer(); 438 } 439 440 return NULL; 441 } 442 443 444 /* 445 =================== 446 NET_CheckNewConnections 447 =================== 448 */ 449 450 struct vcrConnect_t 451 { 452 double time; 453 int op; 454 long session; 455 } vcrConnect; 456 457 qsocket_t *NET_CheckNewConnections (void) 458 { 459 qsocket_t *ret; 460 461 SetNetTime(); 462 463 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++) 464 { 465 if (net_drivers[net_driverlevel].initialized == false) 466 continue; 467 if (net_driverlevel && listening == false) 468 continue; 469 ret = dfunc.CheckNewConnections (); 470 if (ret) 471 { 472 if (recording) 473 { 474 vcrConnect.time = host_time; 475 vcrConnect.op = VCR_OP_CONNECT; 476 vcrConnect.session = (long)ret; 477 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect)); 478 Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN); 479 } 480 return ret; 481 } 482 } 483 484 if (recording) 485 { 486 vcrConnect.time = host_time; 487 vcrConnect.op = VCR_OP_CONNECT; 488 vcrConnect.session = 0; 489 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect)); 490 } 491 492 return NULL; 493 } 494 495 /* 496 =================== 497 NET_Close 498 =================== 499 */ 500 void NET_Close (qsocket_t *sock) 501 { 502 if (!sock) 503 return; 504 505 if (sock->disconnected) 506 return; 507 508 SetNetTime(); 509 510 // call the driver_Close function 511 sfunc.Close (sock); 512 513 NET_FreeQSocket(sock); 514 } 515 516 517 /* 518 ================= 519 NET_GetMessage 520 521 If there is a complete message, return it in net_message 522 523 returns 0 if no data is waiting 524 returns 1 if a message was received 525 returns -1 if connection is invalid 526 ================= 527 */ 528 529 struct vcrGetMessage_t 530 { 531 double time; 532 int op; 533 long session; 534 int ret; 535 int len; 536 } vcrGetMessage; 537 538 extern void PrintStats(qsocket_t *s); 539 540 int NET_GetMessage (qsocket_t *sock) 541 { 542 int ret; 543 544 if (!sock) 545 return -1; 546 547 if (sock->disconnected) 548 { 549 Con_Printf("NET_GetMessage: disconnected socket\n"); 550 return -1; 551 } 552 553 SetNetTime(); 554 555 ret = sfunc.QGetMessage(sock); 556 557 // see if this connection has timed out 558 if (ret == 0 && sock->driver) 559 { 560 if (net_time - sock->lastMessageTime > net_messagetimeout.value) 561 { 562 NET_Close(sock); 563 return -1; 564 } 565 } 566 567 568 if (ret > 0) 569 { 570 if (sock->driver) 571 { 572 sock->lastMessageTime = net_time; 573 if (ret == 1) 574 messagesReceived++; 575 else if (ret == 2) 576 unreliableMessagesReceived++; 577 } 578 579 if (recording) 580 { 581 vcrGetMessage.time = host_time; 582 vcrGetMessage.op = VCR_OP_GETMESSAGE; 583 vcrGetMessage.session = (long)sock; 584 vcrGetMessage.ret = ret; 585 vcrGetMessage.len = net_message.cursize; 586 Sys_FileWrite (vcrFile, &vcrGetMessage, 24); 587 Sys_FileWrite (vcrFile, net_message.data, net_message.cursize); 588 } 589 } 590 else 591 { 592 if (recording) 593 { 594 vcrGetMessage.time = host_time; 595 vcrGetMessage.op = VCR_OP_GETMESSAGE; 596 vcrGetMessage.session = (long)sock; 597 vcrGetMessage.ret = ret; 598 Sys_FileWrite (vcrFile, &vcrGetMessage, 20); 599 } 600 } 601 602 return ret; 603 } 604 605 606 /* 607 ================== 608 NET_SendMessage 609 610 Try to send a complete length+message unit over the reliable stream. 611 returns 0 if the message cannot be delivered reliably, but the connection 612 is still considered valid 613 returns 1 if the message was sent properly 614 returns -1 if the connection died 615 ================== 616 */ 617 struct vcrSendMessage_t 618 { 619 double time; 620 int op; 621 long session; 622 int r; 623 } vcrSendMessage; 624 625 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data) 626 { 627 int r; 628 629 if (!sock) 630 return -1; 631 632 if (sock->disconnected) 633 { 634 Con_Printf("NET_SendMessage: disconnected socket\n"); 635 return -1; 636 } 637 638 SetNetTime(); 639 r = sfunc.QSendMessage(sock, data); 640 if (r == 1 && sock->driver) 641 messagesSent++; 642 643 if (recording) 644 { 645 vcrSendMessage.time = host_time; 646 vcrSendMessage.op = VCR_OP_SENDMESSAGE; 647 vcrSendMessage.session = (long)sock; 648 vcrSendMessage.r = r; 649 Sys_FileWrite (vcrFile, &vcrSendMessage, 20); 650 } 651 652 return r; 653 } 654 655 656 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) 657 { 658 int r; 659 660 if (!sock) 661 return -1; 662 663 if (sock->disconnected) 664 { 665 Con_Printf("NET_SendMessage: disconnected socket\n"); 666 return -1; 667 } 668 669 SetNetTime(); 670 r = sfunc.SendUnreliableMessage(sock, data); 671 if (r == 1 && sock->driver) 672 unreliableMessagesSent++; 673 674 if (recording) 675 { 676 vcrSendMessage.time = host_time; 677 vcrSendMessage.op = VCR_OP_SENDMESSAGE; 678 vcrSendMessage.session = (long)sock; 679 vcrSendMessage.r = r; 680 Sys_FileWrite (vcrFile, &vcrSendMessage, 20); 681 } 682 683 return r; 684 } 685 686 687 /* 688 ================== 689 NET_CanSendMessage 690 691 Returns true or false if the given qsocket can currently accept a 692 message to be transmitted. 693 ================== 694 */ 695 qboolean NET_CanSendMessage (qsocket_t *sock) 696 { 697 int r; 698 699 if (!sock) 700 return false; 701 702 if (sock->disconnected) 703 return false; 704 705 SetNetTime(); 706 707 r = sfunc.CanSendMessage(sock); 708 709 if (recording) 710 { 711 vcrSendMessage.time = host_time; 712 vcrSendMessage.op = VCR_OP_CANSENDMESSAGE; 713 vcrSendMessage.session = (long)sock; 714 vcrSendMessage.r = r; 715 Sys_FileWrite (vcrFile, &vcrSendMessage, 20); 716 } 717 718 return r; 719 } 720 721 722 int NET_SendToAll(sizebuf_t *data, int blocktime) 723 { 724 double start; 725 int i; 726 int count = 0; 727 qboolean state1 [MAX_SCOREBOARD]; 728 qboolean state2 [MAX_SCOREBOARD]; 729 730 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) 731 { 732 if (!host_client->netconnection) 733 continue; 734 if (host_client->active) 735 { 736 if (host_client->netconnection->driver == 0) 737 { 738 NET_SendMessage(host_client->netconnection, data); 739 state1[i] = true; 740 state2[i] = true; 741 continue; 742 } 743 count++; 744 state1[i] = false; 745 state2[i] = false; 746 } 747 else 748 { 749 state1[i] = true; 750 state2[i] = true; 751 } 752 } 753 754 start = Sys_FloatTime(); 755 while (count) 756 { 757 count = 0; 758 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) 759 { 760 if (! state1[i]) 761 { 762 if (NET_CanSendMessage (host_client->netconnection)) 763 { 764 state1[i] = true; 765 NET_SendMessage(host_client->netconnection, data); 766 } 767 else 768 { 769 NET_GetMessage (host_client->netconnection); 770 } 771 count++; 772 continue; 773 } 774 775 if (! state2[i]) 776 { 777 if (NET_CanSendMessage (host_client->netconnection)) 778 { 779 state2[i] = true; 780 } 781 else 782 { 783 NET_GetMessage (host_client->netconnection); 784 } 785 count++; 786 continue; 787 } 788 } 789 if ((Sys_FloatTime() - start) > blocktime) 790 break; 791 } 792 return count; 793 } 794 795 796 //============================================================================= 797 798 /* 799 ==================== 800 NET_Init 801 ==================== 802 */ 803 804 void NET_Init (void) 805 { 806 int i; 807 int controlSocket; 808 qsocket_t *s; 809 810 if (COM_CheckParm("-playback")) 811 { 812 net_numdrivers = 1; 813 net_drivers[0].Init = VCR_Init; 814 } 815 816 if (COM_CheckParm("-record")) 817 recording = true; 818 819 i = COM_CheckParm ("-port"); 820 if (!i) 821 i = COM_CheckParm ("-udpport"); 822 if (!i) 823 i = COM_CheckParm ("-ipxport"); 824 825 if (i) 826 { 827 if (i < com_argc-1) 828 DEFAULTnet_hostport = Q_atoi (com_argv[i+1]); 829 else 830 Sys_Error ("NET_Init: you must specify a number after -port"); 831 } 832 net_hostport = DEFAULTnet_hostport; 833 834 if (COM_CheckParm("-listen") || cls.state == ca_dedicated) 835 listening = true; 836 net_numsockets = svs.maxclientslimit; 837 if (cls.state != ca_dedicated) 838 net_numsockets++; 839 840 SetNetTime(); 841 842 for (i = 0; i < net_numsockets; i++) 843 { 844 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket"); 845 s->next = net_freeSockets; 846 net_freeSockets = s; 847 s->disconnected = true; 848 } 849 850 // allocate space for network message buffer 851 SZ_Alloc (&net_message, NET_MAXMESSAGE); 852 853 Cvar_RegisterVariable (&net_messagetimeout); 854 Cvar_RegisterVariable (&hostname); 855 Cvar_RegisterVariable (&config_com_port); 856 Cvar_RegisterVariable (&config_com_irq); 857 Cvar_RegisterVariable (&config_com_baud); 858 Cvar_RegisterVariable (&config_com_modem); 859 Cvar_RegisterVariable (&config_modem_dialtype); 860 Cvar_RegisterVariable (&config_modem_clear); 861 Cvar_RegisterVariable (&config_modem_init); 862 Cvar_RegisterVariable (&config_modem_hangup); 863 #ifdef IDGODS 864 Cvar_RegisterVariable (&idgods); 865 #endif 866 867 Cmd_AddCommand ("slist", NET_Slist_f); 868 Cmd_AddCommand ("listen", NET_Listen_f); 869 Cmd_AddCommand ("maxplayers", MaxPlayers_f); 870 Cmd_AddCommand ("port", NET_Port_f); 871 872 // initialize all the drivers 873 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++) 874 { 875 controlSocket = net_drivers[net_driverlevel].Init(); 876 if (controlSocket == -1) 877 continue; 878 net_drivers[net_driverlevel].initialized = true; 879 net_drivers[net_driverlevel].controlSock = controlSocket; 880 if (listening) 881 net_drivers[net_driverlevel].Listen (true); 882 } 883 884 if (*my_ipx_address) 885 Con_DPrintf("IPX address %s\n", my_ipx_address); 886 if (*my_tcpip_address) 887 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address); 888 } 889 890 /* 891 ==================== 892 NET_Shutdown 893 ==================== 894 */ 895 896 void NET_Shutdown (void) 897 { 898 qsocket_t *sock; 899 900 SetNetTime(); 901 902 for (sock = net_activeSockets; sock; sock = sock->next) 903 NET_Close(sock); 904 905 // 906 // shutdown the drivers 907 // 908 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) 909 { 910 if (net_drivers[net_driverlevel].initialized == true) 911 { 912 net_drivers[net_driverlevel].Shutdown (); 913 net_drivers[net_driverlevel].initialized = false; 914 } 915 } 916 917 if (vcrFile != -1) 918 { 919 Con_Printf ("Closing vcrfile.\n"); 920 Sys_FileClose(vcrFile); 921 } 922 } 923 924 925 static PollProcedure *pollProcedureList = NULL; 926 927 void NET_Poll(void) 928 { 929 PollProcedure *pp; 930 qboolean useModem; 931 932 if (!configRestored) 933 { 934 if (serialAvailable) 935 { 936 if (config_com_modem.value == 1.0) 937 useModem = true; 938 else 939 useModem = false; 940 SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem); 941 SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string); 942 } 943 configRestored = true; 944 } 945 946 SetNetTime(); 947 948 for (pp = pollProcedureList; pp; pp = pp->next) 949 { 950 if (pp->nextTime > net_time) 951 break; 952 pollProcedureList = pp->next; 953 pp->procedure(pp->arg); 954 } 955 } 956 957 958 void SchedulePollProcedure(PollProcedure *proc, double timeOffset) 959 { 960 PollProcedure *pp, *prev; 961 962 proc->nextTime = Sys_FloatTime() + timeOffset; 963 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) 964 { 965 if (pp->nextTime >= proc->nextTime) 966 break; 967 prev = pp; 968 } 969 970 if (prev == NULL) 971 { 972 proc->next = pollProcedureList; 973 pollProcedureList = proc; 974 return; 975 } 976 977 proc->next = pp; 978 prev->next = proc; 979 } 980 981 982 #ifdef IDGODS 983 #define IDNET 0xc0f62800 984 985 qboolean IsID(struct qsockaddr *addr) 986 { 987 if (idgods.value == 0.0) 988 return false; 989 990 if (addr->sa_family != 2) 991 return false; 992 993 if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET) 994 return true; 995 return false; 996 } 997 #endif 998