]> jfr.im git - irc/gameservirc.git/blame - gameserv/tcpclient.cpp
Fixed some p10, bugs, and gameserv is now running as a true daemon with pid outputtin...
[irc/gameservirc.git] / gameserv / tcpclient.cpp
CommitLineData
85ce9d3e 1/*
2 * This file is provided for use with the unix-socket-faq. It is public
3 * domain, and may be copied freely. There is no copyright on it. The
4 * original work was by Vic Metcalfe (vic@brutus.tlug.org), and any
5 * modifications made to that work were made with the understanding that
6 * the finished work would be in the public domain.
7 *
8 * If you have found a bug, please pass it on to me at the above address
9 * acknowledging that there will be no copyright on your work.
10 *
11 * The most recent version of this file, and the unix-socket-faq can be
12 * found at http://www.interlog.com/~vic/sock-faq/.
13 */
14
15#include "sockhelp.h"
c7340cbd 16#include "options.h"
85ce9d3e 17#include "list.h"
18#include "aClient.h"
19#include "extern.h"
20#include <stdio.h>
21#include <unistd.h>
22#include <string.h>
fb37ecc7 23#include <fstream>
85ce9d3e 24#include <stdlib.h>
ce61cdfa 25#include <fcntl.h>
26#include <signal.h>
27//#include <sys/types.h>
28//#include <sys/wait.h>
29//#include <errno.h>
30
31
85ce9d3e 32
fb37ecc7 33using std::ofstream;
34using std::ifstream;
ce61cdfa 35using std::cerr;
36using std::endl;
fb37ecc7 37
91c0b563 38char *PACKAGE = "GameServ";
ce61cdfa 39char *VERSION = "1.1.8";
173302fe 40
85ce9d3e 41int sock;
44ea29f7 42long timestamp;
43
85ce9d3e 44List<aClient> clients;
45
44ea29f7 46void save_timestamp();
47void load_timestamp();
48
ce61cdfa 49// Make this a daemon
50int daemon(int nochdir, int noclose);
51
52// Close all file descriptors from >= fd
53void closeall(int fd);
54
c62d75be 55int main()
85ce9d3e 56{
28f552b8 57 char buffer[1024], buf[1024];
85ce9d3e 58 int connected = 1;
59 char *cmd, *source = NULL;
60 srand(time(NULL));
44ea29f7 61
324ab87f 62
c62d75be 63 load_config_file(); // default = gameserv.conf
324ab87f 64
ce61cdfa 65 // Turn into a daemon
66 if (daemon(1,0) < 0)
67 {
68 perror("Could not turn into a daemon");
69 exit(2);
70 }
71
85ce9d3e 72 ignore_pipe();
324ab87f 73 sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
85ce9d3e 74 if (sock == -1) {
75 fprintf(stderr,"make_connection failed.\n");
76 unload_config_file();
77 return -1;
78 }
79
c7340cbd 80#ifdef UNREAL
85ce9d3e 81 raw("PROTOCTL NICKv2 VHP");
82 raw("PASS :%s", remotepass);
c7340cbd 83 raw("SERVER %s 1 :%s", servername, servername);
173302fe 84 raw("NICK %S 1 %d %S %s %s %d +owghraAxNt %s :%s v%s", time(NULL), gshost,
85 servername, time(NULL), gshost, PACKAGE, VERSION);
85ce9d3e 86 raw(":%S JOIN %s", c_Forest);
c7340cbd 87 raw(":%S MODE %s +mtn", c_Forest);
88#elif defined(BAHAMUT)
89 raw("PASS %s :TS", remotepass);
90 raw("SERVER %s 1 :%s", servername, servername);
91 raw("NICK %S 1 %d +o %s %s %s 0 :GameServ", time(NULL), gsident, gshost,
92 servername);
93 raw(":%s SJOIN %d %d %s +mnt :@%S", servername, time(NULL), time(NULL), c_Forest);
581ec09e 94#elif defined(HYBRID)
95 raw("PASS %s :TS", remotepass);
96 raw("SERVER %s 1 :%s", servername, servername);
97 raw("NICK %S 1 %d +o %s %s %s :GameServ", time(NULL), gsident, gshost,
98 servername);
99 // Sending a timestamp of 1 to force ops.
100 raw(":%s SJOIN 1 %s +ntm :@%S", servername, c_Forest);
e1c41a84 101#elif defined(P10)
102 // Server numeric is: [] <-- must be unique
103 raw("PASS :%s", remotepass);
104 raw("SERVER %s 1 %d %d P10 []AAF :%s", servername, time(NULL), time(NULL), servername);
105 raw("[] N %S 1 %d %s %s DAqAoB %s :%S", time(NULL), gsident, gshost, gsnum);
106 raw("[] B %s %d +tnm %s:o", c_Forest, time(NULL) - 864000, gsnum);
c7340cbd 107#endif
e1c41a84 108
109#if defined(P10)
110 raw("%s T %s :%s", gsnum, c_Forest, c_ForestTopic);
fc9d2643 111 raw("[] EB"); // End burst
581ec09e 112#else
113#ifndef HYBRID
85ce9d3e 114 raw(":%S MODE %s +o %S", c_Forest);
581ec09e 115#endif
c7340cbd 116 raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
e1c41a84 117#endif
85ce9d3e 118
119 sock_gets(sock,buffer,sizeof(buffer)-1); /* -1 added thanks to
120 David Duchene <dave@ltd.com> for pointing out the possible
121 buffer overflow resulting from the linefeed added below. */
122
123
9f8c2acc 124 #ifdef DEBUGMODE
125 log("Server: %s",buffer);
126 #endif
127
ab4f4ec0 128 init_masters();
ad7dfaa0 129 load_gs_dbase();
44ea29f7 130 load_timestamp();
922daad7 131 long int loadtime = time(NULL);
132 long int currentTime;
133 long int oldTime = loadtime;
5963944b 134 bool loaded = false;
44ea29f7 135
4dde2ed9 136 if (load_monsters() == false)
137 goto end;
138
85ce9d3e 139 while (connected) {
140 if (sock_gets(sock,buffer,sizeof(buffer)) == -1) {
141 connected = 0;
142 }
143 strcpy(buf, buffer);
144
e1c41a84 145 #if !defined(P10)
85ce9d3e 146 if (buffer[0] == ':')
147 {
148 source = strtok(buf, " ");
149 cmd = strtok(NULL, " ");
150 }
151 else
152 cmd = strtok(buf, " ");
e1c41a84 153 #else
154 source = strtok(buf, " ");
155 cmd = strtok(NULL, " ");
156 #endif
85ce9d3e 157
9f8c2acc 158 #ifdef DEBUGMODE
159 log("Server: %s", buffer);
160 #endif
5963944b 161
bf2cabcd 162 // Wait N seconds then we're loaded.
5963944b 163 if (!loaded)
164 {
922daad7 165 if (time(NULL) >= welcomedelay + loadtime)
5963944b 166 loaded = true;
167 }
168
922daad7 169 // Save the player data every updateperiod seconds
170 currentTime = time(NULL);
171 if (currentTime - oldTime >= updateperiod)
172 {
173 oldTime = currentTime;
174 save_gs_dbase();
175 }
176
e1c41a84 177
178 #if !defined(P10)
85ce9d3e 179 if (stricmp(cmd, "PING") == 0) {
0a1518fa 180 char *timestamp;
181 timestamp = strtok(NULL, "");
182 raw("PONG %s", timestamp);
e1c41a84 183 #else
184 if (stricmp(cmd, "G") == 0) {
185 char *timestamp;
186 timestamp = strtok(NULL, " ");
187 raw("[] Z [] %s 0 %s", timestamp + 1, timestamp);
188 #endif
fc9d2643 189 #ifdef P10
190 } else if (stricmp(cmd, "EB") == 0) {
191 raw("[] EA");
192 #endif
0501fe18 193 } else if (stricmp(cmd, "VERSION") == 0) {
194 char *server;
195 server = strtok(NULL, " ");
196 server++;
0501fe18 197 raw(":%s 351 %s %s %s. %s", servername, source+1, PACKAGE, VERSION, servername);
ba2a880f 198 #if !defined(P10)
85ce9d3e 199 } else if (strncmp(cmd, "NICK", 4) == 0) {
200 if (buffer[0] == ':')
201 {
202 aClient *tempPtr;
28f552b8 203 if ((tempPtr = find((source + 1))))
85ce9d3e 204 {
205 char *nick;
206 nick = strtok(NULL, " ");
207 tempPtr->setNick(nick);
208 }
209 }
210 else
211 {
212 char *nick;
ba2a880f 213 #else
214 } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
215 {
ce61cdfa 216 char *nick, *realnick;
217 realnick = strtok(NULL, " ");
ba2a880f 218
ce61cdfa 219 for (int x = 0; x < 5; x++)
ba2a880f 220 nick = strtok(NULL, " ");
fc9d2643 221
ba2a880f 222 if (nick[0] == '+')
fc9d2643 223 {
224 #ifdef DEBUGMODE
225 log ("aClient has modes");
226 #endif
227
228 // Searching for the +r mode (extra parameter)
229 for (unsigned int count = 1; count < strlen(nick); count++)
230 {
231 if (nick[count] == 'r')
232 {
233 nick = strtok(NULL, " ");
234 break;
235 }
236 }
237 nick = strtok(NULL, " ");
238 }
ba2a880f 239 #endif
85ce9d3e 240 aClient *newuser;
ba2a880f 241
85ce9d3e 242 nick = strtok(NULL, " ");
ba2a880f 243
ce61cdfa 244 #ifdef P10
245 newuser = new aClient(nick, realnick);
246 #else
247 newuser = new aClient(nick);
248 #endif
249
250
5963944b 251 if (loaded)
ce61cdfa 252 #ifdef P10
253 notice(s_GameServ, nick, welcomemsg, realnick);
254 #else
bf2cabcd 255 notice(s_GameServ, nick, welcomemsg, nick);
ce61cdfa 256 #endif
b0a5c536 257
85ce9d3e 258 clients.insertAtBack(newuser);
259 delete newuser;
260 }
ba2a880f 261 #if defined(P10)
262 } else if (stricmp(cmd, "Q") == 0) {
263 #else
85ce9d3e 264 } else if (stricmp(cmd, "QUIT") == 0) {
ba2a880f 265 #endif
85ce9d3e 266 aClient *quitter;
fc9d2643 267 char z = source[0];
268
269 if (z == ':')
270 source++;
271
272 if ((quitter = find(source)))
85ce9d3e 273 clients.remove(quitter);
fc9d2643 274 if ((quitter = findIRCplayer(source)))
ee38284f 275 {
276 quitter->setNick("!NULL!");
277 quitter->stats->user = NULL; // Unidentify them
278 }
fc9d2643 279
280 if (z == ':')
281 source--;
282
ba2a880f 283 #if defined(P10)
284 } else if (stricmp(cmd, "P") == 0) {
285 char *rest, *dest;
286 char *longname;
287 longname = new char[strlen(s_GameServ) + strlen(servername) + 2];
288
289 sprintf(longname, "%S@%s", servername);
85ce9d3e 290
ba2a880f 291 dest = strtok(NULL, " ");
292 rest = strtok(NULL, "");
293 if (stricmp(dest, gsnum) == 0 || stricmp(dest, longname) == 0)
294 {
295 delete [] longname;
296 gameserv(source, rest);
297 }
298 else if (stricmp(dest, c_Forest) == 0)
299 {
300 delete [] longname;
301 forest(source, rest);
302 }
303 #else
85ce9d3e 304 } else if (stricmp(cmd, "PRIVMSG") == 0) {
305 char *rest, *dest;
306 dest = strtok(NULL, " ");
307 rest = strtok(NULL, "");
ad7dfaa0 308 if (strnicmp(dest, s_GameServ, strlen(s_GameServ)) == 0)
85ce9d3e 309 gameserv(source, rest);
310 else if (stricmp(dest, c_Forest) == 0)
311 forest(source, rest);
ba2a880f 312 #endif
85ce9d3e 313 } else if (stricmp(cmd, "JOIN") == 0) {
314 char *channel;
315 channel = strtok(NULL, " ");
316 if (stricmp(channel, c_Forest) == 0 && is_playing(source + 1))
317 raw(":%S MODE %s +v %s", c_Forest, (source + 1));
c7340cbd 318
319 #if defined(BAHAMUT)
320 } else if (stricmp(cmd, "SJOIN") == 0) {
581ec09e 321 char *channel, *nick, *tmp, *rest;
c7340cbd 322 strtok(NULL, " "); // Ignore the TS
581ec09e 323#ifndef HYBRID
c7340cbd 324 strtok(NULL, " "); // Ignore the TS
581ec09e 325#endif
c7340cbd 326 channel = strtok(NULL, " ");
581ec09e 327 rest = strtok(NULL, "");
328 tmp = strchr(rest, ':');
329 tmp++;
330 nick = strtok(tmp, " ");
331 while (nick != NULL)
332 {
333 if (*nick == '@')
334 nick++;
335 if (*nick == '+')
336 nick++; // Assume for users set op and voice, they
337 // are never passed as +@nick
338 if (stricmp(channel, c_Forest) == 0 && is_playing(nick))
339 raw(":%S MODE %s +v %s", channel, nick);
340
341 nick = strtok(NULL, " ");
342 }
343#endif
85ce9d3e 344 } else {
9f8c2acc 345 #ifdef DEBUGMODE
346 log("Unrecognized Message: cmd = %s source = %s", cmd, source);
347 #endif
85ce9d3e 348 }
349 }
4dde2ed9 350
351 end:
352
c8ada07e 353 save_gs_dbase();
44ea29f7 354 save_timestamp();
4dde2ed9 355
c8ada07e 356 delete_monsters();
357 delete_masters();
358
9f8c2acc 359 #ifdef DEBUGMODE
360 log("<CLOSED>");
361 #endif
362
85ce9d3e 363 close(sock);
364 unload_config_file();
365 return 0;
366}
367
368aClient *find(char *nick)
369{
370 return findbynick(nick);
371}
372
373aClient *find(const char *nick)
374{
375 return findbynick(nick);
376}
377
ce61cdfa 378#ifdef P10
379
380aClient *findbyrealnick(char *realnick)
381{
382 ListNode <aClient> *newPtr;
383 newPtr = clients.First();
384
385 aClient *client = NULL;
386
387 while (newPtr)
388 {
389 client = newPtr->getData();
390 if (stricmp(client->getRealNick(), realnick) == 0)
391 return client;
392 client = NULL;
393 newPtr = newPtr->Next();
394 }
395 return client;
396}
397#endif
85ce9d3e 398
399aClient *findbynick(char *nick)
400{
401 ListNode <aClient> *newPtr;
402 newPtr = clients.First();
403
404 aClient *client = NULL;
405
406 while (newPtr)
407 {
408 client = newPtr->getData();
23ec3ff4 409 #ifdef P10
23ec3ff4 410 if (strcmp(client->getNick(), nick) == 0)
411 #else
412 if (stricmp(client->getNick(), nick) == 0)
413 #endif
85ce9d3e 414 return client;
415 client = NULL;
416 newPtr = newPtr->Next();
417 }
418 return client;
419}
420
ee38284f 421aClient *findIRCplayer(const char *nick)
422{
423 ListNode <aClient> *newPtr;
424 aClient *p = NULL;
425
426 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
427 {
428 p = newPtr->getData();
23ec3ff4 429 #ifdef P10
430 if (strcmp(p->getNick(), nick) == 0)
431 #else
432 if (stricmp(p->getNick(), nick) == 0)
433 #endif
ee38284f 434 return p;
435 p = NULL;
436 }
437 return NULL;
438}
0a1518fa 439aClient *findplayer(const char *name)
440{
441 ListNode <aClient> *newPtr;
442 Player *p = NULL;
443
444 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
445 {
446 p = newPtr->getData()->stats;
447 if (stricmp(p->name, name) == 0)
448 return newPtr->getData();
449 p = NULL;
450 }
451 return NULL;
452}
453
85ce9d3e 454aClient *findbynick(const char *nick)
455{
456 ListNode <aClient> *newPtr;
457 newPtr = clients.First();
458
459 aClient *client = NULL;
460
461 while (newPtr)
462 {
463 client = newPtr->getData();
23ec3ff4 464 #ifdef P10
465 if (strcmp(client->getNick(), nick) == 0)
466 #else
467 if (stricmp(client->getNick(), nick) == 0)
468 #endif
85ce9d3e 469 return client;
470 client = NULL;
471 newPtr = newPtr->Next();
472 }
473 return client;
474}
475
44ea29f7 476void load_timestamp()
477{
478 ifstream infile;
479
480 infile.open(".gstimestamp");
481
482 if (infile.fail())
483 {
9f8c2acc 484 #ifdef DEBUGMODE
485 log("Error opening .gstimestamp");
486 #endif
487
44ea29f7 488 generate:
9f8c2acc 489 #ifdef DEBUGMODE
490 log("Generating new timestamp");
491 #endif
44ea29f7 492 timestamp = midnight();
493 save_timestamp();
494 return;
495 }
496
497 infile >> timestamp;
498 infile.close();
499 if (timestamp < 1000000)
500 goto generate;
501}
502
503void save_timestamp()
504{
505 ofstream outfile;
506
507 outfile.open(".gstimestamp");
508
509 if (outfile.fail())
510 {
fb37ecc7 511 log("Error creating new file .gstimestamp");
44ea29f7 512 return;
513 }
514
515 outfile << timestamp << endl;
516
517 outfile.close();
518}
519
520long int midnight(long int offset)
521{
522 return (time(NULL) - (time(NULL) % 86400)) + (offset * 3600);
523}
ce61cdfa 524
525/* daemon() - detach process from user and disappear into the background
526 * returns -1 on failure, but you can't do much except exit in that case
527 * since we may already have forked. This is based on the BSD version,
528 * so the caller is responsible for things like the umask, etc.
529 */
530
531/* believed to work on all Posix systems */
532
533int daemon(int nochdir, int noclose)
534{
535 pid_t pid;
536 switch (pid = fork())
537 {
538 case 0: break;
539 case -1: return -1;
540 default: _exit(0); /* exit the original process */
541 }
542
543 if (setsid() < 0) /* shoudn't fail */
544 return -1;
545
546 /* dyke out this switch if you want to acquire a control tty in */
547 /* the future -- not normally advisable for daemons */
548
549 switch (pid = fork())
550 {
551 case 0: break;
552 case -1: return -1;
553 default:
554 ofstream outfile;
555 outfile.open("gameserv.pid");
556 if (outfile.fail())
557 cerr << "Unable to open gameserv.pid" << endl;
558 outfile << pid << endl;
559 outfile.close();
560
561 _exit(0);
562 }
563
564 if (!nochdir)
565 chdir("/");
566
567 if (!noclose)
568 {
569 closeall(0);
570 open("/dev/null",O_RDWR);
571 dup(0); dup(0);
572 }
573
574 return 0;
575}
576
577
578/* closeall() -- close all FDs >= a specified value */
579
580void closeall(int fd)
581{
582 int fdlimit = sysconf(_SC_OPEN_MAX);
583
584 while (fd < fdlimit)
585 close(fd++);
586}
587
588