Newer
Older
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file mserv.c
/// \brief Commands used for communicate with the master server
#ifdef __GNUC__
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#endif
#if !defined (UNDER_CE)
#include <time.h>
#endif
#if (defined (NOMD5) || defined (NOMSERV)) && !defined (NONET)
#define NONET
#endif
#ifndef NONET
#ifndef NO_IPV6
#define HAVE_IPV6
#endif
#if (defined (_WIN32) || defined (_WIN32_WCE)) && !defined (_XBOX)
#define RPC_NO_WINDOWS_H
#ifdef HAVE_IPV6
#include <ws2tcpip.h>
#else
#include <winsock.h> // socket(),...
#endif //!HAVE_IPV6
#else
#ifdef __OS2__
#include <sys/types.h>
#endif // __OS2__
#ifdef HAVE_LWIP
#include <lwip/inet.h>
#include <kos/net.h>
#include <lwip/lwip.h>
#define ioctl lwip_ioctl
#else
#include <arpa/inet.h>
#ifdef __APPLE_CC__
#ifndef _BSD_SOCKLEN_T_
#define _BSD_SOCKLEN_T_
#endif
#endif
#include <sys/socket.h> // socket(),...
#include <netinet/in.h> // sockaddr_in
#ifdef _PS3
#include <net/select.h>
#elif !defined(_arch_dreamcast)
#include <netdb.h> // getaddrinfo(),...
#include <sys/ioctl.h>
#endif
#endif
#ifdef _arch_dreamcast
#include "sdl12/SRB2DC/dchelp.h"
#endif
#include <sys/time.h> // timeval,... (TIMEOUT)
#include <errno.h>
#endif // _WIN32/_WIN32_WCE
#ifdef __OS2__
#include <errno.h>
#endif // __OS2__
#endif // !NONET
#include "doomstat.h"
#include "doomdef.h"
#include "command.h"
#include "i_net.h"
#include "console.h"
#include "mserv.h"
#include "d_net.h"
#include "i_tcp.h"
#include "i_system.h"
#include "byteptr.h"
#include "m_menu.h"
#include "m_argv.h" // Alam is going to kill me <3
#include "m_misc.h" // GetRevisionString()
#ifdef _WIN32_WCE
#include "sdl12/SRB2CE/cehelp.h"
int HMS_register (void);
void HMS_unlist (void);
void HMS_update (void);
void HMS_list_servers (void);
void HMS_fetch_servers (msg_server_t *list, int room);
// ================================ DEFINITIONS ===============================
#define PACKET_SIZE 1024
#define MS_NO_ERROR 0
#define MS_SOCKET_ERROR -201
#define MS_CONNECT_ERROR -203
#define MS_WRITE_ERROR -210
#define MS_READ_ERROR -211
#define MS_CLOSE_ERROR -212
#define MS_GETHOSTBYNAME_ERROR -220
#define MS_GETHOSTNAME_ERROR -221
#define MS_TIMEOUT_ERROR -231
#define ADD_SERVER_MSG 101
#define REMOVE_SERVER_MSG 103
#define ADD_SERVERv2_MSG 104
#define GET_SERVER_MSG 200
#define GET_SHORT_SERVER_MSG 205
#define ASK_SERVER_MSG 206
#define ANSWER_ASK_SERVER_MSG 207
#define ASK_SERVER_MSG 206
#define ANSWER_ASK_SERVER_MSG 207
#define GET_MOTD_MSG 208
#define SEND_MOTD_MSG 209
#define GET_ROOMS_MSG 210
#define SEND_ROOMS_MSG 211
#define GET_ROOMS_HOST_MSG 212
#define GET_VERSION_MSG 213
#define SEND_VERSION_MSG 214
#define GET_BANNED_MSG 215 // Someone's been baaaaaad!
#define PING_SERVER_MSG 216
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#define HEADER_SIZE (sizeof (INT32)*4)
#define HEADER_MSG_POS 0
#define IP_MSG_POS 16
#define PORT_MSG_POS 32
#define HOSTNAME_MSG_POS 40
#if defined(_MSC_VER)
#pragma pack(1)
#endif
/** A message to be exchanged with the master server.
*/
typedef struct
{
INT32 id; ///< Unused?
INT32 type; ///< Type of message.
INT32 room; ///< Because everyone needs a roomie.
UINT32 length; ///< Length of the message.
char buffer[PACKET_SIZE]; ///< Actual contents of the message.
} ATTRPACK msg_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
typedef struct Copy_CVarMS_t
{
char ip[64];
char port[8];
char name[64];
} Copy_CVarMS_s;
static Copy_CVarMS_s registered_server;
static time_t MSLastPing;
#if defined(_MSC_VER)
#pragma pack(1)
#endif
typedef struct
{
char ip[16]; // Big enough to hold a full address.
UINT16 port;
UINT8 padding1[2];
tic_t time;
} ATTRPACK ms_holepunch_packet_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
// win32 or djgpp
#if defined (_WIN32) || defined (_WIN32_WCE) || defined (__DJGPP__)
#define ioctl ioctlsocket
#define close closesocket
#ifdef WATTCP
#define strerror strerror_s
#endif
#if defined (_WIN32) || defined (_WIN32_WCE)
#undef errno
#define errno h_errno // some very strange things happen when not using h_error
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0x00000400
#endif
#endif
#ifndef NONET
static void Command_Listserv_f(void);
#endif
static void MasterServer_OnChange(void);
static void ServerName_OnChange(void);
#define DEF_PORT "28900"
consvar_t cv_masterserver = {"masterserver", "ms.srb2.org:"DEF_PORT, CV_SAVE, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_servername = {"servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, ServerName_OnChange, 0, NULL, NULL, 0, 0, NULL};
INT16 ms_RoomId = -1;
static enum { MSCS_NONE, MSCS_WAITING, MSCS_REGISTERED, MSCS_FAILED } con_state = MSCS_NONE;
static INT32 msnode = -1;
UINT16 current_port = 0;
#if (defined (_WIN32) || defined (_WIN32_WCE) || defined (_WIN32)) && !defined (NONET)
typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR)
#else
#if (defined (__unix__) && !defined (MSDOS)) || defined (__APPLE__) || defined (__HAIKU__) || defined (_PS3)
typedef int SOCKET_TYPE;
#else
typedef unsigned long SOCKET_TYPE;
#endif
#define ERRSOCKET (-1)
#endif
#if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (_WIN32)
typedef int socklen_t;
#endif
#ifndef NONET
static SOCKET_TYPE socket_fd = ERRSOCKET; // WINSOCK socket
static struct timeval select_timeout;
static fd_set wset;
static size_t recvfull(SOCKET_TYPE s, char *buf, size_t len, int flags);
#endif
// Room list is an external variable now.
// Avoiding having to get info ten thousand times...
msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
/** Adds variables and commands relating to the master server.
*
* \sa cv_masterserver, cv_servername,
* Command_Listserv_f
*/
void AddMServCommands(void)
{
#ifndef NONET
CV_RegisterVar(&cv_masterserver);
CV_RegisterVar(&cv_http_masterserver);
CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_servername);
COM_AddCommand("listserv", Command_Listserv_f);
#endif
}
/** Closes the connection to the master server.
*
* \todo Fix for Windows?
*/
static void CloseConnection(void)
{
#ifndef NONET
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
#endif
}
//
// MS_Write():
//
static INT32 MS_Write(msg_t *msg)
{
#ifdef NONET
(void)msg;
return MS_WRITE_ERROR;
#else
size_t len;
if (msg->length == 0)
msg->length = (INT32)strlen(msg->buffer);
len = msg->length + HEADER_SIZE;
msg->type = htonl(msg->type);
msg->length = htonl(msg->length);
msg->room = htonl(msg->room);
if ((size_t)send(socket_fd, (char *)msg, (int)len, 0) != len)
return MS_WRITE_ERROR;
return 0;
#endif
}
//
// MS_Read():
//
static INT32 MS_Read(msg_t *msg)
{
#ifdef NONET
(void)msg;
return MS_READ_ERROR;
#else
if (recvfull(socket_fd, (char *)msg, HEADER_SIZE, 0) != HEADER_SIZE)
return MS_READ_ERROR;
msg->type = ntohl(msg->type);
msg->length = ntohl(msg->length);
msg->room = ntohl(msg->room);
if (!msg->length) // fix a bug in Windows 2000
return 0;
if (recvfull(socket_fd, (char *)msg->buffer, msg->length, 0) != msg->length)
return MS_READ_ERROR;
return 0;
#endif
}
#ifndef NONET
/** Gets a list of game servers from the master server.
*/
static INT32 GetServersList(void)
{
msg_t msg;
INT32 count = 0;
msg.type = GET_SERVER_MSG;
msg.length = 0;
msg.room = 0;
if (MS_Write(&msg) < 0)
return MS_WRITE_ERROR;
while (MS_Read(&msg) >= 0)
{
if (!msg.length)
{
if (!count)
CONS_Alert(CONS_NOTICE, M_GetText("No servers currently running.\n"));
return MS_NO_ERROR;
}
count++;
CONS_Printf("%s",msg.buffer);
}
return MS_READ_ERROR;
}
#endif
//
// MS_Connect()
//
static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
{
#ifdef NONET
(void)ip_addr;
(void)str_port;
(void)async;
#else
struct my_addrinfo *ai, *runp, hints;
int gaie;
memset (&hints, 0x00, sizeof(hints));
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//I_InitTcpNetwork(); this is already done on startup in D_SRB2Main()
if (!I_InitTcpDriver()) // this is done only if not already done
return MS_SOCKET_ERROR;
gaie = I_getaddrinfo(ip_addr, str_port, &hints, &ai);
if (gaie != 0)
return MS_GETHOSTBYNAME_ERROR;
else
runp = ai;
while (runp != NULL)
{
socket_fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
{
if (async) // do asynchronous connection
{
#ifdef FIONBIO
#ifdef WATTCP
char res = 1;
#else
unsigned long res = 1;
#endif
ioctl(socket_fd, FIONBIO, &res);
#endif
if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) == ERRSOCKET)
{
#ifdef _WIN32 // humm, on win32/win64 it doesn't work with EINPROGRESS (stupid windows)
if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EINPROGRESS)
#endif
{
con_state = MSCS_FAILED;
CloseConnection();
I_freeaddrinfo(ai);
return MS_CONNECT_ERROR;
}
}
con_state = MSCS_WAITING;
FD_ZERO(&wset);
FD_SET(socket_fd, &wset);
select_timeout.tv_sec = 0, select_timeout.tv_usec = 0;
I_freeaddrinfo(ai);
return 0;
}
else if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) != ERRSOCKET)
{
I_freeaddrinfo(ai);
return 0;
}
}
runp = runp->ai_next;
}
I_freeaddrinfo(ai);
#endif
return MS_CONNECT_ERROR;
}
#define NUM_LIST_SERVER MAXSERVERLIST
const msg_server_t *GetShortServersList(INT32 room)
{
static msg_server_t server_list[NUM_LIST_SERVER+1]; // +1 for easy test
msg_t msg;
INT32 i;
if (HMS_in_use())
{
HMS_fetch_servers(server_list, room);
return server_list;
}
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
// we must be connected to the master server before writing to it
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
return NULL;
}
msg.type = GET_SHORT_SERVER_MSG;
msg.length = 0;
msg.room = room;
if (MS_Write(&msg) < 0)
return NULL;
for (i = 0; i < NUM_LIST_SERVER && MS_Read(&msg) >= 0; i++)
{
if (!msg.length)
{
server_list[i].header.buffer[0] = 0;
CloseConnection();
return server_list;
}
M_Memcpy(&server_list[i], msg.buffer, sizeof (msg_server_t));
server_list[i].header.buffer[0] = 1;
}
CloseConnection();
if (i == NUM_LIST_SERVER)
{
server_list[i].header.buffer[0] = 0;
return server_list;
}
else
return NULL;
}
INT32 GetRoomsList(boolean hosting)
{
static msg_ban_t banned_info[1];
msg_t msg;
INT32 i;
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
// we must be connected to the master server before writing to it
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
return -1;
}
if (hosting)
msg.type = GET_ROOMS_HOST_MSG;
else
msg.type = GET_ROOMS_MSG;
msg.length = 0;
msg.room = 0;
if (MS_Write(&msg) < 0)
{
room_list[0].id = 1;
strcpy(room_list[0].motd,"Master Server Offline.");
strcpy(room_list[0].name,"Offline");
return -1;
}
for (i = 0; i < NUM_LIST_ROOMS && MS_Read(&msg) >= 0; i++)
{
if(msg.type == GET_BANNED_MSG)
{
char banmsg[1000];
M_Memcpy(&banned_info[0], msg.buffer, sizeof (msg_ban_t));
if (hosting)
sprintf(banmsg, M_GetText("You have been banned from\nhosting netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
else
sprintf(banmsg, M_GetText("You have been banned from\njoining netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
M_StartMessage(banmsg, NULL, MM_NOTHING);
ms_RoomId = -1;
return -2;
}
if (!msg.length)
{
room_list[i].header.buffer[0] = 0;
CloseConnection();
return 1;
}
M_Memcpy(&room_list[i], msg.buffer, sizeof (msg_rooms_t));
room_list[i].header.buffer[0] = 1;
}
CloseConnection();
if (i == NUM_LIST_ROOMS)
{
room_list[i].header.buffer[0] = 0;
return 1;
}
else
{
room_list[0].id = 1;
strcpy(room_list[0].motd,M_GetText("Master Server Offline."));
strcpy(room_list[0].name,M_GetText("Offline"));
return -1;
}
}
#ifdef UPDATE_ALERT
const char *GetMODVersion(void)
{
static msg_t msg;
// we must be connected to the master server before writing to it
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
return NULL;
}
msg.type = GET_VERSION_MSG;
msg.length = sizeof MODVERSION;
msg.room = MODID; // Might as well use it for something.
sprintf(msg.buffer,"%d",MODVERSION);
if (MS_Write(&msg) < 0)
Monster Iestyn
committed
{
CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
M_StartMessage(M_GetText("Could not send to the Master Server\n"), NULL, MM_NOTHING);
CloseConnection();
Monster Iestyn
committed
}
if (MS_Read(&msg) < 0)
{
CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
M_StartMessage(M_GetText("No reply from the Master Server\n"), NULL, MM_NOTHING);
CloseConnection();
Monster Iestyn
committed
}
CloseConnection();
if(strcmp(msg.buffer,"NULL") != 0)
{
return msg.buffer;
}
else
return NULL;
}
// Console only version of the above (used before game init)
void GetMODVersion_Console(void)
{
static msg_t msg;
// we must be connected to the master server before writing to it
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
return;
}
msg.type = GET_VERSION_MSG;
msg.length = sizeof MODVERSION;
msg.room = MODID; // Might as well use it for something.
sprintf(msg.buffer,"%d",MODVERSION);
if (MS_Write(&msg) < 0)
Monster Iestyn
committed
{
CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
CloseConnection();
Monster Iestyn
committed
}
if (MS_Read(&msg) < 0)
{
CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
CloseConnection();
Monster Iestyn
committed
}
CloseConnection();
if(strcmp(msg.buffer,"NULL") != 0)
I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, msg.buffer);
}
#endif
#ifndef NONET
/** Gets a list of game servers. Called from console.
*/
static void Command_Listserv_f(void)
{
if (con_state == MSCS_WAITING)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not yet connected to the Master Server.\n"));
return;
}
CONS_Printf(M_GetText("Retrieving server list...\n"));
if (HMS_in_use())
{
HMS_list_servers();
return;
}
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
return;
}
if (GetServersList())
CONS_Alert(CONS_ERROR, M_GetText("Cannot get server list\n"));
CloseConnection();
}
#endif
FUNCMATH static const char *int2str(INT32 n)
{
INT32 i;
static char res[16];
res[15] = '\0';
res[14] = (char)((char)(n%10)+'0');
for (i = 13; (n /= 10); i--)
res[i] = (char)((char)(n%10)+'0');
return &res[i+1];
}
#ifndef NONET
static INT32 ConnectionFailed(void)
{
con_state = MSCS_FAILED;
CONS_Alert(CONS_ERROR, M_GetText("Connection to Master Server failed\n"));
CloseConnection();
return MS_CONNECT_ERROR;
}
#endif
/** Tries to register the local game server on the master server.
*/
static INT32 AddToMasterServer(boolean firstadd)
{
#ifdef NONET
(void)firstadd;
#else
static INT32 retry = 0;
int i, res;
socklen_t j;
msg_t msg;
msg_server_t *info = (msg_server_t *)msg.buffer;
INT32 room = -1;
fd_set tset;
time_t timestamp = time(NULL);
UINT32 signature, tmp;
const char *insname;
if (HMS_in_use())
{
HMS_update();
return MS_NO_ERROR;
}
M_Memcpy(&tset, &wset, sizeof (tset));
res = select(255, NULL, &tset, NULL, &select_timeout);
if (res != ERRSOCKET && !res)
{
if (retry++ > 30) // an about 30 second timeout
{
retry = 0;
CONS_Alert(CONS_ERROR, M_GetText("Master Server timed out\n"));
MSLastPing = timestamp;
return ConnectionFailed();
}
return MS_CONNECT_ERROR;
}
retry = 0;
/*
Somehow we can still select our old socket despite it being closed(?).
Atleast, that's what I THINK is happening. Anyway, we have to check that we
haven't open a socket, and actually open it!
*/
/*if (res == ERRSOCKET)*//* wtf? no! */
{
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
MSLastPing = timestamp;
return ConnectionFailed();
}
}
// so, the socket is writable, but what does that mean, that the connection is
// ok, or bad... let see that!
j = (socklen_t)sizeof (i);
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&i, &j);
/*
This is also wrong. If getsockopt fails, i doesn't have to be set. Plus, if
it is set (which it appearantly is on linux), we check errno anyway. And in
the case that i is returned as normal, we don't even report the correct
value! So we accomplish NOTHING, except returning due to dumb luck.
If you care, fix this--I don't. -James (R.)
*/
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
if (i) // it was bad
{
CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
MSLastPing = timestamp;
return ConnectionFailed();
}
#ifdef PARANOIA
if (ms_RoomId <= 0)
I_Error("Attmepted to host in room \"All\"!\n");
#endif
room = ms_RoomId;
for(signature = 0, insname = cv_servername.string; *insname; signature += *insname++);
tmp = (UINT32)(signature * (size_t)&MSLastPing);
signature *= tmp;
signature &= 0xAAAAAAAA;
M_Memcpy(&info->header.signature, &signature, sizeof (UINT32));
strcpy(info->ip, "");
strcpy(info->port, int2str(current_port));
strcpy(info->name, cv_servername.string);
M_Memcpy(&info->room, & room, sizeof (INT32));
#if VERSION > 0 || SUBVERSION > 0
sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
#else // Trunk build, send revision info
strcpy(info->version, GetRevisionString());
#endif
strcpy(registered_server.name, cv_servername.string);
if(firstadd)
msg.type = ADD_SERVER_MSG;
else
msg.type = PING_SERVER_MSG;
msg.length = (UINT32)sizeof (msg_server_t);
msg.room = 0;
if (MS_Write(&msg) < 0)
{
MSLastPing = timestamp;
return ConnectionFailed();
}
if(con_state != MSCS_REGISTERED)
CONS_Printf(M_GetText("Master Server update successful.\n"));
MSLastPing = timestamp;
con_state = MSCS_REGISTERED;
CloseConnection();
#endif
return MS_NO_ERROR;
}
static INT32 RemoveFromMasterSever(void)
{
msg_t msg;
msg_server_t *info = (msg_server_t *)msg.buffer;
strcpy(info->header.buffer, "");
strcpy(info->ip, "");
strcpy(info->port, int2str(current_port));
strcpy(info->name, registered_server.name);
sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
msg.type = REMOVE_SERVER_MSG;
msg.length = (UINT32)sizeof (msg_server_t);
msg.room = 0;
if (MS_Write(&msg) < 0)
return MS_WRITE_ERROR;
return MS_NO_ERROR;
}
const char *GetMasterServerPort(void)
{
const char *t = cv_masterserver.string;
while ((*t != ':') && (*t != '\0'))
t++;
if (*t)
return ++t;
else
return DEF_PORT;
}
/** Gets the IP address of the master server. Actually, it seems to just
* return the hostname, instead; the lookup is done elsewhere.
*
* \return Hostname of the master server, without port number on the end.
* \todo Rename function?
*/
const char *GetMasterServerIP(void)
{
static char str_ip[64];
char *t = str_ip;
if (strstr(cv_masterserver.string, "srb2.ssntails.org:28910")
|| strstr(cv_masterserver.string, "srb2.servegame.org:28910")
|| strstr(cv_masterserver.string, "srb2.servegame.org:28900")
)
{
// replace it with the current default one
CV_Set(&cv_masterserver, cv_masterserver.defaultvalue);
}
strcpy(t, cv_masterserver.string);
while ((*t != ':') && (*t != '\0'))
t++;
*t = '\0';
return str_ip;
}
void MSOpenUDPSocket(void)
{
#ifndef NONET
if (I_NetMakeNodewPort)
{
// If it's already open, there's nothing to do.
if (msnode < 0)
msnode = I_NetMakeNodewPort(GetMasterServerIP(), GetMasterServerPort());
}
else
#endif
msnode = -1;
}
void MSCloseUDPSocket(void)
{
if (msnode != INT16_MAX) I_NetFreeNodenum(msnode);
msnode = -1;
}
void RegisterServer(void)
{
if (con_state == MSCS_REGISTERED || con_state == MSCS_WAITING)
return;
CONS_Printf(M_GetText("Registering this server on the Master Server...\n"));
if (HMS_in_use())
{
if (HMS_register())
con_state = MSCS_REGISTERED;
return;
}
strcpy(registered_server.ip, GetMasterServerIP());
strcpy(registered_server.port, GetMasterServerPort());
if (MS_Connect(registered_server.ip, registered_server.port, 1))
{
CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
return;
}
MSOpenUDPSocket();
// keep the TCP connection open until AddToMasterServer() is completed;
}
static inline void SendPingToMasterServer(void)
{
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* static tic_t next_time = 0;
tic_t cur_time;
char *inbuffer = (char*)netbuffer;
cur_time = I_GetTime();
if (!netgame)
UnregisterServer();
else if (cur_time > next_time) // ping every 2 second if possible
{
next_time = cur_time+2*TICRATE;
if (con_state == MSCS_WAITING)
AddToMasterServer();
if (con_state != MSCS_REGISTERED)
return;
// cur_time is just a dummy data to send
WRITEUINT32(inbuffer, cur_time);
doomcom->datalength = sizeof (cur_time);
doomcom->remotenode = (INT16)msnode;
I_NetSend();
}
*/
// Here, have a simpler MS Ping... - Cue
if(time(NULL) > (MSLastPing+(60*2)) && con_state != MSCS_NONE)
{
//CONS_Debug(DBG_NETPLAY, "%ld (current time) is greater than %d (Last Ping Time)\n", time(NULL), MSLastPing);
if(MSLastPing < 1)
AddToMasterServer(true);
else
AddToMasterServer(false);
}
}
void SendAskInfoViaMS(INT32 node, tic_t asktime)
{
const char *address;
UINT16 port;
char *inip;
ms_holepunch_packet_t mshpp;
MSOpenUDPSocket();
// This must be called after calling MSOpenUDPSocket, due to the
// static buffer.
address = I_GetNodeAddress(node);
// no address?
if (!address)
return;
// Copy the IP address into the buffer.
inip = mshpp.ip;
while(*address && *address != ':') *inip++ = *address++;
*inip = '\0';
// Get the port.
port = (UINT16)(*address++ ? atoi(address) : 0);
mshpp.port = SHORT(port);
// Set the time for ping calculation.
mshpp.time = LONG(asktime);