1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// net_wipx.c 21 22#include "quakedef.h" 23#include "winquake.h" 24#include <wsipx.h> 25#include "net_wipx.h" 26 27extern cvar_t hostname; 28 29#define MAXHOSTNAMELEN 256 30 31static int net_acceptsocket = -1; // socket for fielding new connections 32static int net_controlsocket; 33static struct qsockaddr broadcastaddr; 34 35extern qboolean winsock_initialized; 36extern WSADATA winsockdata; 37 38#define IPXSOCKETS 18 39static int ipxsocket[IPXSOCKETS]; 40static int sequence[IPXSOCKETS]; 41 42//============================================================================= 43 44int WIPX_Init (void) 45{ 46 int i; 47 char buff[MAXHOSTNAMELEN]; 48 struct qsockaddr addr; 49 char *p; 50 int r; 51 WORD wVersionRequested; 52 53 if (COM_CheckParm ("-noipx")) 54 return -1; 55 56// make sure LoadLibrary has happened successfully 57 if (!winsock_lib_initialized) 58 return -1; 59 60 if (winsock_initialized == 0) 61 { 62 wVersionRequested = MAKEWORD(1, 1); 63 64 r = pWSAStartup (MAKEWORD(1, 1), &winsockdata); 65 66 if (r) 67 { 68 Con_Printf ("Winsock initialization failed.\n"); 69 return -1; 70 } 71 } 72 winsock_initialized++; 73 74 for (i = 0; i < IPXSOCKETS; i++) 75 ipxsocket[i] = 0; 76 77 // determine my name & address 78 if (pgethostname(buff, MAXHOSTNAMELEN) == 0) 79 { 80 // if the quake hostname isn't set, set it to the machine name 81 if (Q_strcmp(hostname.string, "UNNAMED") == 0) 82 { 83 // see if it's a text IP address (well, close enough) 84 for (p = buff; *p; p++) 85 if ((*p < '0' || *p > '9') && *p != '.') 86 break; 87 88 // if it is a real name, strip off the domain; we only want the host 89 if (*p) 90 { 91 for (i = 0; i < 15; i++) 92 if (buff[i] == '.') 93 break; 94 buff[i] = 0; 95 } 96 Cvar_Set ("hostname", buff); 97 } 98 } 99 100 if ((net_controlsocket = WIPX_OpenSocket (0)) == -1) 101 { 102 Con_Printf("WIPX_Init: Unable to open control socket\n"); 103 if (--winsock_initialized == 0) 104 pWSACleanup (); 105 return -1; 106 } 107 108 ((struct sockaddr_ipx *)&broadcastaddr)->sa_family = AF_IPX; 109 memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_netnum, 0, 4); 110 memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_nodenum, 0xff, 6); 111 ((struct sockaddr_ipx *)&broadcastaddr)->sa_socket = htons((unsigned short)net_hostport); 112 113 WIPX_GetSocketAddr (net_controlsocket, &addr); 114 Q_strcpy(my_ipx_address, WIPX_AddrToString (&addr)); 115 p = Q_strrchr (my_ipx_address, ':'); 116 if (p) 117 *p = 0; 118 119 Con_Printf("Winsock IPX Initialized\n"); 120 ipxAvailable = true; 121 122 return net_controlsocket; 123} 124 125//============================================================================= 126 127void WIPX_Shutdown (void) 128{ 129 WIPX_Listen (false); 130 WIPX_CloseSocket (net_controlsocket); 131 if (--winsock_initialized == 0) 132 pWSACleanup (); 133} 134 135//============================================================================= 136 137void WIPX_Listen (qboolean state) 138{ 139 // enable listening 140 if (state) 141 { 142 if (net_acceptsocket != -1) 143 return; 144 if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == -1) 145 Sys_Error ("WIPX_Listen: Unable to open accept socket\n"); 146 return; 147 } 148 149 // disable listening 150 if (net_acceptsocket == -1) 151 return; 152 WIPX_CloseSocket (net_acceptsocket); 153 net_acceptsocket = -1; 154} 155 156//============================================================================= 157 158int WIPX_OpenSocket (int port) 159{ 160 int handle; 161 int newsocket; 162 struct sockaddr_ipx address; 163 u_long _true = 1; 164 165 for (handle = 0; handle < IPXSOCKETS; handle++) 166 if (ipxsocket[handle] == 0) 167 break; 168 if (handle == IPXSOCKETS) 169 return -1; 170 171 if ((newsocket = psocket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET) 172 return -1; 173 174 if (pioctlsocket (newsocket, FIONBIO, &_true) == -1) 175 goto ErrorReturn; 176 177 if (psetsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) < 0) 178 goto ErrorReturn; 179 180 address.sa_family = AF_IPX; 181 memset(address.sa_netnum, 0, 4); 182 memset(address.sa_nodenum, 0, 6);; 183 address.sa_socket = htons((unsigned short)port); 184 if( bind (newsocket, (void *)&address, sizeof(address)) == 0) 185 { 186 ipxsocket[handle] = newsocket; 187 sequence[handle] = 0; 188 return handle; 189 } 190 191 Sys_Error ("Winsock IPX bind failed\n"); 192ErrorReturn: 193 pclosesocket (newsocket); 194 return -1; 195} 196 197//============================================================================= 198 199int WIPX_CloseSocket (int handle) 200{ 201 int socket = ipxsocket[handle]; 202 int ret; 203 204 ret = pclosesocket (socket); 205 ipxsocket[handle] = 0; 206 return ret; 207} 208 209 210//============================================================================= 211 212int WIPX_Connect (int handle, struct qsockaddr *addr) 213{ 214 return 0; 215} 216 217//============================================================================= 218 219int WIPX_CheckNewConnections (void) 220{ 221 unsigned long available; 222 223 if (net_acceptsocket == -1) 224 return -1; 225 226 if (pioctlsocket (ipxsocket[net_acceptsocket], FIONREAD, &available) == -1) 227 Sys_Error ("WIPX: ioctlsocket (FIONREAD) failed\n"); 228 if (available) 229 return net_acceptsocket; 230 return -1; 231} 232 233//============================================================================= 234 235static byte packetBuffer[NET_DATAGRAMSIZE + 4]; 236 237int WIPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr) 238{ 239 int addrlen = sizeof (struct qsockaddr); 240 int socket = ipxsocket[handle]; 241 int ret; 242 243 ret = precvfrom (socket, packetBuffer, len+4, 0, (struct sockaddr *)addr, &addrlen); 244 if (ret == -1) 245 { 246 int errno = pWSAGetLastError(); 247 248 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) 249 return 0; 250 251 } 252 253 if (ret < 4) 254 return 0; 255 256 // remove sequence number, it's only needed for DOS IPX 257 ret -= 4; 258 memcpy(buf, packetBuffer+4, ret); 259 260 return ret; 261} 262 263//============================================================================= 264 265int WIPX_Broadcast (int handle, byte *buf, int len) 266{ 267 return WIPX_Write (handle, buf, len, &broadcastaddr); 268} 269 270//============================================================================= 271 272int WIPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr) 273{ 274 int socket = ipxsocket[handle]; 275 int ret; 276 277 // build packet with sequence number 278 *(int *)(&packetBuffer[0]) = sequence[handle]; 279 sequence[handle]++; 280 memcpy(&packetBuffer[4], buf, len); 281 len += 4; 282 283 ret = psendto (socket, packetBuffer, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); 284 if (ret == -1) 285 if (pWSAGetLastError() == WSAEWOULDBLOCK) 286 return 0; 287 288 return ret; 289} 290 291//============================================================================= 292 293char *WIPX_AddrToString (struct qsockaddr *addr) 294{ 295 static char buf[28]; 296 297 sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u", 298 ((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff, 299 ((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff, 300 ((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff, 301 ((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff, 302 ((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff, 303 ((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff, 304 ((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff, 305 ((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff, 306 ((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff, 307 ((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff, 308 ntohs(((struct sockaddr_ipx *)addr)->sa_socket) 309 ); 310 return buf; 311} 312 313//============================================================================= 314 315int WIPX_StringToAddr (char *string, struct qsockaddr *addr) 316{ 317 int val; 318 char buf[3]; 319 320 buf[2] = 0; 321 Q_memset(addr, 0, sizeof(struct qsockaddr)); 322 addr->sa_family = AF_IPX; 323 324#define DO(src,dest) \ 325 buf[0] = string[src]; \ 326 buf[1] = string[src + 1]; \ 327 if (sscanf (buf, "%x", &val) != 1) \ 328 return -1; \ 329 ((struct sockaddr_ipx *)addr)->dest = val 330 331 DO(0, sa_netnum[0]); 332 DO(2, sa_netnum[1]); 333 DO(4, sa_netnum[2]); 334 DO(6, sa_netnum[3]); 335 DO(9, sa_nodenum[0]); 336 DO(11, sa_nodenum[1]); 337 DO(13, sa_nodenum[2]); 338 DO(15, sa_nodenum[3]); 339 DO(17, sa_nodenum[4]); 340 DO(19, sa_nodenum[5]); 341#undef DO 342 343 sscanf (&string[22], "%u", &val); 344 ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val); 345 346 return 0; 347} 348 349//============================================================================= 350 351int WIPX_GetSocketAddr (int handle, struct qsockaddr *addr) 352{ 353 int socket = ipxsocket[handle]; 354 int addrlen = sizeof(struct qsockaddr); 355 unsigned int a; 356 357 Q_memset(addr, 0, sizeof(struct qsockaddr)); 358 if(pgetsockname(socket, (struct sockaddr *)addr, &addrlen) != 0) 359 { 360 int errno = pWSAGetLastError(); 361 } 362 363 return 0; 364} 365 366//============================================================================= 367 368int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name) 369{ 370 Q_strcpy(name, WIPX_AddrToString(addr)); 371 return 0; 372} 373 374//============================================================================= 375 376int WIPX_GetAddrFromName(char *name, struct qsockaddr *addr) 377{ 378 int n; 379 char buf[32]; 380 381 n = Q_strlen(name); 382 383 if (n == 12) 384 { 385 sprintf(buf, "00000000:%s:%u", name, net_hostport); 386 return WIPX_StringToAddr (buf, addr); 387 } 388 if (n == 21) 389 { 390 sprintf(buf, "%s:%u", name, net_hostport); 391 return WIPX_StringToAddr (buf, addr); 392 } 393 if (n > 21 && n <= 27) 394 return WIPX_StringToAddr (name, addr); 395 396 return -1; 397} 398 399//============================================================================= 400 401int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) 402{ 403 if (addr1->sa_family != addr2->sa_family) 404 return -1; 405 406 if (*((struct sockaddr_ipx *)addr1)->sa_netnum && *((struct sockaddr_ipx *)addr2)->sa_netnum) 407 if (memcmp(((struct sockaddr_ipx *)addr1)->sa_netnum, ((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0) 408 return -1; 409 if (memcmp(((struct sockaddr_ipx *)addr1)->sa_nodenum, ((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0) 410 return -1; 411 412 if (((struct sockaddr_ipx *)addr1)->sa_socket != ((struct sockaddr_ipx *)addr2)->sa_socket) 413 return 1; 414 415 return 0; 416} 417 418//============================================================================= 419 420int WIPX_GetSocketPort (struct qsockaddr *addr) 421{ 422 return ntohs(((struct sockaddr_ipx *)addr)->sa_socket); 423} 424 425 426int WIPX_SetSocketPort (struct qsockaddr *addr, int port) 427{ 428 ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port); 429 return 0; 430} 431 432//============================================================================= 433