00001
00024 #include "iothread.h"
00025 #include "random.h"
00026 #include "message.h"
00027 #include "timesync.h"
00028 #include "net.h"
00029 #include <string.h>
00030 #include <assert.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <SDL.h>
00034 #ifndef WIN32
00035 #include <sys/socket.h>
00036 #include <arpa/inet.h>
00037 #include <netdb.h>
00038 #include <unistd.h>
00039 #include <fcntl.h>
00040 #endif
00041
00042 const rtsa_char *GetNetErrorString(int err) {
00043 int errInd;
00044 switch (err) {
00045 case 0:
00046 errInd = STRING_ERR_NONE;
00047 break;
00048 case EWOULDBLOCK:
00049 errInd = STRING_ERR_WOULDBLOCK;
00050 break;
00051 case EBADF:
00052 errInd = STRING_ERR_BADF;
00053 break;
00054 case EFAULT:
00055 errInd = STRING_ERR_FAULT;
00056 break;
00057 case EINTR:
00058 errInd = STRING_ERR_INTR;
00059 break;
00060 case EINVAL:
00061 errInd = STRING_ERR_INVAL;
00062 break;
00063 case ENOTSOCK:
00064 errInd = STRING_ERR_NOTSOCK;
00065 break;
00066 case EADDRINUSE:
00067 errInd = STRING_ERR_ADDRINUSE;
00068 break;
00069 case ENETDOWN:
00070 errInd = STRING_ERR_NETDOWN;
00071 break;
00072 case ENETUNREACH:
00073 errInd = STRING_ERR_NETUNREACH;
00074 break;
00075 case ECONNRESET:
00076 errInd = STRING_ERR_CONNRESET;
00077 break;
00078 case ECONNREFUSED:
00079 errInd = STRING_ERR_CONNREFUSED;
00080 break;
00081 case EHOSTUNREACH:
00082 errInd = STRING_ERR_HOSTUNREACH;
00083 break;
00084 default:
00085 errInd = STRING_ERR_DEFAULT;
00086 }
00087 assert(strings[errInd] != NULL);
00088 return strings[errInd];
00089 }
00090
00091 int netError = 0;
00092
00093 ClientData *clients = NULL;
00094
00095 unsigned int networkState = NETSTATE_SEARCHING;
00096
00097 Uint32 clientRandId;
00098
00103 int sock = -1;
00104
00109 SocketAddr outgoingAddr;
00110
00111 extern Uint32 localPlayer;
00112
00119 static Bool ConfigNonBlocking(int sock) {
00120 #ifdef WIN32
00121 u_long val = 1;
00122
00123 return ioctlsocket(sock, FIONBIO, &val) == 0;
00124 #else
00125
00126 int options = fcntl(sock, F_GETFL);
00127
00128 if (options >= 0) {
00129
00130 options |= O_NONBLOCK;
00131
00132 return fcntl(sock, F_SETFL, options) >= 0;
00133 }
00134 return FALSE;
00135 #endif
00136 }
00137
00146 static Bool ConfigIPv4Broadcast(Bool isServer) {
00147 int bcast = 1;
00148 assert(sock == -1);
00149
00150 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
00151
00152 #ifdef USE_GETTEXT
00153 printf("Could not open an IPv4 UDP socket: %ls\n",
00154 GetNetErrorString(GetNetErrorVal()));
00155 #else
00156 printf("Could not open an IPv4 UDP socket: %s\n",
00157 GetNetErrorString(GetNetErrorVal()));
00158 #endif
00159 return FALSE;
00160 }
00161
00162 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&bcast,
00163 sizeof(int));
00164
00165 outgoingAddr.ipv4.sin_family = AF_INET;
00166 outgoingAddr.ipv4.sin_port = isServer ? htons(PORT_SRV) : htons(PORT_CLI);
00167 outgoingAddr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
00168
00169 if (bind(sock, &(outgoingAddr.addr),
00170 outgoingAddr.length = sizeof(struct sockaddr_in))) {
00171
00172 #ifdef USE_GETTEXT
00173 printf("Could not bind to UDP port %u: %ls\n",
00174 ntohs(outgoingAddr.ipv4.sin_port), GetNetErrorString(GetNetErrorVal()));
00175 #else
00176 printf("Could not bind to UDP port %u: %s\n",
00177 ntohs(outgoingAddr.ipv4.sin_port), GetNetErrorString(GetNetErrorVal()));
00178 #endif
00179 return FALSE;
00180 }
00181
00182 outgoingAddr.ipv4.sin_port = isServer ? htons(PORT_CLI) : htons(PORT_SRV);
00183 outgoingAddr.ipv4.sin_addr.s_addr = htonl(INADDR_BROADCAST);
00184
00185 return ConfigNonBlocking(sock);
00186 }
00187
00188 int UnicastSocket(void *addr, Bool block) {
00189 int sock;
00190 assert(addr != NULL);
00191
00192 if ((sock = socket(((SocketAddr*)addr)->addr.sa_family,
00193 SOCK_DGRAM, IPPROTO_UDP)) == -1) {
00194
00195 return -1;
00196 }
00197
00198 if (bind(sock, &(((SocketAddr*)addr)->addr),
00199 (((SocketAddr*)addr)->addr.sa_family == AF_INET) ?
00200 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) {
00201
00202 CloseSocket(sock);
00203 return -1;
00204 }
00205
00206 if (!block && !ConfigNonBlocking(sock)) {
00207
00208 CloseSocket(sock);
00209 return -1;
00210 }
00211
00212 return sock;
00213 }
00214
00223 static Bool SendConnectMsg(Bool bcast) {
00224 char buff[6];
00225
00226
00227 buff[0] = MSG_TYPE_CONN_REQ;
00228
00229 buff[1] = bcast;
00230
00231 MSG_WRITE_32C(buff, 2, clientRandId);
00232
00233 return sendto(sock, buff, 6, 0, (struct sockaddr*)&outgoingAddr,
00234 outgoingAddr.length) == 6;
00235 }
00236
00237 extern char statHost[MAX_HOST_LEN];
00238
00252 static void DiscoverConnectServer(void *srvstr) {
00253 int loop, delay = 32;
00254
00255 memset(statHost, 0, MAX_HOST_LEN);
00256
00257 if (srvstr) {
00259
00260 outgoingAddr.ipv4.sin_family = AF_INET;
00261 outgoingAddr.ipv4.sin_port = htons(PORT_CLI);
00262 outgoingAddr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
00263
00264 outgoingAddr.length = sizeof(struct sockaddr_in);
00265
00266 if ((sock = UnicastSocket(&outgoingAddr, FALSE)) == -1) {
00267
00268 networkState = NETSTATE_CONERR;
00269 netError = GetNetErrorVal();
00270 return;
00271 }
00272
00273 if (inet_pton(AF_INET, srvstr, &(outgoingAddr.ipv4.sin_addr)) <= 0) {
00274
00275 srvstr = NULL;
00276 }
00277 else {
00278
00279 outgoingAddr.ipv4.sin_port = htons(PORT_SRV);
00280 }
00281 }
00282
00283 if (!srvstr && !ConfigIPv4Broadcast(FALSE)) {
00284
00285 networkState = NETSTATE_SEARCHERR;
00286 netError = GetNetErrorVal();
00287 return;
00288 }
00289
00290 networkState = srvstr ? NETSTATE_CONNECTING : NETSTATE_SEARCHING;
00291
00292 clientRandId = RandNum();
00293
00294 for (loop = 0; (loop < 24) && !IsCancelationRequested(); loop++) {
00295
00296 if (((loop & 3) == 0) && (delay += 32,
00297 !SendConnectMsg(srvstr ? FALSE : TRUE))) {
00298
00299 networkState = srvstr ? NETSTATE_CONERR : NETSTATE_SEARCHERR;
00300 netError = GetNetErrorVal();
00301 return;
00302 }
00303
00304 SDL_Delay(delay);
00305
00306 if (!ReceiveMessages()) {
00307
00308 networkState = srvstr ? NETSTATE_CONERR : NETSTATE_SEARCHERR;
00309 netError = GetNetErrorVal();
00310 return;
00311 }
00312
00313 if ((networkState == NETSTATE_RCVCFG) ||
00314 (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_SRVDENY)) {
00315
00316 StartNameLookup(&outgoingAddr, statHost);
00317 if (networkState == NETSTATE_RCVCFG) {
00318
00319 StartClientTimeSync();
00320 }
00321
00322 return;
00323 }
00324 }
00325
00326 if (srvstr) {
00327 printf("Could not connect to %s; falling back on server discovery\n",
00328 (char*)srvstr);
00329
00330 CloseSocket(sock);
00331
00332 DiscoverConnectServer(NULL);
00333 }
00334
00335 else {
00336
00337 NetCliToSrv();
00338 }
00339 }
00340
00341 Bool NetInit(char *srv) {
00342
00343 networkState = NETSTATE_INIT;
00344
00345 QueueOperation(DoHostnameLookup, NULL);
00346
00347 QueueOperation(DiscoverConnectServer, srv);
00348
00349 return MessageInit();
00350 }
00351
00352 Bool NetInitSrv() {
00353
00354 networkState = NETSTATE_INIT;
00355
00356 QueueOperation(DoHostnameLookup, NULL);
00357
00358 NetCliToSrv();
00359
00360 return MessageInit();
00361 }
00362
00370 static void Disconnect(void *ignore) {
00371 int loop;
00372
00373 for (loop = 255; loop > 0; loop--) {
00374
00375 SDL_Delay(16);
00376
00377 if (!ReceiveMessages()) {
00378
00379 #ifndef NDEBUG
00380 printf("Disconnect receive error\n");
00381 #endif
00382 break;
00383 }
00384
00385 ServiceMessages();
00386
00387 if (GetNumOutgoingMessages() == 0) {
00388
00389 break;
00390 }
00391
00392 if (networkState == NETSTATE_INIT) {
00393 return;
00394 }
00395 }
00396
00397 if (networkState == NETSTATE_SRVDISCONN) {
00398 NetSrvToCli();
00399 }
00400 else {
00401 CloseSocket(sock);
00402 networkState = NETSTATE_INIT;
00403 timeSyncState = TIMESYNC_IDLE;
00404 }
00405 #ifndef NDEBUG
00406 printf("Disconnect complete\n");
00407 #endif
00408 }
00409
00410 void NetUninit() {
00411
00412 StopServerTimeSync();
00413
00414 if ((networkState == NETSTATE_RCVCFG) ||
00415 (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_SERVER)) {
00416
00417 CancelAllMessages();
00418
00419 SendDisconnectMessage(localPlayer);
00420
00421 networkState++;
00422
00423 Disconnect(NULL);
00424 }
00425
00426 else if ((networkState == NETSTATE_CLIDISCONN) ||
00427 (networkState == NETSTATE_SRVDISCONN)) {
00428
00429
00430
00431
00432
00433
00434 Disconnect(NULL);
00435 }
00436
00437 MessageUninit();
00438
00439 CloseSocket(sock);
00440
00441 if (clients) {
00442
00443 free(clients);
00444 clients = NULL;
00445 }
00446 }
00447
00448 void NetDisconnect() {
00449
00450 StopServerTimeSync();
00451
00452 if ((networkState == NETSTATE_RCVCFG)
00453 || (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_SERVER)) {
00454
00455 CancelOperations();
00456
00457 CancelAllMessages();
00458
00459 SendDisconnectMessage(localPlayer);
00460
00461 networkState++;
00462
00463 QueueOperation(Disconnect, NULL);
00464 }
00465 }
00466
00467
00468 Bool MessageCliToSrv();
00469 Bool MessageSrvToCli();
00470
00471 Bool NetCliToSrv() {
00472
00473 if ((clients = calloc(MAX_PLAYERS, sizeof(ClientData))) == NULL) {
00474
00475 networkState = NETSTATE_SRVERR;
00476 netError = 0;
00477 return FALSE;
00478 }
00479
00480 CloseSocket(sock);
00481
00482 if (!ConfigIPv4Broadcast(TRUE) || !StartServerTimeSync()) {
00483
00484 free(clients);
00485 clients = NULL;
00486 networkState = NETSTATE_SRVERR;
00487 netError = GetNetErrorVal();
00488 return FALSE;
00489 }
00490
00494 localPlayer = 0;
00495 clients->contact = clients->active = TRUE;
00496
00497 if (MessageCliToSrv()) {
00498
00499 networkState = NETSTATE_SERVER;
00500
00501 return TRUE;
00502 }
00503 StopServerTimeSync();
00504
00505 return FALSE;
00506 }
00507
00508 Bool NetSrvToCli() {
00509 Bool result;
00510 assert(networkState == NETSTATE_SRVDISCONN);
00511
00512
00513 free(clients);
00514 clients = NULL;
00515
00516 CloseSocket(sock);
00517
00518
00519 result = MessageSrvToCli();
00520
00521 StopServerTimeSync();
00522
00523 networkState = NETSTATE_INIT;
00524 return result;
00525 }
00526