x86UNIXNet.cpp
Engine/source/platformX86UNIX/x86UNIXNet.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23#if 0 24 25#include "platformX86UNIX/platformX86UNIX.h" 26#include "platform/platform.h" 27#include "platform/event.h" 28#include "platform/platformNetAsync.h" 29 30#include <unistd.h> 31#include <sys/types.h> 32#include <sys/socket.h> 33#include <sys/poll.h> 34#include <arpa/inet.h> 35#include <netdb.h> 36#include <netinet/in.h> 37#include <errno.h> 38 39/* for PROTO_IPX */ 40#if defined(__linux__) 41#include <net/if_ppp.h> 42#include <sys/ioctl.h> /* ioctl() */ 43#include <net/ppp_defs.h> 44#elif defined(__OpenBSD__) || defined(__FreeBSD__) 45#include <sys/ioctl.h> /* ioctl() */ 46#include <net/ppp_defs.h> 47#endif 48 49#include <netipx/ipx.h> 50#include <stdlib.h> 51 52#include "console/console.h" 53#include "platform/gameInterface.h" 54#include "core/fileStream.h" 55#include "core/tVector.h" 56 57static Net::Error getLastError(); 58static S32 defaultPort = 28000; 59static S32 netPort = 0; 60static int ipxSocket = InvalidSocket; 61static int udpSocket = InvalidSocket; 62 63// local enum for socket states for polled sockets 64enum SocketState 65{ 66 InvalidState, 67 Connected, 68 ConnectionPending, 69 Listening, 70 NameLookupRequired 71}; 72 73// the Socket structure helps us keep track of the 74// above states 75struct Socket 76{ 77 Socket() 78 { 79 fd = InvalidSocket; 80 state = InvalidState; 81 remoteAddr[0] = 0; 82 remotePort = -1; 83 } 84 85 NetSocket fd; 86 S32 state; 87 char remoteAddr[256]; 88 S32 remotePort; 89}; 90 91// list of polled sockets 92static Vector<Socket*> gPolledSockets; 93 94static Socket* addPolledSocket(NetSocket& fd, S32 state, 95 char* remoteAddr = NULL, S32 port = -1) 96{ 97 Socket* sock = new Socket(); 98 sock->fd = fd; 99 sock->state = state; 100 if (remoteAddr) 101 dStrcpy(sock->remoteAddr, remoteAddr, 256); 102 if (port != -1) 103 sock->remotePort = port; 104 gPolledSockets.push_back(sock); 105 return sock; 106} 107 108enum { 109 MaxConnections = 1024, 110}; 111 112S32 Poll(NetSocket fd, S32 eventMask, S32 timeoutMs) 113{ 114 pollfd pfd; 115 S32 retVal; 116 pfd.fd = fd; 117 pfd.events = eventMask; 118 119 retVal = poll(&pfd, 1, timeoutMs); 120 return retVal; 121 if (retVal <= 0) 122 return retVal; 123 else 124 return pfd.revents; 125} 126 127bool Net::init() 128{ 129 NetAsync::startAsync(); 130 return(true); 131} 132 133void Net::shutdown() 134{ 135 while (gPolledSockets.size() > 0) 136 closeConnectTo(gPolledSockets[0]->fd); 137 138 closePort(); 139 NetAsync::stopAsync(); 140} 141 142static void netToIPSocketAddress(const NetAddress *address, struct sockaddr_in *sockAddr) 143{ 144 dMemset(sockAddr, 0, sizeof(struct sockaddr_in)); 145 sockAddr->sin_family = AF_INET; 146 sockAddr->sin_port = htons(address->port); 147 char tAddr[20]; 148 dSprintf(tAddr, 20, "%d.%d.%d.%d\n", address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3]); 149//fprintf(stdout,"netToIPSocketAddress(): %s\n",tAddr);fflush(NULL); 150 sockAddr->sin_addr.s_addr = inet_addr(tAddr); 151// sockAddr->sin_addr.s_addr = address->netNum[0]; // hopefully this will work. 152} 153 154static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address) 155{ 156 address->type = NetAddress::IPAddress; 157 address->port = htons(sockAddr->sin_port); 158 char *tAddr; 159 tAddr = inet_ntoa(sockAddr->sin_addr); 160//fprintf(stdout,"IPSocketToNetAddress(): %s\n",tAddr);fflush(NULL); 161 U8 nets[4]; 162 nets[0] = atoi(strtok(tAddr, ".")); 163 nets[1] = atoi(strtok(NULL, ".")); 164 nets[2] = atoi(strtok(NULL, ".")); 165 nets[3] = atoi(strtok(NULL, ".")); 166//fprintf(stdout,"0 = %d, 1 = %d, 2 = %d, 3 = %d\n", nets[0], nets[1], nets[2], nets[3]); 167 address->netNum[0] = nets[0]; 168 address->netNum[1] = nets[1]; 169 address->netNum[2] = nets[2]; 170 address->netNum[3] = nets[3]; 171} 172 173static void netToIPXSocketAddress(const NetAddress *address, sockaddr_ipx *sockAddr) 174{ 175#if !defined(__FreeBSD__) 176 dMemset(sockAddr, 0, sizeof(sockaddr_ipx)); 177 sockAddr->sipx_family = AF_INET; 178 sockAddr->sipx_port = htons(address->port); 179 sockAddr->sipx_network = address->netNum[0]; 180 sockAddr->sipx_node[0] = address->nodeNum[0]; 181 sockAddr->sipx_node[1] = address->nodeNum[1]; 182 sockAddr->sipx_node[2] = address->nodeNum[2]; 183 sockAddr->sipx_node[3] = address->nodeNum[3]; 184 sockAddr->sipx_node[4] = address->nodeNum[4]; 185 sockAddr->sipx_node[5] = address->nodeNum[5]; 186#endif 187} 188 189static void IPXSocketToNetAddress(const sockaddr_ipx *sockAddr, NetAddress *address) 190{ 191#if !defined(__FreeBSD__) 192 address->type = NetAddress::IPXAddress; 193 address->port = htons(sockAddr->sipx_port); 194 address->netNum[0] = sockAddr->sipx_network; 195 address->nodeNum[0] = sockAddr->sipx_node[0]; 196 address->nodeNum[1] = sockAddr->sipx_node[1]; 197 address->nodeNum[2] = sockAddr->sipx_node[2]; 198 address->nodeNum[3] = sockAddr->sipx_node[3]; 199 address->nodeNum[4] = sockAddr->sipx_node[4]; 200 address->nodeNum[5] = sockAddr->sipx_node[5]; 201#endif 202} 203 204NetSocket Net::openListenPort(U16 port) 205{ 206 if(Game->isJournalReading()) 207 { 208 U32 ret; 209 Game->journalRead(&ret); 210 return NetSocket(ret); 211 } 212 NetSocket sock = openSocket(); 213 if (sock == InvalidSocket) 214 { 215 Con::errorf("Unable to open listen socket: %s", strerror(errno)); 216 return InvalidSocket; 217 } 218 219 if (bind(sock, port) != NoError) 220 { 221 Con::errorf("Unable to bind port %d: %s", port, strerror(errno)); 222 ::close(sock); 223 return InvalidSocket; 224 } 225 if (listen(sock, 4) != NoError) 226 { 227 Con::errorf("Unable to listen on port %d: %s", port, strerror(errno)); 228 ::close(sock); 229 return InvalidSocket; 230 } 231 232 setBlocking(sock, false); 233 addPolledSocket(sock, Listening); 234 if (Game->isJournalWriting()) 235 Game->journalWrite(U32(sock)); 236 return sock; 237} 238 239NetSocket Net::openConnectTo(const char *addressString) 240{ 241 if(!dStrnicmp(addressString, "ipx:", 4)) 242 return InvalidSocket; 243 if(!dStrnicmp(addressString, "ip:", 3)) 244 addressString += 3; // eat off the ip: 245 char remoteAddr[256]; 246 dStrcpy(remoteAddr, addressString, 256); 247 248 char *portString = dStrchr(remoteAddr, ':'); 249 250 U16 port; 251 if(portString) 252 { 253 *portString++ = 0; 254 port = htons(dAtoi(portString)); 255 } 256 else 257 port = htons(defaultPort); 258 259 if(!dStricmp(remoteAddr, "broadcast")) 260 return InvalidSocket; 261 262 if(Game->isJournalReading()) 263 { 264 U32 ret; 265 Game->journalRead(&ret); 266 return NetSocket(ret); 267 } 268 NetSocket sock = openSocket(); 269 setBlocking(sock, false); 270 271 sockaddr_in ipAddr; 272 dMemset(&ipAddr, 0, sizeof(ipAddr)); 273 274 if (inet_aton(remoteAddr, &ipAddr.sin_addr) != 0) 275 { 276 ipAddr.sin_port = port; 277 ipAddr.sin_family = AF_INET; 278 if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1 && 279 errno != EINPROGRESS) 280 { 281 Con::errorf("Error connecting %s: %s", 282 addressString, strerror(errno)); 283 ::close(sock); 284 sock = InvalidSocket; 285 } 286 if(sock != InvalidSocket) { 287 // add this socket to our list of polled sockets 288 addPolledSocket(sock, ConnectionPending); 289 } 290 } 291 else 292 { 293 // need to do an asynchronous name lookup. first, add the socket 294 // to the polled list 295 addPolledSocket(sock, NameLookupRequired, remoteAddr, port); 296 // queue the lookup 297 gNetAsync.queueLookup(remoteAddr, sock); 298 } 299 if(Game->isJournalWriting()) 300 Game->journalWrite(U32(sock)); 301 return sock; 302} 303 304void Net::closeConnectTo(NetSocket sock) 305{ 306 if(Game->isJournalReading()) 307 return; 308 309 // if this socket is in the list of polled sockets, remove it 310 for (int i = 0; i < gPolledSockets.size(); ++i) 311 if (gPolledSockets[i]->fd == sock) 312 { 313 delete gPolledSockets[i]; 314 gPolledSockets.erase(i); 315 break; 316 } 317 318 closeSocket(sock); 319} 320 321Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, int bufferSize) 322{ 323 if(Game->isJournalReading()) 324 { 325 U32 e; 326 Game->journalRead(&e); 327 328 return (Net::Error) e; 329 } 330 Net::Error e = send(socket, buffer, bufferSize); 331 if(Game->isJournalWriting()) 332 Game->journalWrite(U32(e)); 333 return e; 334} 335 336bool Net::openPort(S32 port) 337{ 338 if(udpSocket != InvalidSocket) 339 close(udpSocket); 340 if(ipxSocket != InvalidSocket) 341 close(ipxSocket); 342 343 udpSocket = socket(AF_INET, SOCK_DGRAM, 0); 344 ipxSocket = socket(AF_IPX, SOCK_DGRAM, 0); 345 346 if(udpSocket != InvalidSocket) 347 { 348 Net::Error error; 349 error = bind(udpSocket, port); 350 if(error == NoError) 351 error = setBufferSize(udpSocket, 32768); 352 if(error == NoError) 353 error = setBroadcast(udpSocket, true); 354 if(error == NoError) 355 error = setBlocking(udpSocket, false); 356 if(error == NoError) 357 Con::printf("UDP initialized on port %d", port); 358 else 359 { 360 close(udpSocket); 361 udpSocket = InvalidSocket; 362 Con::printf("Unable to initialize UDP - error %d", error); 363 } 364 } 365 if(ipxSocket != InvalidSocket) 366 { 367 Net::Error error = NoError; 368 sockaddr_ipx ipxAddress; 369 memset((char *)&ipxAddress, 0, sizeof(ipxAddress)); 370 ipxAddress.sipx_family = AF_IPX; 371 ipxAddress.sipx_port = htons(port); 372 S32 err = ::bind(ipxSocket, (struct sockaddr *)&ipxAddress, sizeof(ipxAddress)); 373 if(err) 374 error = getLastError(); 375 if(error == NoError) 376 error = setBufferSize(ipxSocket, 32768); 377 if(error == NoError) 378 error = setBroadcast(ipxSocket, true); 379 if(error == NoError) 380 error = setBlocking(ipxSocket, false); 381 if(error == NoError) 382 Con::printf("IPX initialized on port %d", port); 383 else 384 { 385 close(ipxSocket); 386 ipxSocket = InvalidSocket; 387 Con::printf("Unable to initialize IPX - error %d", error); 388 } 389 } 390 netPort = port; 391 return ipxSocket != InvalidSocket || udpSocket != InvalidSocket; 392} 393 394void Net::closePort() 395{ 396 if(ipxSocket != InvalidSocket) 397 close(ipxSocket); 398 if(udpSocket != InvalidSocket) 399 close(udpSocket); 400} 401 402Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize) 403{ 404 if(Game->isJournalReading()) 405 return NoError; 406 407 if(address->type == NetAddress::IPXAddress) 408 { 409 sockaddr_ipx ipxAddr; 410 netToIPXSocketAddress(address, &ipxAddr); 411 if(::sendto(ipxSocket, (const char*)buffer, bufferSize, 0, 412 (sockaddr *) &ipxAddr, sizeof(sockaddr_ipx)) == -1) 413 return getLastError(); 414 else 415 return NoError; 416 } 417 else 418 { 419 sockaddr_in ipAddr; 420 netToIPSocketAddress(address, &ipAddr); 421 if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0, 422 (sockaddr *) &ipAddr, sizeof(sockaddr_in)) == -1) 423 return getLastError(); 424 else 425 return NoError; 426 } 427} 428 429void Net::process() 430{ 431 sockaddr sa; 432 433 PacketReceiveEvent receiveEvent; 434 for(;;) 435 { 436 U32 addrLen = sizeof(sa); 437 S32 bytesRead = -1; 438 if(udpSocket != InvalidSocket) 439 bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen); 440 if(bytesRead == -1 && ipxSocket != InvalidSocket) 441 { 442 addrLen = sizeof(sa); 443 bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen); 444 } 445 446 if(bytesRead == -1) 447 break; 448 449 if(sa.sa_family == AF_INET) 450 IPSocketToNetAddress((sockaddr_in *) &sa, &receiveEvent.sourceAddress); 451 else if(sa.sa_family == AF_IPX) 452 IPXSocketToNetAddress((sockaddr_ipx *) &sa, &receiveEvent.sourceAddress); 453 else 454 continue; 455 456 NetAddress &na = receiveEvent.sourceAddress; 457 if(na.type == NetAddress::IPAddress && 458 na.netNum[0] == 127 && 459 na.netNum[1] == 0 && 460 na.netNum[2] == 0 && 461 na.netNum[3] == 1 && 462 na.port == netPort) 463 continue; 464 if(bytesRead <= 0) 465 continue; 466 receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead; 467 Game->postEvent(receiveEvent); 468 } 469 470 // process the polled sockets. This blob of code performs functions 471 // similar to WinsockProc in winNet.cc 472 473 if (gPolledSockets.size() == 0) 474 return; 475 476 static ConnectedNotifyEvent notifyEvent; 477 static ConnectedAcceptEvent acceptEvent; 478 static ConnectedReceiveEvent cReceiveEvent; 479 480 S32 optval; 481 socklen_t optlen = sizeof(S32); 482 S32 bytesRead; 483 Net::Error err; 484 bool removeSock = false; 485 Socket *currentSock = NULL; 486 sockaddr_in ipAddr; 487 NetSocket incoming = InvalidSocket; 488 char out_h_addr[1024]; 489 int out_h_length = 0; 490 491 for (S32 i = 0; i < gPolledSockets.size(); 492 /* no increment, this is done at end of loop body */) 493 { 494 removeSock = false; 495 currentSock = gPolledSockets[i]; 496 switch (currentSock->state) 497 { 498 case InvalidState: 499 Con::errorf("Error, InvalidState socket in polled sockets list"); 500 break; 501 case ConnectionPending: 502 notifyEvent.tag = currentSock->fd; 503 // see if it is now connected 504 if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR, 505 &optval, &optlen) == -1) 506 { 507 Con::errorf("Error getting socket options: %s", strerror(errno)); 508 notifyEvent.state = ConnectedNotifyEvent::ConnectFailed; 509 Game->postEvent(notifyEvent); 510 removeSock = true; 511 } 512 else 513 { 514 if (optval == EINPROGRESS) 515 // still connecting... 516 break; 517 518 if (optval == 0) 519 { 520 // connected 521 notifyEvent.state = ConnectedNotifyEvent::Connected; 522 Game->postEvent(notifyEvent); 523 currentSock->state = Connected; 524 } 525 else 526 { 527 // some kind of error 528 Con::errorf("Error connecting: %s", strerror(errno)); 529 notifyEvent.state = ConnectedNotifyEvent::ConnectFailed; 530 Game->postEvent(notifyEvent); 531 removeSock = true; 532 } 533 } 534 break; 535 case Connected: 536 bytesRead = 0; 537 // try to get some data 538 err = Net::recv(currentSock->fd, cReceiveEvent.data, 539 MaxPacketDataSize, &bytesRead); 540 if(err == Net::NoError) 541 { 542 if (bytesRead > 0) 543 { 544 // got some data, post it 545 cReceiveEvent.tag = currentSock->fd; 546 cReceiveEvent.size = ConnectedReceiveEventHeaderSize + 547 bytesRead; 548 Game->postEvent(cReceiveEvent); 549 } 550 else 551 { 552 // zero bytes read means EOF 553 if (bytesRead < 0) 554 // ack! this shouldn't happen 555 Con::errorf("Unexpected error on socket: %s", 556 strerror(errno)); 557 558 notifyEvent.tag = currentSock->fd; 559 notifyEvent.state = ConnectedNotifyEvent::Disconnected; 560 Game->postEvent(notifyEvent); 561 removeSock = true; 562 } 563 } 564 else if (err != Net::NoError && err != Net::WouldBlock) 565 { 566 Con::errorf("Error reading from socket: %s", strerror(errno)); 567 notifyEvent.tag = currentSock->fd; 568 notifyEvent.state = ConnectedNotifyEvent::Disconnected; 569 Game->postEvent(notifyEvent); 570 removeSock = true; 571 } 572 break; 573 case NameLookupRequired: 574 // is the lookup complete? 575 if (!gNetAsync.checkLookup( 576 currentSock->fd, out_h_addr, &out_h_length, 577 sizeof(out_h_addr))) 578 break; 579 580 notifyEvent.tag = currentSock->fd; 581 if (out_h_length == -1) 582 { 583 Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr); 584 notifyEvent.state = ConnectedNotifyEvent::DNSFailed; 585 removeSock = true; 586 } 587 else 588 { 589 // try to connect 590 dMemcpy(&(ipAddr.sin_addr.s_addr), out_h_addr, out_h_length); 591 ipAddr.sin_port = currentSock->remotePort; 592 ipAddr.sin_family = AF_INET; 593 if(::connect(currentSock->fd, (struct sockaddr *)&ipAddr, 594 sizeof(ipAddr)) == -1) 595 { 596 if (errno == EINPROGRESS) 597 { 598 notifyEvent.state = ConnectedNotifyEvent::DNSResolved; 599 currentSock->state = ConnectionPending; 600 } 601 else 602 { 603 Con::errorf("Error connecting to %s: %s", 604 currentSock->remoteAddr, strerror(errno)); 605 notifyEvent.state = ConnectedNotifyEvent::ConnectFailed; 606 removeSock = true; 607 } 608 } 609 else 610 { 611 notifyEvent.state = ConnectedNotifyEvent::Connected; 612 currentSock->state = Connected; 613 } 614 } 615 Game->postEvent(notifyEvent); 616 break; 617 case Listening: 618 incoming = 619 Net::accept(currentSock->fd, &acceptEvent.address); 620 if(incoming != InvalidSocket) 621 { 622 acceptEvent.portTag = currentSock->fd; 623 acceptEvent.connectionTag = incoming; 624 setBlocking(incoming, false); 625 addPolledSocket(incoming, Connected); 626 Game->postEvent(acceptEvent); 627 } 628 break; 629 } 630 631 // only increment index if we're not removing the connection, since 632 // the removal will shift the indices down by one 633 if (removeSock) 634 closeConnectTo(currentSock->fd); 635 else 636 i++; 637 } 638} 639 640NetSocket Net::openSocket() 641{ 642 int retSocket; 643 retSocket = socket(AF_INET, SOCK_STREAM, 0); 644 645 if(retSocket == InvalidSocket) 646 return InvalidSocket; 647 else 648 return retSocket; 649} 650 651Net::Error Net::closeSocket(NetSocket socket) 652{ 653 if(socket != InvalidSocket) 654 { 655 if(!close(socket)) 656 return NoError; 657 else 658 return getLastError(); 659 } 660 else 661 return NotASocket; 662} 663 664Net::Error Net::connect(NetSocket socket, const NetAddress *address) 665{ 666 if(address->type != NetAddress::IPAddress) 667 return WrongProtocolType; 668 sockaddr_in socketAddress; 669 netToIPSocketAddress(address, &socketAddress); 670 if(!::connect(socket, (sockaddr *) &socketAddress, sizeof(socketAddress))) 671 return NoError; 672 return getLastError(); 673} 674 675Net::Error Net::listen(NetSocket socket, S32 backlog) 676{ 677 if(!::listen(socket, backlog)) 678 return NoError; 679 return getLastError(); 680} 681 682NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress) 683{ 684 sockaddr_in socketAddress; 685 U32 addrLen = sizeof(socketAddress); 686 687 int retVal = ::accept(acceptSocket, (sockaddr *) &socketAddress, &addrLen); 688 if(retVal != InvalidSocket) 689 { 690 IPSocketToNetAddress(&socketAddress, remoteAddress); 691 return retVal; 692 } 693 return InvalidSocket; 694} 695 696Net::Error Net::bind(NetSocket socket, U16 port) 697{ 698 S32 error; 699 700 sockaddr_in socketAddress; 701 dMemset((char *)&socketAddress, 0, sizeof(socketAddress)); 702 socketAddress.sin_family = AF_INET; 703 // It's entirely possible that there are two NIC cards. 704 // We let the user specify which one the server runs on. 705 706 // thanks to [TPG]P1aGu3 for the name 707 const char* serverIP = Con::getVariable( "Pref::Net::BindAddress" ); 708 // serverIP is guaranteed to be non-0. 709 AssertFatal( serverIP, "serverIP is NULL!" ); 710 711 if( serverIP[0] != '\0' ) { 712 // we're not empty 713 socketAddress.sin_addr.s_addr = inet_addr( serverIP ); 714 715 if( socketAddress.sin_addr.s_addr != INADDR_NONE ) { 716 Con::printf( "Binding server port to %s", serverIP ); 717 } else { 718 Con::warnf( ConsoleLogEntry::General, 719 "inet_addr() failed for %s while binding!", 720 serverIP ); 721 socketAddress.sin_addr.s_addr = INADDR_ANY; 722 } 723 724 } else { 725 Con::printf( "Binding server port to default IP" ); 726 socketAddress.sin_addr.s_addr = INADDR_ANY; 727 } 728 729 socketAddress.sin_port = htons(port); 730 error = ::bind(socket, (sockaddr *) &socketAddress, sizeof(socketAddress)); 731 732 if(!error) 733 return NoError; 734 return getLastError(); 735} 736 737Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize) 738{ 739 S32 error; 740 error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize)); 741 if(!error) 742 error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize)); 743 if(!error) 744 return NoError; 745 return getLastError(); 746} 747 748Net::Error Net::setBroadcast(NetSocket socket, bool broadcast) 749{ 750 S32 bc = broadcast; 751 S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc)); 752 if(!error) 753 return NoError; 754 return getLastError(); 755} 756 757Net::Error Net::setBlocking(NetSocket socket, bool blockingIO) 758{ 759 int notblock = !blockingIO; 760 S32 error = ioctl(socket, FIONBIO, ¬block); 761 if(!error) 762 return NoError; 763 return getLastError(); 764} 765 766Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize) 767{ 768 // Poll for write status. this blocks. should really 769 // do this in a separate thread or set it up so that the data can 770 // get queued and sent later 771 // JMQTODO 772 Poll(socket, POLLOUT, 10000); 773 774 S32 error = ::send(socket, (const char*)buffer, bufferSize, 0); 775 if(error != -1) 776 return NoError; 777 778 return getLastError(); 779} 780 781Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead) 782{ 783 *bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0); 784 if(*bytesRead == -1) 785 return getLastError(); 786 return NoError; 787} 788 789bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2) 790{ 791 if((a1->type != a2->type) || 792 (*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) || 793 (a1->port != a2->port)) 794 return false; 795 796 if(a1->type == NetAddress::IPAddress) 797 return true; 798 for(S32 i = 0; i < 6; i++) 799 if(a1->nodeNum[i] != a2->nodeNum[i]) 800 return false; 801 return true; 802} 803 804bool Net::stringToAddress(const char *addressString, NetAddress *address) 805{ 806 if(dStrnicmp(addressString, "ipx:", 4)) 807 { 808 // assume IP if it doesn't have ipx: at the front. 809 810 if(!dStrnicmp(addressString, "ip:", 3)) 811 addressString += 3; // eat off the ip: 812 813 sockaddr_in ipAddr; 814 char remoteAddr[256]; 815 if(strlen(addressString) > 255) 816 return false; 817 818 dStrcpy(remoteAddr, addressString, 256); 819 820 char *portString = dStrchr(remoteAddr, ':'); 821 if(portString) 822 *portString++ = '\0'; 823 824 struct hostent *hp; 825 if(!dStricmp(remoteAddr, "broadcast")) 826 ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); 827 else 828 { 829 if (inet_aton(remoteAddr,&ipAddr.sin_addr) == 0) // error 830 { 831 if((hp = gethostbyname(remoteAddr)) == 0) 832 return false; 833 else 834 memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr)); 835 } 836 } 837 if(portString) 838 ipAddr.sin_port = htons(dAtoi(portString)); 839 else 840 ipAddr.sin_port = htons(defaultPort); 841 ipAddr.sin_family = AF_INET; 842 IPSocketToNetAddress(&ipAddr, address); 843 return true; 844 } 845 else 846 { 847 S32 i; 848 S32 port; 849 850 address->type = NetAddress::IPXAddress; 851 for(i = 0; i < 6; i++) 852 address->nodeNum[i] = 0xFF; 853 854 // it's an IPX string 855 addressString += 4; 856 if(!dStricmp(addressString, "broadcast")) 857 { 858 address->port = defaultPort; 859 return true; 860 } 861 else if(sscanf(addressString, "broadcast:%d", &port) == 1) 862 { 863 address->port = port; 864 return true; 865 } 866 else 867 { 868 S32 nodeNum[6]; 869 S32 netNum[4]; 870 S32 count = dSscanf(addressString, "%2x%2x%2x%2x:%2x%2x%2x%2x%2x%2x:%d", 871 &netNum[0], &netNum[1], &netNum[2], &netNum[3], 872 &nodeNum[0], &nodeNum[1], &nodeNum[2], &nodeNum[3], &nodeNum[4], &nodeNum[5], 873 &port); 874 875 if(count == 10) 876 { 877 port = defaultPort; 878 count++; 879 } 880 if(count != 11) 881 return false; 882 883 for(i = 0; i < 6; i++) 884 address->nodeNum[i] = nodeNum[i]; 885 for(i = 0; i < 4; i++) 886 address->netNum[i] = netNum[i]; 887 address->port = port; 888 return true; 889 } 890 } 891} 892 893void Net::addressToString(const NetAddress *address, char addressString[256]) 894{ 895 if(address->type == NetAddress::IPAddress) 896 { 897 sockaddr_in ipAddr; 898 netToIPSocketAddress(address, &ipAddr); 899 900 if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST)) 901 dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port)); 902 else 903 dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr), 904 ntohs(ipAddr.sin_port)); 905// dSprintf(addressString, 256, "IP:%d:%d", ipAddr.sin_addr.s_addr, 906// ntohs(ipAddr.sin_port)); 907 } 908 else 909 { 910 return; 911 dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d", 912 address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3], 913 address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5], 914 address->port); 915 } 916} 917 918Net::Error getLastError() 919{ 920 if (errno == EAGAIN) 921 return Net::WouldBlock; 922 return Net::UnknownError; 923} 924 925#endif 926