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_mpath.c 21 22#include <dpmi.h> 23#include "quakedef.h" 24#include "mpdosock.h" 25 26short flat_selector; 27 28int WSAGetLastError(void); 29void sockets_flush(void); 30 31extern cvar_t hostname; 32 33#define MAXHOSTNAMELEN 256 34 35static int net_acceptsocket = -1; // socket for fielding new connections 36static int net_controlsocket; 37static int net_broadcastsocket = 0; 38//static qboolean ifbcastinit = false; 39static struct qsockaddr broadcastaddr; 40 41static unsigned long myAddr; 42 43#include "net_mp.h" 44 45 46//============================================================================= 47 48int MPATH_Init (void) 49{ 50 int i; 51 struct hostent *local = NULL; 52 char buff[MAXHOSTNAMELEN]; 53 struct qsockaddr addr; 54 char *p; 55 56 if (COM_CheckParm ("-mpath") == 0) 57 return -1; 58 59 flat_selector = __dpmi_allocate_ldt_descriptors(1); 60 if (flat_selector == -1) { 61 Con_Printf("MPATH_Init: Can't get flat selector\n"); 62 return -1; 63 } 64 if (__dpmi_set_segment_base_address(flat_selector, 0) == -1) { 65 Con_Printf("MPATH_Init: Can't seg flat base!\n"); 66 return -1; 67 } 68 if (__dpmi_set_segment_limit(flat_selector, 0xffffffff) == -1) { 69 Con_Printf("MPATH_Init: Can't set segment limit\n"); 70 return -1; 71 } 72 // determine my name & address 73 if (gethostname(buff, MAXHOSTNAMELEN) == 0) 74 local = gethostbyname(buff); 75 if (local) 76 { 77 myAddr = *(int *)local->h_addr_list[0]; 78 79 // if the quake hostname isn't set, set it to the machine name 80 if (Q_strcmp(hostname.string, "UNNAMED") == 0) 81 { 82 // see if it's a text IP address (well, close enough) 83 for (p = buff; *p; p++) 84 if ((*p < '0' || *p > '9') && *p != '.') 85 break; 86 87 // if it is a real name, strip off the domain; we only want the host 88 if (*p) 89 { 90 for (i = 0; i < 15; i++) 91 if (buff[i] == '.') 92 break; 93 buff[i] = 0; 94 } 95 Cvar_Set ("hostname", buff); 96 } 97 } 98 99 if ((net_controlsocket = MPATH_OpenSocket (0)) == -1) 100 Sys_Error("MPATH_Init: Unable to open control socket\n"); 101 102 ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; 103 ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; 104 ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport); 105 106 MPATH_GetSocketAddr (net_controlsocket, &addr); 107 Q_strcpy(my_tcpip_address, MPATH_AddrToString (&addr)); 108 p = Q_strrchr (my_tcpip_address, ':'); 109 if (p) 110 *p = 0; 111 112 Con_Printf("MPath Initialized\n"); 113 tcpipAvailable = true; 114 115 return net_controlsocket; 116} 117 118//============================================================================= 119 120void MPATH_Shutdown (void) 121{ 122 MPATH_Listen (false); 123 MPATH_CloseSocket (net_controlsocket); 124} 125 126//============================================================================= 127 128void MPATH_Listen (qboolean state) 129{ 130 // enable listening 131 if (state) 132 { 133 if (net_acceptsocket != -1) 134 return; 135 if ((net_acceptsocket = MPATH_OpenSocket (net_hostport)) == -1) 136 Sys_Error ("MPATH_Listen: Unable to open accept socket\n"); 137 return; 138 } 139 140 // disable listening 141 if (net_acceptsocket == -1) 142 return; 143 MPATH_CloseSocket (net_acceptsocket); 144 net_acceptsocket = -1; 145} 146 147//============================================================================= 148 149int MPATH_OpenSocket (int port) 150{ 151 int newsocket; 152 struct sockaddr_in address; 153 u_long _true = 1; 154 155 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 156 return -1; 157 158 if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) 159 goto ErrorReturn; 160 161 address.sin_family = AF_INET; 162 address.sin_addr.s_addr = INADDR_ANY; 163 address.sin_port = htons(port); 164 if( bind (newsocket, (void *)&address, sizeof(address)) == -1) 165 goto ErrorReturn; 166 167 return newsocket; 168 169ErrorReturn: 170 closesocket (newsocket); 171 return -1; 172} 173 174//============================================================================= 175 176int MPATH_CloseSocket (int socket) 177{ 178 if (socket == net_broadcastsocket) 179 net_broadcastsocket = 0; 180 return closesocket (socket); 181} 182 183 184//============================================================================= 185/* 186============ 187PartialIPAddress 188 189this lets you type only as much of the net address as required, using 190the local network components to fill in the rest 191============ 192*/ 193static int PartialIPAddress (char *in, struct qsockaddr *hostaddr) 194{ 195 char buff[256]; 196 char *b; 197 int addr; 198 int num; 199 int mask; 200 int run; 201 int port; 202 203 buff[0] = '.'; 204 b = buff; 205 strcpy(buff+1, in); 206 if (buff[1] == '.') 207 b++; 208 209 addr = 0; 210 mask=-1; 211 while (*b == '.') 212 { 213 b++; 214 num = 0; 215 run = 0; 216 while (!( *b < '0' || *b > '9')) 217 { 218 num = num*10 + *b++ - '0'; 219 if (++run > 3) 220 return -1; 221 } 222 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) 223 return -1; 224 if (num < 0 || num > 255) 225 return -1; 226 mask<<=8; 227 addr = (addr<<8) + num; 228 } 229 230 if (*b++ == ':') 231 port = Q_atoi(b); 232 else 233 port = net_hostport; 234 235 hostaddr->sa_family = AF_INET; 236 ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port); 237 ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); 238 239 return 0; 240} 241//============================================================================= 242 243int MPATH_Connect (int socket, struct qsockaddr *addr) 244{ 245 return 0; 246} 247 248//============================================================================= 249 250int MPATH_CheckNewConnections (void) 251{ 252 char buf[4]; 253 254 if (net_acceptsocket == -1) 255 return -1; 256 257 if (recvfrom (net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) 258 return net_acceptsocket; 259 return -1; 260} 261 262//============================================================================= 263 264int MPATH_Read (int socket, byte *buf, int len, struct qsockaddr *addr) 265{ 266 int addrlen = sizeof (struct qsockaddr); 267 int ret; 268 269 ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); 270 if (ret == -1) 271 { 272 int errno = WSAGetLastError(); 273 274 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) 275 return 0; 276 277 } 278 return ret; 279} 280 281//============================================================================= 282 283int MPATH_MakeSocketBroadcastCapable (int socket) 284{ 285 int i = 1; 286 287 // make this socket broadcast capable 288 if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) 289 return -1; 290 net_broadcastsocket = socket; 291 292 return 0; 293} 294 295//============================================================================= 296 297int MPATH_Broadcast (int socket, byte *buf, int len) 298{ 299 int ret; 300 301 if (socket != net_broadcastsocket) 302 { 303 if (net_broadcastsocket != 0) 304 Sys_Error("Attempted to use multiple broadcasts sockets\n"); 305 ret = MPATH_MakeSocketBroadcastCapable (socket); 306 if (ret == -1) 307 { 308 Con_Printf("Unable to make socket broadcast capable\n"); 309 return ret; 310 } 311 } 312 313 return MPATH_Write (socket, buf, len, &broadcastaddr); 314} 315 316//============================================================================= 317 318int MPATH_Write (int socket, byte *buf, int len, struct qsockaddr *addr) 319{ 320 int ret; 321 322 ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); 323 if (ret == -1) 324 if (WSAGetLastError() == WSAEWOULDBLOCK) 325 return 0; 326 327 sockets_flush(); 328 329 return ret; 330} 331 332//============================================================================= 333 334char *MPATH_AddrToString (struct qsockaddr *addr) 335{ 336 static char buffer[22]; 337 int haddr; 338 339 haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); 340 sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); 341 return buffer; 342} 343 344//============================================================================= 345 346int MPATH_StringToAddr (char *string, struct qsockaddr *addr) 347{ 348 int ha1, ha2, ha3, ha4, hp; 349 int ipaddr; 350 351 sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); 352 ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; 353 354 addr->sa_family = AF_INET; 355 ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); 356 ((struct sockaddr_in *)addr)->sin_port = htons(hp); 357 return 0; 358} 359 360//============================================================================= 361 362int MPATH_GetSocketAddr (int socket, struct qsockaddr *addr) 363{ 364 int addrlen = sizeof(struct qsockaddr); 365 unsigned int a; 366 367 Q_memset(addr, 0, sizeof(struct qsockaddr)); 368 getsockname(socket, (struct sockaddr *)addr, &addrlen); 369 a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 370 if (a == 0 || a == inet_addr("127.0.0.1")) 371 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; 372 373 return 0; 374} 375 376//============================================================================= 377 378int MPATH_GetNameFromAddr (struct qsockaddr *addr, char *name) 379{ 380 struct hostent *hostentry; 381 382 hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); 383 if (hostentry) 384 { 385 Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); 386 return 0; 387 } 388 389 Q_strcpy (name, MPATH_AddrToString (addr)); 390 return 0; 391} 392 393//============================================================================= 394 395int MPATH_GetAddrFromName(char *name, struct qsockaddr *addr) 396{ 397 struct hostent *hostentry; 398 399 if (name[0] >= '0' && name[0] <= '9') 400 return PartialIPAddress (name, addr); 401 402 hostentry = gethostbyname (name); 403 if (!hostentry) 404 return -1; 405 406 addr->sa_family = AF_INET; 407 ((struct sockaddr_in *)addr)->sin_port = htons(net_hostport); 408 ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; 409 410 return 0; 411} 412 413//============================================================================= 414 415int MPATH_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) 416{ 417 if (addr1->sa_family != addr2->sa_family) 418 return -1; 419 420 if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) 421 return -1; 422 423 if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) 424 return 1; 425 426 return 0; 427} 428 429//============================================================================= 430 431int MPATH_GetSocketPort (struct qsockaddr *addr) 432{ 433 return ntohs(((struct sockaddr_in *)addr)->sin_port); 434} 435 436 437int MPATH_SetSocketPort (struct qsockaddr *addr, int port) 438{ 439 ((struct sockaddr_in *)addr)->sin_port = htons(port); 440 return 0; 441} 442 443//============================================================================= 444