net.c

Go to the documentation of this file.
00001 
00009 /*
00010 Copyright (C) 2002-2010 UFO: Alien Invasion.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 #include "common.h"
00030 #include <errno.h>
00031 #include <string.h>
00032 #include <fcntl.h>
00033 #include <unistd.h>
00034 
00035 #ifdef _WIN32
00036 #include "../ports/system.h"
00037 #endif
00038 
00039 #define MAX_STREAMS 56
00040 #define MAX_DATAGRAM_SOCKETS 7
00041 
00042 struct memPool_s *com_networkPool;
00043 
00044 #ifdef _WIN32
00045 # include <winsock2.h>
00046 # include <ws2tcpip.h>
00047 # if WINVER < 0x501
00048 #  include <wspiapi.h>
00049 # else
00050 #  include <ws2spi.h>
00051 # endif
00052 # define netError WSAGetLastError()
00053 # define netStringError netStringErrorWin
00054 # define netCloseSocket closesocket
00055 # define gai_strerrorA netStringErrorWin
00056 
00057 #else /* WIN32 */
00058 
00059 # include <sys/ioctl.h>
00060 # include <sys/select.h>
00061 # include <sys/types.h>
00062 # include <sys/socket.h>
00063 # include <sys/time.h>
00064 # include <netdb.h>
00065 # include <arpa/inet.h>
00066 # include <netinet/in.h>
00067 # include <signal.h>
00068 typedef int SOCKET;
00069 # define INVALID_SOCKET (-1)
00070 # define netError errno
00071 # define netStringError strerror
00072 # define netCloseSocket close
00073 # define ioctlsocket ioctl
00074 #endif /* WIN32 */
00075 
00081 #ifndef AI_NUMERICSERV
00082 #define AI_NUMERICSERV 0
00083 #endif
00084 #ifndef AI_ADDRCONFIG
00085 #define AI_ADDRCONFIG 0
00086 #endif
00087 
00092 #define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
00093 
00094 static cvar_t* net_ipv4;
00095 
00096 struct net_stream {
00097     void *data;
00098 
00099     qboolean loopback;
00100     qboolean ready;
00101     qboolean closed;
00102     qboolean finished;      
00103     int socket;
00104     int index;
00105     int family;
00106     int addrlen;
00107 
00108     struct dbuffer *inbound;
00109     struct dbuffer *outbound;
00110 
00111     stream_callback_func *func;
00112     struct net_stream *loopback_peer;
00113 };
00114 
00115 struct datagram {
00116     int len;
00117     char *msg;
00118     char *addr;
00119     struct datagram *next;
00120 };
00121 
00122 struct datagram_socket {
00123     int socket;
00124     int index;
00125     int family;
00126     int addrlen;
00127     struct datagram *queue;
00128     struct datagram **queue_tail;
00129     datagram_callback_func *func;
00130 };
00131 
00132 static fd_set read_fds;
00133 static fd_set write_fds;
00134 static int maxfd;
00135 static struct net_stream *streams[MAX_STREAMS];
00136 static struct datagram_socket *datagram_sockets[MAX_DATAGRAM_SOCKETS];
00137 
00138 static qboolean loopback_ready = qfalse;
00139 static qboolean server_running = qfalse;
00140 static stream_callback_func *server_func = NULL;
00141 static int server_socket = INVALID_SOCKET;
00142 static int server_family, server_addrlen;
00143 
00144 #ifdef _WIN32
00145 static const char *netStringErrorWin (int code)
00146 {
00147     switch (code) {
00148     case WSAEINTR: return "WSAEINTR";
00149     case WSAEBADF: return "WSAEBADF";
00150     case WSAEACCES: return "WSAEACCES";
00151     case WSAEDISCON: return "WSAEDISCON";
00152     case WSAEFAULT: return "WSAEFAULT";
00153     case WSAEINVAL: return "WSAEINVAL";
00154     case WSAEMFILE: return "WSAEMFILE";
00155     case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
00156     case WSAEINPROGRESS: return "WSAEINPROGRESS";
00157     case WSAEALREADY: return "WSAEALREADY";
00158     case WSAENOTSOCK: return "WSAENOTSOCK";
00159     case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
00160     case WSAEMSGSIZE: return "WSAEMSGSIZE";
00161     case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
00162     case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
00163     case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
00164     case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
00165     case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
00166     case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
00167     case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
00168     case WSAEADDRINUSE: return "WSAEADDRINUSE";
00169     case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
00170     case WSAENETDOWN: return "WSAENETDOWN";
00171     case WSAENETUNREACH: return "WSAENETUNREACH";
00172     case WSAENETRESET: return "WSAENETRESET";
00173     case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
00174     case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH";
00175     case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
00176     case WSAECONNRESET: return "WSAECONNRESET";
00177     case WSAENOBUFS: return "WSAENOBUFS";
00178     case WSAEISCONN: return "WSAEISCONN";
00179     case WSAENOTCONN: return "WSAENOTCONN";
00180     case WSAESHUTDOWN: return "WSAESHUTDOWN";
00181     case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
00182     case WSAETIMEDOUT: return "WSAETIMEDOUT";
00183     case WSAECONNREFUSED: return "WSAECONNREFUSED";
00184     case WSAELOOP: return "WSAELOOP";
00185     case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
00186     case WSASYSNOTREADY: return "WSASYSNOTREADY";
00187     case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
00188     case WSANOTINITIALISED: return "WSANOTINITIALISED";
00189     case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
00190     case WSATRY_AGAIN: return "WSATRY_AGAIN";
00191     case WSANO_RECOVERY: return "WSANO_RECOVERY";
00192     case WSANO_DATA: return "WSANO_DATA";
00193     default: return "NO ERROR";
00194     }
00195 }
00196 #endif
00197 
00204 static int NET_StreamGetFree (void)
00205 {
00206     static int start = 0;
00207     int i;
00208 
00209     for (i = 0; i < MAX_STREAMS; i++) {
00210         const int pos = (i + start) % MAX_STREAMS;
00211         if (streams[pos] == NULL) {
00212             start = (pos + 1) % MAX_STREAMS;
00213             Com_DPrintf(DEBUG_SERVER, "New stream at index: %i\n", pos);
00214             return pos;
00215         }
00216     }
00217     return -1;
00218 }
00219 
00223 static int NET_DatagramFindFreeSocket (void)
00224 {
00225     static int start = 0;
00226     int i;
00227 
00228     for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++) {
00229         const int pos = (i + start) % MAX_DATAGRAM_SOCKETS;
00230         if (datagram_sockets[pos] == NULL) {
00231             start = (pos + 1) % MAX_DATAGRAM_SOCKETS;
00232             Com_DPrintf(DEBUG_SERVER, "New datagram at index: %i\n", pos);
00233             return pos;
00234         }
00235     }
00236     return -1;
00237 }
00238 
00243 static struct net_stream *NET_StreamNew (int index)
00244 {
00245     struct net_stream *s = Mem_PoolAlloc(sizeof(*s), com_networkPool, 0);
00246     s->data = NULL;
00247     s->loopback_peer = NULL;
00248     s->loopback = qfalse;
00249     s->closed = qfalse;
00250     s->finished = qfalse;
00251     s->ready = qfalse;
00252     s->socket = INVALID_SOCKET;
00253     s->inbound = NULL;
00254     s->outbound = NULL;
00255     s->index = index;
00256     s->family = 0;
00257     s->addrlen = 0;
00258     s->func = NULL;
00259     if (streams[index])
00260         NET_StreamFree(streams[index]);
00261     streams[index] = s;
00262     return s;
00263 }
00264 
00265 static void NET_ShowStreams_f (void)
00266 {
00267     int i;
00268     char buf[256];
00269     int cnt = 0;
00270 
00271     for (i = 0; i < MAX_STREAMS; i++) {
00272         if (streams[i] != NULL) {
00273             Com_Printf("Steam %i is opened: %s on socket %i (closed: %i, finished: %i, outbound: "UFO_SIZE_T", inbound: "UFO_SIZE_T")\n", i,
00274                 NET_StreamPeerToName(streams[i], buf, sizeof(buf), qtrue),
00275                 streams[i]->socket, streams[i]->closed, streams[i]->finished,
00276                 dbuffer_len(streams[i]->outbound), dbuffer_len(streams[i]->inbound));
00277             cnt++;
00278         }
00279     }
00280     Com_Printf("%i/%i streams opened\n", cnt, MAX_STREAMS);
00281 }
00282 
00287 void NET_Init (void)
00288 {
00289     int i;
00290 #ifdef _WIN32
00291     WSADATA winsockdata;
00292 #endif
00293 
00294     Com_Printf("\n----- network initialization -------\n");
00295 
00296 #ifdef _WIN32
00297     if (WSAStartup(MAKEWORD(2, 0), &winsockdata) != 0)
00298         Com_Error(ERR_FATAL, "Winsock initialization failed.");
00299 #endif
00300 
00301     maxfd = 0;
00302     FD_ZERO(&read_fds);
00303     FD_ZERO(&write_fds);
00304 
00305     for (i = 0; i < MAX_STREAMS; i++)
00306         streams[i] = NULL;
00307     for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++)
00308         datagram_sockets[i] = NULL;
00309 
00310 #ifndef _WIN32
00311     signal(SIGPIPE, SIG_IGN);
00312 #endif
00313 
00314     dbuffer_init();
00315 
00316     net_ipv4 = Cvar_Get("net_ipv4", "1", CVAR_ARCHIVE, "Only use ipv4");
00317     Cmd_AddCommand("net_showstreams", NET_ShowStreams_f, "Show opened streams");
00318 }
00319 
00323 void NET_Shutdown (void)
00324 {
00325 #ifdef _WIN32
00326     WSACleanup();
00327 #endif
00328     dbuffer_shutdown();
00329 }
00330 
00335 static void NET_StreamClose (struct net_stream *s)
00336 {
00337     if (!s || s->closed)
00338         return;
00339 
00340     if (s->socket != INVALID_SOCKET) {
00341         if (dbuffer_len(s->outbound))
00342             Com_Printf("The outbound buffer for this socket (%d) is not empty\n", s->socket);
00343         else if (dbuffer_len(s->inbound))
00344             Com_Printf("The inbound buffer for this socket (%d) is not empty\n", s->socket);
00345 
00346         FD_CLR(s->socket, &read_fds);
00347         FD_CLR(s->socket, &write_fds);
00348         netCloseSocket(s->socket);
00349         s->socket = INVALID_SOCKET;
00350     }
00351     if (s->index >= 0)
00352         streams[s->index] = NULL;
00353 
00354     if (s->loopback_peer) {
00355         /* Detach the peer, so that it won't send us anything more */
00356         s->loopback_peer->outbound = NULL;
00357         s->loopback_peer->loopback_peer = NULL;
00358     }
00359 
00360     s->closed = qtrue;
00361     Com_DPrintf(DEBUG_SERVER, "Close stream at index: %i\n", s->index);
00362 
00363     /* If we have a loopback peer, don't free the outbound buffer,
00364      * because it's our peer's inbound buffer */
00365     if (!s->loopback_peer)
00366         free_dbuffer(s->outbound);
00367 
00368     s->outbound = NULL;
00369     s->socket = INVALID_SOCKET;
00370 
00371     /* Note that this is potentially invalid after the callback returns */
00372     if (s->finished) {
00373         free_dbuffer(s->inbound);
00374         Mem_Free(s);
00375     } else if (s->func)
00376         s->func(s);
00377 }
00378 
00379 static void do_accept (int sock)
00380 {
00381     const int index = NET_StreamGetFree();
00382     struct net_stream *s;
00383     if (index == -1) {
00384         Com_Printf("Too many streams open, rejecting inbound connection\n");
00385         netCloseSocket(sock);
00386         return;
00387     }
00388 
00389     s = NET_StreamNew(index);
00390     s->socket = sock;
00391     s->inbound = new_dbuffer();
00392     s->outbound = new_dbuffer();
00393     s->family = server_family;
00394     s->addrlen = server_addrlen;
00395     s->func = server_func;
00396 
00397     maxfd = max(sock + 1, maxfd);
00398     FD_SET(sock, &read_fds);
00399 
00400     server_func(s);
00402 }
00403 
00407 void NET_Wait (int timeout)
00408 {
00409     struct timeval tv;
00410     int ready;
00411     int i;
00412 
00413     fd_set read_fds_out;
00414     fd_set write_fds_out;
00415 
00416     memcpy(&read_fds_out, &read_fds, sizeof(read_fds_out));
00417     memcpy(&write_fds_out, &write_fds, sizeof(write_fds_out));
00418 
00419     /* select() won't notice that loopback streams are ready, so we'll
00420      * eliminate the delay directly */
00421     if (loopback_ready)
00422         timeout = 0;
00423 
00424     tv.tv_sec = timeout / 1000;
00425     tv.tv_usec = 1000 * (timeout % 1000);
00426 #ifdef _WIN32
00427     if (read_fds_out.fd_count == 0) {
00428         Sys_Sleep(timeout);
00429         ready = 0;
00430     } else
00431 #endif
00432         ready = select(maxfd, &read_fds_out, &write_fds_out, NULL, &tv);
00433 
00434     if (ready == -1) {
00435         Com_Printf("select failed: %s\n", netStringError(netError));
00436         return;
00437     }
00438 
00439     if (ready == 0 && !loopback_ready)
00440         return;
00441 
00442     if (server_socket != INVALID_SOCKET && FD_ISSET(server_socket, &read_fds_out)) {
00443         const int client_socket = accept(server_socket, NULL, 0);
00444         if (client_socket == INVALID_SOCKET) {
00445             if (errno != EAGAIN)
00446                 Com_Printf("accept on socket %d failed: %s\n", server_socket, netStringError(netError));
00447         } else
00448             do_accept(client_socket);
00449     }
00450 
00451     for (i = 0; i < MAX_STREAMS; i++) {
00452         struct net_stream *s = streams[i];
00453 
00454         if (!s)
00455             continue;
00456 
00457         if (s->loopback) {
00458             /* If the peer is gone and the buffer is empty, close the stream */
00459             if (!s->loopback_peer && NET_StreamGetLength(s) == 0) {
00460                 NET_StreamClose(s);
00461             }
00462             /* Note that s is potentially invalid after the callback returns - we'll close dead streams on the next pass */
00463             else if (s->ready && s->func) {
00464                 s->func(s);
00465             }
00466 
00467             continue;
00468         }
00469 
00470         if (s->socket == INVALID_SOCKET)
00471             continue;
00472 
00473         if (FD_ISSET(s->socket, &write_fds_out)) {
00474             char buf[4096];
00475             int len;
00476 
00477             if (dbuffer_len(s->outbound) == 0) {
00478                 FD_CLR(s->socket, &write_fds);
00479 
00480                 /* Finished streams are closed when their outbound queues empty */
00481                 if (s->finished)
00482                     NET_StreamClose(s);
00483 
00484                 continue;
00485             }
00486 
00487             len = dbuffer_get(s->outbound, buf, sizeof(buf));
00488             len = send(s->socket, buf, len, 0);
00489 
00490             if (len < 0) {
00491                 Com_Printf("write on socket %d failed: %s\n", s->socket, netStringError(netError));
00492                 NET_StreamClose(s);
00493                 continue;
00494             }
00495 
00496             Com_DPrintf(DEBUG_SERVER, "wrote %d bytes to stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), qtrue));
00497 
00498             dbuffer_remove(s->outbound, len);
00499         }
00500 
00501         if (FD_ISSET(s->socket, &read_fds_out)) {
00502             char buf[4096];
00503             const int len = recv(s->socket, buf, sizeof(buf), 0);
00504             if (len <= 0) {
00505                 if (len == -1)
00506                     Com_Printf("read on socket %d failed: %s\n", s->socket, netStringError(netError));
00507                 NET_StreamClose(s);
00508                 continue;
00509             } else {
00510                 if (s->inbound) {
00511                     dbuffer_add(s->inbound, buf, len);
00512 
00513                     Com_DPrintf(DEBUG_SERVER, "read %d bytes from stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), qtrue));
00514 
00515                     /* Note that s is potentially invalid after the callback returns */
00516                     if (s->func)
00517                         s->func(s);
00518 
00519                     continue;
00520                 }
00521             }
00522         }
00523     }
00524 
00525     for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++) {
00526         struct datagram_socket *s = datagram_sockets[i];
00527 
00528         if (!s)
00529             continue;
00530 
00531         if (FD_ISSET(s->socket, &write_fds_out)) {
00532             if (s->queue) {
00533                 struct datagram *dgram = s->queue;
00534                 const int len = sendto(s->socket, dgram->msg, dgram->len, 0, (struct sockaddr *)dgram->addr, s->addrlen);
00535                 if (len == -1)
00536                     Com_Printf("sendto on socket %d failed: %s\n", s->socket, netStringError(netError));
00537                 /* Regardless of whether it worked, we don't retry datagrams */
00538                 s->queue = dgram->next;
00539                 Mem_Free(dgram->msg);
00540                 Mem_Free(dgram->addr);
00541                 Mem_Free(dgram);
00542                 if (!s->queue)
00543                     s->queue_tail = &s->queue;
00544             } else {
00545                 FD_CLR(s->socket, &write_fds);
00546             }
00547         }
00548 
00549         if (FD_ISSET(s->socket, &read_fds_out)) {
00550             char buf[256];
00551             char addrbuf[256];
00552             socklen_t addrlen = sizeof(addrbuf);
00553             const int len = recvfrom(s->socket, buf, sizeof(buf), 0, (struct sockaddr *)addrbuf, &addrlen);
00554             if (len == -1)
00555                 Com_Printf("recvfrom on socket %d failed: %s\n", s->socket, netStringError(netError));
00556             else
00557                 s->func(s, buf, len, (struct sockaddr *)addrbuf);
00558         }
00559     }
00560 
00561     loopback_ready = qfalse;
00562 }
00563 
00564 static qboolean NET_SocketSetNonBlocking (int socket)
00565 {
00566     unsigned long t = 1;
00567     if (ioctlsocket(socket, FIONBIO, &t) == -1) {
00568         Com_Printf("ioctl FIONBIO failed: %s\n", strerror(errno));
00569         return qfalse;
00570     }
00571     return qtrue;
00572 }
00573 
00574 static struct net_stream *NET_DoConnect (const char *node, const char *service, const struct addrinfo *addr, int i)
00575 {
00576     struct net_stream *s;
00577     SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
00578     if (sock == INVALID_SOCKET) {
00579         Com_Printf("Failed to create socket: %s\n", netStringError(netError));
00580         return NULL;
00581     }
00582 
00583     if (!NET_SocketSetNonBlocking(sock)) {
00584         netCloseSocket(sock);
00585         return NULL;
00586     }
00587 
00588     if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
00589         const int err = netError;
00590 #ifdef _WIN32
00591         if (err != WSAEWOULDBLOCK) {
00592 #else
00593         if (err != EINPROGRESS) {
00594 #endif
00595             Com_Printf("Failed to start connection to %s:%s: %s\n", node, service, netStringError(err));
00596             netCloseSocket(sock);
00597             return NULL;
00598         }
00599     }
00600 
00601     s = NET_StreamNew(i);
00602     s->socket = sock;
00603     s->inbound = new_dbuffer();
00604     s->outbound = new_dbuffer();
00605     s->family = addr->ai_family;
00606     s->addrlen = addr->ai_addrlen;
00607 
00608     maxfd = max(sock + 1, maxfd);
00609     FD_SET(sock, &read_fds);
00610 
00611     return s;
00612 }
00613 
00622 struct net_stream *NET_Connect (const char *node, const char *service)
00623 {
00624     struct addrinfo *res;
00625     struct addrinfo hints;
00626     int rc;
00627     struct net_stream *s = NULL;
00628     int index;
00629 
00630     memset(&hints, 0, sizeof(hints));
00631     hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
00632     hints.ai_socktype = SOCK_STREAM;
00633     /* force ipv4 */
00634     if (net_ipv4->integer)
00635         hints.ai_family = AF_INET;
00636 
00637     rc = getaddrinfo(node, service, &hints, &res);
00638     if (rc != 0) {
00639         Com_Printf("Failed to resolve host %s:%s: %s\n", node, service, gai_strerror(rc));
00640         return NULL;
00641     }
00642 
00643     index = NET_StreamGetFree();
00644     if (index == -1) {
00645         Com_Printf("Failed to connect to host %s:%s, too many streams open\n", node, service);
00646         freeaddrinfo(res);
00647         return NULL;
00648     }
00649 
00650     s = NET_DoConnect(node, service, res, index);
00651 
00652     freeaddrinfo(res);
00653     return s;
00654 }
00655 
00659 struct net_stream *NET_ConnectToLoopBack (void)
00660 {
00661     struct net_stream *client, *server;
00662     int server_index, client_index;
00663 
00664     if (!server_running)
00665         return NULL;
00666 
00667     server_index = NET_StreamGetFree();
00668     client_index = NET_StreamGetFree();
00669 
00670     if (server_index == -1 || client_index == -1 || server_index == client_index) {
00671         Com_Printf("Failed to connect to loopback server, too many streams open\n");
00672         return NULL;
00673     }
00674 
00675     client = NET_StreamNew(client_index);
00676     client->loopback = qtrue;
00677     client->inbound = new_dbuffer();
00678     client->outbound = new_dbuffer();
00679 
00680     server = NET_StreamNew(server_index);
00681     server->loopback = qtrue;
00682     server->inbound = client->outbound;
00683     server->outbound = client->inbound;
00684     server->func = server_func;
00685 
00686     client->loopback_peer = server;
00687     server->loopback_peer = client;
00688 
00689     server_func(server);
00690 
00691     return client;
00692 }
00693 
00699 void NET_StreamEnqueue (struct net_stream *s, const char *data, int len)
00700 {
00701     if (len <= 0 || !s || s->closed || s->finished)
00702         return;
00703 
00704     if (s->outbound)
00705         dbuffer_add(s->outbound, data, len);
00706 
00707     if (s->socket >= 0)
00708         FD_SET(s->socket, &write_fds);
00709 
00710     if (s->loopback_peer) {
00711         loopback_ready = qtrue;
00712         s->loopback_peer->ready = qtrue;
00713     }
00714 }
00715 
00716 qboolean NET_StreamIsClosed (struct net_stream *s)
00717 {
00718     return s ? (s->closed || s->finished) : qtrue;
00719 }
00720 
00721 int NET_StreamGetLength (struct net_stream *s)
00722 {
00723     return s ? dbuffer_len(s->inbound) : 0;
00724 }
00725 
00730 int NET_StreamPeek (struct net_stream *s, char *data, int len)
00731 {
00732     if (len <= 0 || !s)
00733         return 0;
00734 
00735     if ((s->closed || s->finished) && dbuffer_len(s->inbound) == 0)
00736         return 0;
00737 
00738     return dbuffer_get(s->inbound, data, len);
00739 }
00740 
00745 int NET_StreamDequeue (struct net_stream *s, char *data, int len)
00746 {
00747     if (len <= 0 || !s || s->finished)
00748         return 0;
00749 
00750     return dbuffer_extract(s->inbound, data, len);
00751 }
00752 
00753 void *NET_StreamGetData (struct net_stream *s)
00754 {
00755     return s ? s->data : NULL;
00756 }
00757 
00758 void NET_StreamSetData (struct net_stream *s, void *data)
00759 {
00760     if (!s)
00761         return;
00762     s->data = data;
00763 }
00764 
00770 void NET_StreamFree (struct net_stream *s)
00771 {
00772     if (!s)
00773         return;
00774     s->finished = qtrue;
00775     NET_StreamClose(s);
00776 }
00777 
00785 void NET_StreamFinished (struct net_stream *s)
00786 {
00787     if (!s)
00788         return;
00789 
00790     s->finished = qtrue;
00791 
00792     if (s->socket >= 0)
00793         FD_CLR(s->socket, &read_fds);
00794 
00795     /* Stop the loopback peer from queueing stuff up in here */
00796     if (s->loopback_peer)
00797         s->loopback_peer->outbound = NULL;
00798 
00799     free_dbuffer(s->inbound);
00800     s->inbound = NULL;
00801 
00802     /* If there's nothing in the outbound buffer, any finished stream is
00803      * ready to be closed */
00804     if (dbuffer_len(s->outbound) == 0)
00805         NET_StreamClose(s);
00806 }
00807 
00814 const char *NET_StreamPeerToName (struct net_stream *s, char *dst, int len, qboolean appendPort)
00815 {
00816     if (!s)
00817         return "(null)";
00818     else if (NET_StreamIsLoopback(s))
00819         return "loopback connection";
00820     else {
00821         char buf[128];
00822         char node[64];
00823         char service[64];
00824         int rc;
00825         socklen_t addrlen = s->addrlen;
00826         if (getpeername(s->socket, (struct sockaddr *)buf, &addrlen) != 0)
00827             return "(error)";
00828 
00829         rc = getnameinfo((struct sockaddr *)buf, addrlen, node, sizeof(node), service, sizeof(service),
00830                 NI_NUMERICHOST | NI_NUMERICSERV);
00831         if (rc != 0) {
00832             Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
00833             return "(error)";
00834         }
00835         if (!appendPort)
00836             Q_strncpyz(dst, node, len);
00837         else {
00838             node[sizeof(node) - 1] = '\0';
00839             service[sizeof(service) - 1] = '\0';
00840             Com_sprintf(dst, len, "%s %s", node, service);
00841         }
00842         return dst;
00843     }
00844 }
00845 
00846 void NET_StreamSetCallback (struct net_stream *s, stream_callback_func *func)
00847 {
00848     if (!s)
00849         return;
00850     s->func = func;
00851 }
00852 
00853 qboolean NET_StreamIsLoopback (struct net_stream *s)
00854 {
00855     return s && s->loopback;
00856 }
00857 
00858 static int NET_DoStartServer (const struct addrinfo *addr)
00859 {
00860     SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
00861     int t = 1;
00862 
00863     if (sock == INVALID_SOCKET) {
00864         Com_Printf("Failed to create socket: %s\n", netStringError(netError));
00865         return INVALID_SOCKET;
00866     }
00867 
00868     if (!NET_SocketSetNonBlocking(sock)) {
00869         netCloseSocket(sock);
00870         return INVALID_SOCKET;
00871     }
00872 
00873 #ifdef _WIN32
00874     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) != 0) {
00875 #else
00876     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)) != 0) {
00877 #endif
00878         Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
00879         netCloseSocket(sock);
00880         return INVALID_SOCKET;
00881     }
00882 
00883     if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
00884         Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
00885         netCloseSocket(sock);
00886         return INVALID_SOCKET;
00887     }
00888 
00889     if (listen(sock, SOMAXCONN) != 0) {
00890         Com_Printf("Failed to listen on socket: %s\n", netStringError(netError));
00891         netCloseSocket(sock);
00892         return INVALID_SOCKET;
00893     }
00894 
00895     maxfd = max(sock + 1, maxfd);
00896     FD_SET(sock, &read_fds);
00897     server_family = addr->ai_family;
00898     server_addrlen = addr->ai_addrlen;
00899 
00900     return sock;
00901 }
00902 
00912 qboolean SV_Start (const char *node, const char *service, stream_callback_func *func)
00913 {
00914     if (!func)
00915         return qfalse;
00916 
00917     if (server_running) {
00918         Com_Printf("SV_Start: Server is still running - call SV_Stop before\n");
00919         return qfalse;
00920     }
00921 
00922     if (service) {
00923         struct addrinfo *res;
00924         struct addrinfo hints;
00925         int rc;
00926 
00927         memset(&hints, 0, sizeof(hints));
00928         hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE;
00929         hints.ai_socktype = SOCK_STREAM;
00930         /* force ipv4 */
00931         if (net_ipv4->integer)
00932             hints.ai_family = AF_INET;
00933 
00934         rc = getaddrinfo(node, service, &hints, &res);
00935 
00936         if (rc != 0) {
00937             Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
00938             return qfalse;
00939         }
00940 
00941         server_socket = NET_DoStartServer(res);
00942         if (server_socket == INVALID_SOCKET) {
00943             Com_Printf("Failed to start server on %s:%s\n", node ? node : "*", service);
00944         } else {
00945             server_running = qtrue;
00946             server_func = func;
00947         }
00948         freeaddrinfo(res);
00949     } else {
00950         /* Loopback server only */
00951         server_running = qtrue;
00952         server_func = func;
00953     }
00954 
00955     return server_running;
00956 }
00957 
00961 void SV_Stop (void)
00962 {
00963     server_running = qfalse;
00964     server_func = NULL;
00965     if (server_socket != INVALID_SOCKET) {
00966         FD_CLR(server_socket, &read_fds);
00967         netCloseSocket(server_socket);
00968     }
00969     server_socket = INVALID_SOCKET;
00970 }
00971 
00975 static struct datagram_socket *NET_DatagramSocketDoNew (const struct addrinfo *addr)
00976 {
00977     struct datagram_socket *s;
00978     SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
00979     int t = 1;
00980     const int index = NET_DatagramFindFreeSocket();
00981 
00982     if (index == -1) {
00983         Com_Printf("Too many datagram sockets open\n");
00984         return NULL;
00985     }
00986 
00987     if (sock == INVALID_SOCKET) {
00988         Com_Printf("Failed to create socket: %s\n", netStringError(netError));
00989         return NULL;
00990     }
00991 
00992     if (!NET_SocketSetNonBlocking(sock)) {
00993         netCloseSocket(sock);
00994         return NULL;
00995     }
00996 
00997     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) != 0) {
00998         Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
00999         netCloseSocket(sock);
01000         return NULL;
01001     }
01002 
01003     if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &t, sizeof(t)) != 0) {
01004         Com_Printf("Failed to set SO_BROADCAST on socket: %s\n", netStringError(netError));
01005         netCloseSocket(sock);
01006         return NULL;
01007     }
01008 
01009     if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
01010         Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
01011         netCloseSocket(sock);
01012         return NULL;
01013     }
01014 
01015     maxfd = max(sock + 1, maxfd);
01016     FD_SET(sock, &read_fds);
01017 
01018     s = Mem_PoolAlloc(sizeof(*s), com_networkPool, 0);
01019     s->family = addr->ai_family;
01020     s->addrlen = addr->ai_addrlen;
01021     s->socket = sock;
01022     s->index = index;
01023     s->queue = NULL;
01024     s->queue_tail = &s->queue;
01025     s->func = NULL;
01026     datagram_sockets[index] = s;
01027 
01028     return s;
01029 }
01030 
01038 struct datagram_socket *NET_DatagramSocketNew (const char *node, const char *service, datagram_callback_func *func)
01039 {
01040     struct datagram_socket *s;
01041     struct addrinfo *res;
01042     struct addrinfo hints;
01043     int rc;
01044 
01045     if (!service || !func)
01046         return NULL;
01047 
01048     memset(&hints, 0, sizeof(hints));
01049     hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE;
01050     hints.ai_socktype = SOCK_DGRAM;
01051     /* force ipv4 */
01052     if (net_ipv4->integer)
01053         hints.ai_family = AF_INET;
01054 
01055     rc = getaddrinfo(node, service, &hints, &res);
01056 
01057     if (rc != 0) {
01058         Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
01059         return qfalse;
01060     }
01061 
01062     s = NET_DatagramSocketDoNew(res);
01063     if (s)
01064         s->func = func;
01065 
01066     freeaddrinfo(res);
01067     return s;
01068 }
01069 
01073 void NET_DatagramSend (struct datagram_socket *s, const char *buf, int len, struct sockaddr *to)
01074 {
01075     struct datagram *dgram;
01076     if (!s || len <= 0 || !buf || !to)
01077         return;
01078 
01079     dgram = Mem_PoolAlloc(sizeof(*dgram), com_networkPool, 0);
01080     dgram->msg = Mem_PoolAlloc(len, com_networkPool, 0);
01081     dgram->addr = Mem_PoolAlloc(s->addrlen, com_networkPool, 0);
01082     memcpy(dgram->msg, buf, len);
01083     memcpy(dgram->addr, to, len);
01084     dgram->len = len;
01085     dgram->next = NULL;
01086 
01087     *s->queue_tail = dgram;
01088     s->queue_tail = &dgram->next;
01089 
01090     FD_SET(s->socket, &write_fds);
01091 }
01092 
01098 void NET_DatagramBroadcast (struct datagram_socket *s, const char *buf, int len, int port)
01099 {
01100     if (s->family == AF_INET) {
01101         struct sockaddr_in addr;
01102         addr.sin_family = AF_INET;
01103         addr.sin_port = htons(port);
01104         addr.sin_addr.s_addr = INADDR_BROADCAST;
01105         NET_DatagramSend(s, buf, len, (struct sockaddr *)&addr);
01106     } else if (s->family == AF_INET6) {
01107         struct sockaddr_in addr;
01108         addr.sin_family = AF_INET6;
01109         addr.sin_port = htons(port);
01110         addr.sin_addr.s_addr = INADDR_BROADCAST;
01111         NET_DatagramSend(s, buf, len, (struct sockaddr *)&addr);
01112     } else {
01113         Com_Error(ERR_DROP, "Broadcast unsupported on address family %d\n", s->family);
01114     }
01115 }
01116 
01121 void NET_DatagramSocketClose (struct datagram_socket *s)
01122 {
01123     if (!s)
01124         return;
01125 
01126     FD_CLR(s->socket, &read_fds);
01127     FD_CLR(s->socket, &write_fds);
01128     netCloseSocket(s->socket);
01129 
01130     while (s->queue) {
01131         struct datagram *dgram = s->queue;
01132         s->queue = dgram->next;
01133         Mem_Free(dgram->msg);
01134         Mem_Free(dgram->addr);
01135         Mem_Free(dgram);
01136     }
01137 
01138     datagram_sockets[s->index] = NULL;
01139     Mem_Free(s);
01140 }
01141 
01151 void NET_SockaddrToStrings (struct datagram_socket *s, struct sockaddr *addr, char *node, size_t nodelen, char *service, size_t servicelen)
01152 {
01153     const int rc = getnameinfo(addr, s->addrlen, node, nodelen, service, servicelen,
01154             NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
01155     if (rc != 0) {
01156         Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
01157         Q_strncpyz(node, "(error)", nodelen);
01158         Q_strncpyz(service, "(error)", servicelen);
01159     }
01160 }

Generated by  doxygen 1.6.2