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 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 46 netadr_t net_local_adr; 47 48 netadr_t net_from; 49 sizebuf_t net_message; 50 int net_socket; // non blocking, for receives 51 int net_send_socket; // blocking, for sends 52 53 #define MAX_UDP_PACKET 8192 54 byte net_message_buffer[MAX_UDP_PACKET]; 55 56 // int gethostname (char *, int); 57 int close (int); 58 59 //============================================================================= 60 61 void 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 70 void 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 76 qboolean 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 84 qboolean 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 91 char *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 100 char *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 ============= 111 NET_StringToAdr 112 113 idnewt 114 idnewt:28000 115 192.246.40.70 116 192.246.40.70:28000 117 ============= 118 */ 119 qboolean 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. 159 qboolean 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 191 qboolean 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 216 void 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 235 int 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 264 void 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 ==================== 285 NET_Init 286 ==================== 287 */ 288 void 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 ==================== 311 NET_Shutdown 312 ==================== 313 */ 314 void NET_Shutdown (void) 315 { 316 close (net_socket); 317 } 318 319