]> jfr.im git - irc/gameservirc.git/blame - gameserv/tcpclient.cpp
Made config.cpp output errors now that it's a true daemon!
[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++;
2e9db9c4 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}
4e5760fd 397
398#else
399
400aClient *findbyrealnick(char *realnick)
401{
402 return findbynick(realnick);
403}
404
ce61cdfa 405#endif
85ce9d3e 406
407aClient *findbynick(char *nick)
408{
409 ListNode <aClient> *newPtr;
410 newPtr = clients.First();
411
412 aClient *client = NULL;
413
414 while (newPtr)
415 {
416 client = newPtr->getData();
23ec3ff4 417 #ifdef P10
23ec3ff4 418 if (strcmp(client->getNick(), nick) == 0)
419 #else
420 if (stricmp(client->getNick(), nick) == 0)
421 #endif
85ce9d3e 422 return client;
423 client = NULL;
424 newPtr = newPtr->Next();
425 }
426 return client;
427}
428
ee38284f 429aClient *findIRCplayer(const char *nick)
430{
431 ListNode <aClient> *newPtr;
432 aClient *p = NULL;
433
434 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
435 {
436 p = newPtr->getData();
23ec3ff4 437 #ifdef P10
438 if (strcmp(p->getNick(), nick) == 0)
439 #else
440 if (stricmp(p->getNick(), nick) == 0)
441 #endif
ee38284f 442 return p;
443 p = NULL;
444 }
445 return NULL;
446}
0a1518fa 447aClient *findplayer(const char *name)
448{
449 ListNode <aClient> *newPtr;
450 Player *p = NULL;
451
452 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
453 {
454 p = newPtr->getData()->stats;
455 if (stricmp(p->name, name) == 0)
456 return newPtr->getData();
457 p = NULL;
458 }
459 return NULL;
460}
461
85ce9d3e 462aClient *findbynick(const char *nick)
463{
464 ListNode <aClient> *newPtr;
465 newPtr = clients.First();
466
467 aClient *client = NULL;
468
469 while (newPtr)
470 {
471 client = newPtr->getData();
23ec3ff4 472 #ifdef P10
473 if (strcmp(client->getNick(), nick) == 0)
474 #else
475 if (stricmp(client->getNick(), nick) == 0)
476 #endif
85ce9d3e 477 return client;
478 client = NULL;
479 newPtr = newPtr->Next();
480 }
481 return client;
482}
483
44ea29f7 484void load_timestamp()
485{
486 ifstream infile;
487
488 infile.open(".gstimestamp");
489
490 if (infile.fail())
491 {
9f8c2acc 492 #ifdef DEBUGMODE
493 log("Error opening .gstimestamp");
494 #endif
495
44ea29f7 496 generate:
9f8c2acc 497 #ifdef DEBUGMODE
498 log("Generating new timestamp");
499 #endif
44ea29f7 500 timestamp = midnight();
501 save_timestamp();
502 return;
503 }
504
505 infile >> timestamp;
506 infile.close();
507 if (timestamp < 1000000)
508 goto generate;
509}
510
511void save_timestamp()
512{
513 ofstream outfile;
514
515 outfile.open(".gstimestamp");
516
517 if (outfile.fail())
518 {
fb37ecc7 519 log("Error creating new file .gstimestamp");
44ea29f7 520 return;
521 }
522
523 outfile << timestamp << endl;
524
525 outfile.close();
526}
527
528long int midnight(long int offset)
529{
530 return (time(NULL) - (time(NULL) % 86400)) + (offset * 3600);
531}
ce61cdfa 532
533/* daemon() - detach process from user and disappear into the background
534 * returns -1 on failure, but you can't do much except exit in that case
535 * since we may already have forked. This is based on the BSD version,
536 * so the caller is responsible for things like the umask, etc.
537 */
538
539/* believed to work on all Posix systems */
540
541int daemon(int nochdir, int noclose)
542{
543 pid_t pid;
544 switch (pid = fork())
545 {
546 case 0: break;
547 case -1: return -1;
548 default: _exit(0); /* exit the original process */
549 }
550
551 if (setsid() < 0) /* shoudn't fail */
552 return -1;
553
554 /* dyke out this switch if you want to acquire a control tty in */
555 /* the future -- not normally advisable for daemons */
556
557 switch (pid = fork())
558 {
559 case 0: break;
560 case -1: return -1;
561 default:
562 ofstream outfile;
563 outfile.open("gameserv.pid");
564 if (outfile.fail())
565 cerr << "Unable to open gameserv.pid" << endl;
566 outfile << pid << endl;
567 outfile.close();
568
569 _exit(0);
570 }
571
572 if (!nochdir)
573 chdir("/");
574
575 if (!noclose)
576 {
577 closeall(0);
578 open("/dev/null",O_RDWR);
579 dup(0); dup(0);
580 }
581
582 return 0;
583}
584
585
586/* closeall() -- close all FDs >= a specified value */
587
588void closeall(int fd)
589{
590 int fdlimit = sysconf(_SC_OPEN_MAX);
591
592 while (fd < fdlimit)
593 close(fd++);
594}
595
596