]> jfr.im git - irc/gameservirc.git/blob - gameserv/tcpclient.cpp
Made config.cpp output errors now that it's a true daemon!
[irc/gameservirc.git] / gameserv / tcpclient.cpp
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"
16 #include "options.h"
17 #include "list.h"
18 #include "aClient.h"
19 #include "extern.h"
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <fstream>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 //#include <sys/types.h>
28 //#include <sys/wait.h>
29 //#include <errno.h>
30
31
32
33 using std::ofstream;
34 using std::ifstream;
35 using std::cerr;
36 using std::endl;
37
38 char *PACKAGE = "GameServ";
39 char *VERSION = "1.1.8";
40
41 int sock;
42 long timestamp;
43
44 List<aClient> clients;
45
46 void save_timestamp();
47 void load_timestamp();
48
49 // Make this a daemon
50 int daemon(int nochdir, int noclose);
51
52 // Close all file descriptors from >= fd
53 void closeall(int fd);
54
55 int main()
56 {
57 char buffer[1024], buf[1024];
58 int connected = 1;
59 char *cmd, *source = NULL;
60 srand(time(NULL));
61
62
63 load_config_file(); // default = gameserv.conf
64
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
72 ignore_pipe();
73 sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
74 if (sock == -1) {
75 fprintf(stderr,"make_connection failed.\n");
76 unload_config_file();
77 return -1;
78 }
79
80 #ifdef UNREAL
81 raw("PROTOCTL NICKv2 VHP");
82 raw("PASS :%s", remotepass);
83 raw("SERVER %s 1 :%s", servername, servername);
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);
86 raw(":%S JOIN %s", c_Forest);
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);
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);
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);
107 #endif
108
109 #if defined(P10)
110 raw("%s T %s :%s", gsnum, c_Forest, c_ForestTopic);
111 raw("[] EB"); // End burst
112 #else
113 #ifndef HYBRID
114 raw(":%S MODE %s +o %S", c_Forest);
115 #endif
116 raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
117 #endif
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
124 #ifdef DEBUGMODE
125 log("Server: %s",buffer);
126 #endif
127
128 init_masters();
129 load_gs_dbase();
130 load_timestamp();
131 long int loadtime = time(NULL);
132 long int currentTime;
133 long int oldTime = loadtime;
134 bool loaded = false;
135
136 if (load_monsters() == false)
137 goto end;
138
139 while (connected) {
140 if (sock_gets(sock,buffer,sizeof(buffer)) == -1) {
141 connected = 0;
142 }
143 strcpy(buf, buffer);
144
145 #if !defined(P10)
146 if (buffer[0] == ':')
147 {
148 source = strtok(buf, " ");
149 cmd = strtok(NULL, " ");
150 }
151 else
152 cmd = strtok(buf, " ");
153 #else
154 source = strtok(buf, " ");
155 cmd = strtok(NULL, " ");
156 #endif
157
158 #ifdef DEBUGMODE
159 log("Server: %s", buffer);
160 #endif
161
162 // Wait N seconds then we're loaded.
163 if (!loaded)
164 {
165 if (time(NULL) >= welcomedelay + loadtime)
166 loaded = true;
167 }
168
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
177
178 #if !defined(P10)
179 if (stricmp(cmd, "PING") == 0) {
180 char *timestamp;
181 timestamp = strtok(NULL, "");
182 raw("PONG %s", timestamp);
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
189 #ifdef P10
190 } else if (stricmp(cmd, "EB") == 0) {
191 raw("[] EA");
192 #endif
193 } else if (stricmp(cmd, "VERSION") == 0) {
194 char *server;
195 server = strtok(NULL, " ");
196 server++;
197 raw(":%s 351 %s %s_%s. %s", servername, source+1, PACKAGE, VERSION, servername);
198 #if !defined(P10)
199 } else if (strncmp(cmd, "NICK", 4) == 0) {
200 if (buffer[0] == ':')
201 {
202 aClient *tempPtr;
203 if ((tempPtr = find((source + 1))))
204 {
205 char *nick;
206 nick = strtok(NULL, " ");
207 tempPtr->setNick(nick);
208 }
209 }
210 else
211 {
212 char *nick;
213 #else
214 } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
215 {
216 char *nick, *realnick;
217 realnick = strtok(NULL, " ");
218
219 for (int x = 0; x < 5; x++)
220 nick = strtok(NULL, " ");
221
222 if (nick[0] == '+')
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 }
239 #endif
240 aClient *newuser;
241
242 nick = strtok(NULL, " ");
243
244 #ifdef P10
245 newuser = new aClient(nick, realnick);
246 #else
247 newuser = new aClient(nick);
248 #endif
249
250
251 if (loaded)
252 #ifdef P10
253 notice(s_GameServ, nick, welcomemsg, realnick);
254 #else
255 notice(s_GameServ, nick, welcomemsg, nick);
256 #endif
257
258 clients.insertAtBack(newuser);
259 delete newuser;
260 }
261 #if defined(P10)
262 } else if (stricmp(cmd, "Q") == 0) {
263 #else
264 } else if (stricmp(cmd, "QUIT") == 0) {
265 #endif
266 aClient *quitter;
267 char z = source[0];
268
269 if (z == ':')
270 source++;
271
272 if ((quitter = find(source)))
273 clients.remove(quitter);
274 if ((quitter = findIRCplayer(source)))
275 {
276 quitter->setNick("!NULL!");
277 quitter->stats->user = NULL; // Unidentify them
278 }
279
280 if (z == ':')
281 source--;
282
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);
290
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
304 } else if (stricmp(cmd, "PRIVMSG") == 0) {
305 char *rest, *dest;
306 dest = strtok(NULL, " ");
307 rest = strtok(NULL, "");
308 if (strnicmp(dest, s_GameServ, strlen(s_GameServ)) == 0)
309 gameserv(source, rest);
310 else if (stricmp(dest, c_Forest) == 0)
311 forest(source, rest);
312 #endif
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));
318
319 #if defined(BAHAMUT)
320 } else if (stricmp(cmd, "SJOIN") == 0) {
321 char *channel, *nick, *tmp, *rest;
322 strtok(NULL, " "); // Ignore the TS
323 #ifndef HYBRID
324 strtok(NULL, " "); // Ignore the TS
325 #endif
326 channel = strtok(NULL, " ");
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
344 } else {
345 #ifdef DEBUGMODE
346 log("Unrecognized Message: cmd = %s source = %s", cmd, source);
347 #endif
348 }
349 }
350
351 end:
352
353 save_gs_dbase();
354 save_timestamp();
355
356 delete_monsters();
357 delete_masters();
358
359 #ifdef DEBUGMODE
360 log("<CLOSED>");
361 #endif
362
363 close(sock);
364 unload_config_file();
365 return 0;
366 }
367
368 aClient *find(char *nick)
369 {
370 return findbynick(nick);
371 }
372
373 aClient *find(const char *nick)
374 {
375 return findbynick(nick);
376 }
377
378 #ifdef P10
379
380 aClient *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
398 #else
399
400 aClient *findbyrealnick(char *realnick)
401 {
402 return findbynick(realnick);
403 }
404
405 #endif
406
407 aClient *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();
417 #ifdef P10
418 if (strcmp(client->getNick(), nick) == 0)
419 #else
420 if (stricmp(client->getNick(), nick) == 0)
421 #endif
422 return client;
423 client = NULL;
424 newPtr = newPtr->Next();
425 }
426 return client;
427 }
428
429 aClient *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();
437 #ifdef P10
438 if (strcmp(p->getNick(), nick) == 0)
439 #else
440 if (stricmp(p->getNick(), nick) == 0)
441 #endif
442 return p;
443 p = NULL;
444 }
445 return NULL;
446 }
447 aClient *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
462 aClient *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();
472 #ifdef P10
473 if (strcmp(client->getNick(), nick) == 0)
474 #else
475 if (stricmp(client->getNick(), nick) == 0)
476 #endif
477 return client;
478 client = NULL;
479 newPtr = newPtr->Next();
480 }
481 return client;
482 }
483
484 void load_timestamp()
485 {
486 ifstream infile;
487
488 infile.open(".gstimestamp");
489
490 if (infile.fail())
491 {
492 #ifdef DEBUGMODE
493 log("Error opening .gstimestamp");
494 #endif
495
496 generate:
497 #ifdef DEBUGMODE
498 log("Generating new timestamp");
499 #endif
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
511 void save_timestamp()
512 {
513 ofstream outfile;
514
515 outfile.open(".gstimestamp");
516
517 if (outfile.fail())
518 {
519 log("Error creating new file .gstimestamp");
520 return;
521 }
522
523 outfile << timestamp << endl;
524
525 outfile.close();
526 }
527
528 long int midnight(long int offset)
529 {
530 return (time(NULL) - (time(NULL) % 86400)) + (offset * 3600);
531 }
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
541 int 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
588 void closeall(int fd)
589 {
590 int fdlimit = sysconf(_SC_OPEN_MAX);
591
592 while (fd < fdlimit)
593 close(fd++);
594 }
595
596