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_main.c 21 22#include "quakedef.h" 23 24#include <sys/types.h> 25#include <sys/socket.h> 26#include <netinet/in.h> 27#include <netdb.h> 28#include <sys/param.h> 29#include <sys/ioctl.h> 30#include <sys/uio.h> 31#include <arpa/inet.h> 32#include <errno.h> 33 34#if defined(sun) 35#include <unistd.h> 36#endif 37 38#ifdef sun 39#include <sys/filio.h> 40#endif 41 42#ifdef NeXT 43#include <libc.h> 44#endif 45 46netadr_t net_local_adr; 47 48netadr_t net_from; 49sizebuf_t net_message; 50int net_socket; // non blocking, for receives 51int net_send_socket; // blocking, for sends 52 53#define MAX_UDP_PACKET 8192 54byte net_message_buffer[MAX_UDP_PACKET]; 55 56// int gethostname (char *, int); 57int close (int); 58 59//============================================================================= 60 61void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s) 62{ 63 memset (s, 0, sizeof(*s)); 64 s->sin_family = AF_INET; 65 66 *(int *)&s->sin_addr = *(int *)&a->ip; 67 s->sin_port = a->port; 68} 69 70void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a) 71{ 72 *(int *)&a->ip = *(int *)&s->sin_addr; 73 a->port = s->sin_port; 74} 75 76qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) 77{ 78 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]) 79 return true; 80 return false; 81} 82 83 84qboolean NET_CompareAdr (netadr_t a, netadr_t b) 85{ 86 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port) 87 return true; 88 return false; 89} 90 91char *NET_AdrToString (netadr_t a) 92{ 93 static char s[64]; 94 95 sprintf (s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)); 96 97 return s; 98} 99 100char *NET_BaseAdrToString (netadr_t a) 101{ 102 static char s[64]; 103 104 sprintf (s, "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); 105 106 return s; 107} 108 109/* 110============= 111NET_StringToAdr 112 113idnewt 114idnewt:28000 115192.246.40.70 116192.246.40.70:28000 117============= 118*/ 119qboolean NET_StringToAdr (char *s, netadr_t *a) 120{ 121 struct hostent *h; 122 struct sockaddr_in sadr; 123 char *colon; 124 char copy[128]; 125 126 127 memset (&sadr, 0, sizeof(sadr)); 128 sadr.sin_family = AF_INET; 129 130 sadr.sin_port = 0; 131 132 strcpy (copy, s); 133 // strip off a trailing :port if present 134 for (colon = copy ; *colon ; colon++) 135 if (*colon == ':') 136 { 137 *colon = 0; 138 sadr.sin_port = htons(atoi(colon+1)); 139 } 140 141 if (copy[0] >= '0' && copy[0] <= '9') 142 { 143 *(int *)&sadr.sin_addr = inet_addr(copy); 144 } 145 else 146 { 147 if (! (h = gethostbyname(copy)) ) 148 return 0; 149 *(int *)&sadr.sin_addr = *(int *)h->h_addr_list[0]; 150 } 151 152 SockadrToNetadr (&sadr, a); 153 154 return true; 155} 156 157// Returns true if we can't bind the address locally--in other words, 158// the IP is NOT one of our interfaces. 159qboolean NET_IsClientLegal(netadr_t *adr) 160{ 161 struct sockaddr_in sadr; 162 int newsocket; 163 164#if 0 165 if (adr->ip[0] == 127) 166 return false; // no local connections period 167 168 NetadrToSockadr (adr, &sadr); 169 170 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 171 Sys_Error ("NET_IsClientLegal: socket:", strerror(errno)); 172 173 sadr.sin_port = 0; 174 175 if( bind (newsocket, (void *)&sadr, sizeof(sadr)) == -1) 176 { 177 // It is not a local address 178 close(newsocket); 179 return true; 180 } 181 close(newsocket); 182 return false; 183#else 184 return true; 185#endif 186} 187 188 189//============================================================================= 190 191qboolean NET_GetPacket (void) 192{ 193 int ret; 194 struct sockaddr_in from; 195 socklen_t fromlen; 196 197 fromlen = sizeof(from); 198 ret = recvfrom (net_socket, net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr *)&from, &fromlen); 199 if (ret == -1) { 200 if (errno == EWOULDBLOCK) 201 return false; 202 if (errno == ECONNREFUSED) 203 return false; 204 Sys_Printf ("NET_GetPacket: %s\n", strerror(errno)); 205 return false; 206 } 207 208 net_message.cursize = ret; 209 SockadrToNetadr (&from, &net_from); 210 211 return ret; 212} 213 214//============================================================================= 215 216void NET_SendPacket (int length, void *data, netadr_t to) 217{ 218 int ret; 219 struct sockaddr_in addr; 220 221 NetadrToSockadr (&to, &addr); 222 223 ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) ); 224 if (ret == -1) { 225 if (errno == EWOULDBLOCK) 226 return; 227 if (errno == ECONNREFUSED) 228 return; 229 Sys_Printf ("NET_SendPacket: %s\n", strerror(errno)); 230 } 231} 232 233//============================================================================= 234 235int UDP_OpenSocket (int port) 236{ 237 int newsocket; 238 struct sockaddr_in address; 239 qboolean _true = true; 240 int i; 241 242 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 243 Sys_Error ("UDP_OpenSocket: socket:", strerror(errno)); 244 if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1) 245 Sys_Error ("UDP_OpenSocket: ioctl FIONBIO:", strerror(errno)); 246 address.sin_family = AF_INET; 247//ZOID -- check for interface binding option 248 if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc) { 249 address.sin_addr.s_addr = inet_addr(com_argv[i+1]); 250 Con_Printf("Binding to IP Interface Address of %s\n", 251 inet_ntoa(address.sin_addr)); 252 } else 253 address.sin_addr.s_addr = INADDR_ANY; 254 if (port == PORT_ANY) 255 address.sin_port = 0; 256 else 257 address.sin_port = htons((short)port); 258 if( bind (newsocket, (void *)&address, sizeof(address)) == -1) 259 Sys_Error ("UDP_OpenSocket: bind: %s", strerror(errno)); 260 261 return newsocket; 262} 263 264void NET_GetLocalAddress (void) 265{ 266 char buff[MAXHOSTNAMELEN]; 267 struct sockaddr_in address; 268 socklen_t namelen; 269 270 gethostname(buff, MAXHOSTNAMELEN); 271 buff[MAXHOSTNAMELEN-1] = 0; 272 273 NET_StringToAdr (buff, &net_local_adr); 274 275 namelen = sizeof(address); 276 if (getsockname (net_socket, (struct sockaddr *)&address, &namelen) == -1) 277 Sys_Error ("NET_Init: getsockname:", strerror(errno)); 278 net_local_adr.port = address.sin_port; 279 280 Con_Printf("IP address %s\n", NET_AdrToString (net_local_adr) ); 281} 282 283/* 284==================== 285NET_Init 286==================== 287*/ 288void NET_Init (int port) 289{ 290 // 291 // open the single socket to be used for all communications 292 // 293 net_socket = UDP_OpenSocket (port); 294 295 // 296 // init the message buffer 297 // 298 net_message.maxsize = sizeof(net_message_buffer); 299 net_message.data = net_message_buffer; 300 301 // 302 // determine my name & address 303 // 304 NET_GetLocalAddress (); 305 306 Con_Printf("UDP Initialized\n"); 307} 308 309/* 310==================== 311NET_Shutdown 312==================== 313*/ 314void NET_Shutdown (void) 315{ 316 close (net_socket); 317} 318 319