]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd_io.cpp
Made setrlimit a commandline option
[user/henk/code/inspircd.git] / src / inspircd_io.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include <sys/time.h>
18 #include <sys/resource.h>
19 #include <sys/types.h>
20 #include <string>
21 #include <unistd.h>
22 #include <sstream>
23 #include <iostream>
24 #include <fstream>
25 #include "inspircd.h"
26 #include "inspircd_io.h"
27 #include "inspircd_util.h"
28 #include "inspstring.h"
29
30 using namespace std;
31
32 extern FILE *log_file;
33 extern int boundPortCount;
34 extern int openSockfd[MAXSOCKS];
35 extern time_t TIME;
36 extern bool unlimitcore;
37
38 void WriteOpers(char* text, ...);
39
40 void Exit (int status)
41 {
42         if (log_file)
43                 fclose(log_file);
44         send_error("Server shutdown.");
45
46         // close down all listening sockets
47         for (int count = 0; count < boundPortCount; count++)
48         {
49                 shutdown(openSockfd[count], 2);
50         }
51
52         exit (status);
53 }
54
55 void Killed(int status)
56 {
57         if (log_file)
58                 fclose(log_file);
59         send_error("Server terminated.");
60         // close down all listening sockets
61         for (int count = 0; count < boundPortCount; count++)
62         {
63                 shutdown(openSockfd[count], 2);
64         }
65         exit(status);
66 }
67
68 void Rehash(int status)
69 {
70         WriteOpers("Rehashing config file %s due to SIGHUP",CONFIG_FILE);
71         ReadConfig(false,NULL);
72 }
73
74
75
76 void Start (void)
77 {
78         printf("\033[1mInspire Internet Relay Chat Server, compiled " __DATE__ " at " __TIME__ "\n");
79         printf("(C) ChatSpike Development team.\033[0;37m\n\n");
80         printf("Developers:\033[1m     Brain, FrostyCoolSlug\n");
81         printf("Documentation:\033[1m  FrostyCoolSlug, w00t\n");
82         printf("Testers:\033[1m        typobox43, piggles, Lord_Zathras, CC\n");
83         printf("Name concept:\033[1m   Lord_Zathras\n\n");
84 }
85
86 void WritePID(std::string filename)
87 {
88         ofstream outfile(filename.c_str());
89         if (outfile.is_open())
90         {
91                 outfile << getpid();
92                 outfile.close();
93         }
94         else
95         {
96                 printf("Failed to write PID-file '%s', exiting.\n",filename.c_str());
97                 log(DEFAULT,"Failed to write PID-file '%s', exiting.",filename.c_str());
98                 Exit(0);
99         }
100 }
101
102 void DeadPipe(int status)
103 {
104   signal (SIGPIPE, DeadPipe);
105 }
106
107 int DaemonSeed (void)
108 {
109         int childpid;
110         signal (SIGALRM, SIG_IGN);
111         signal (SIGHUP, Rehash);
112         signal (SIGPIPE, DeadPipe);
113         signal (SIGTERM, Exit);
114         signal (SIGABRT, Exit);
115         signal (SIGSEGV, Error);
116         signal (SIGURG, Exit);
117         signal (SIGKILL, Exit);
118         if ((childpid = fork ()) < 0)
119                 return (ERROR);
120         else if (childpid > 0)
121                 exit (0);
122         setsid ();
123         umask (007);
124         /* close stdin, stdout, stderr */
125         freopen("/dev/null","w",stdout);
126         freopen("/dev/null","w",stderr);
127         
128         setpriority(PRIO_PROCESS,(int)getpid(),15); /* ircd sets to low process priority so it doesnt hog the box */
129
130         if (unlimitcore)
131         {
132                 rlimit rl;
133                 if (getrlimit(RLIMIT_CORE, &rl) == -1)
134                 {
135                         log(DEFAULT,"Failed to getrlimit()!");
136                         return(FALSE);
137                 }
138                 else
139                 {
140                         rl.rlim_cur = rl.rlim_max;
141                         if (setrlimit(RLIMIT_CORE, &rl) == -1)
142                                 log(DEFAULT,"setrlimit() failed, cannot increase coredump size.");
143                 }
144         }
145   
146         return (TRUE);
147 }
148
149
150 /* Make Sure Modules Are Avaliable!
151  * (BugFix By Craig.. See? I do work! :p)
152  * Modified by brain, requires const char*
153  * to work with other API functions
154  */
155
156 bool FileExists (const char* file)
157 {
158         FILE *input;
159         if ((input = fopen (file, "r")) == NULL)
160         {
161                 return(false);
162         }
163         else
164         {
165                 fclose (input);
166                 return(true);
167         }
168 }
169
170 /* ConfProcess does the following things to a config line in the following order:
171  *
172  * Processes the line for syntax errors as shown below
173  *      (1) Line void of quotes or equals (a malformed, illegal tag format)
174  *      (2) Odd number of quotes on the line indicating a missing quote
175  *      (3) number of equals signs not equal to number of quotes / 2 (missing an equals sign)
176  *      (4) Spaces between the opening bracket (<) and the keyword
177  *      (5) Spaces between a keyword and an equals sign
178  *      (6) Spaces between an equals sign and a quote
179  * Removes trailing spaces
180  * Removes leading spaces
181  * Converts tabs to spaces
182  * Turns multiple spaces that are outside of quotes into single spaces
183  */
184
185 std::string ConfProcess(char* buffer, long linenumber, std::stringstream* errorstream, bool &error, std::string filename)
186 {
187         long number_of_quotes = 0;
188         long number_of_equals = 0;
189         bool has_open_bracket = false;
190         bool in_quotes = false;
191         error = false;
192         if (!buffer)
193         {
194                 return "";
195         }
196         // firstly clean up the line by stripping spaces from the start and end and converting tabs to spaces
197         for (int d = 0; d < strlen(buffer); d++)
198                 if ((buffer[d]) == 9)
199                         buffer[d] = ' ';
200         while ((buffer[0] == ' ') && (strlen(buffer)>0)) buffer++;
201         while ((buffer[strlen(buffer)-1] == ' ') && (strlen(buffer)>0)) buffer[strlen(buffer)-1] = '\0';
202         // empty lines are syntactically valid
203         if (!strcmp(buffer,""))
204                 return "";
205         else if (buffer[0] == '#')
206                 return "";
207         for (int c = 0; c < strlen(buffer); c++)
208         {
209                 // convert all spaces that are OUTSIDE quotes into hardspace (0xA0) as this will make them easier to
210                 // search and replace later :)
211                 if ((!in_quotes) && (buffer[c] == ' '))
212                         buffer[c] = '\xA0';
213                 if ((buffer[c] == '<') && (!in_quotes))
214                 {
215                         has_open_bracket = true;
216                         if (strlen(buffer) == 1)
217                         {
218                                 *errorstream << "Tag without identifier at " << filename << ":" << linenumber << endl;
219                                 error = true;
220                                 return "";
221                         }
222                         else if ((tolower(buffer[c+1]) < 'a') || (tolower(buffer[c+1]) > 'z'))
223                         {
224                                 *errorstream << "Invalid characters in identifier at " << filename << ":" << linenumber << endl;
225                                 error = true;
226                                 return "";
227                         }
228                 }
229                 if (buffer[c] == '"')
230                 {
231                         number_of_quotes++;
232                         in_quotes = (!in_quotes);
233                 }
234                 if ((buffer[c] == '=') && (!in_quotes))
235                 {
236                         number_of_equals++;
237                         if (strlen(buffer) == c)
238                         {
239                                 *errorstream << "Variable without a value at " << filename << ":" << linenumber << endl;
240                                 error = true;
241                                 return "";
242                         }
243                         else if (buffer[c+1] != '"')
244                         {
245                                 *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl;
246                                 error = true;
247                                 return "";
248                         }
249                         else if (!c)
250                         {
251                                 *errorstream << "Value without a variable (line starts with '=') at " << filename << ":" << linenumber << endl;
252                                 error = true;
253                                 return "";
254                         }
255                         else if (buffer[c-1] == '\xA0')
256                         {
257                                 *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl;
258                                 error = true;
259                                 return "";
260                         }
261                 }
262         }
263         // no quotes, and no equals. something freaky.
264         if ((!number_of_quotes) || (!number_of_equals) && (strlen(buffer)>2) && (buffer[0]=='<'))
265         {
266                 *errorstream << "Malformed tag at " << filename << ":" << linenumber << endl;
267                 error = true;
268                 return "";
269         }
270         // odd number of quotes. thats just wrong.
271         if ((number_of_quotes % 2) != 0)
272         {
273                 *errorstream << "Missing \" at " << filename << ":" << linenumber << endl;
274                 error = true;
275                 return "";
276         }
277         if (number_of_equals < (number_of_quotes/2))
278         {
279                 *errorstream << "Missing '=' at " << filename << ":" << linenumber << endl;
280         }
281         if (number_of_equals > (number_of_quotes/2))
282         {
283                 *errorstream << "Too many '=' at " << filename << ":" << linenumber << endl;
284         }
285
286         std::string parsedata = buffer;
287         // turn multispace into single space
288         while (parsedata.find("\xA0\xA0") != std::string::npos)
289         {
290                 parsedata.erase(parsedata.find("\xA0\xA0"),1);
291         }
292
293         // turn our hardspace back into softspace
294         for (int d = 0; d < parsedata.length(); d++)
295         {
296                 if (parsedata[d] == '\xA0')
297                         parsedata[d] = ' ';
298         }
299
300         // and we're done, the line is fine!
301         return parsedata;
302 }
303
304 bool LoadConf(const char* filename, std::stringstream *target, std::stringstream* errorstream)
305 {
306         target->str("");
307         errorstream->str("");
308         long linenumber = 1;
309         // first, check that the file exists before we try to do anything with it
310         if (!FileExists(filename))
311         {
312                 *errorstream << "File " << filename << " not found." << endl;
313                 return false;
314         }
315         // Fix the chmod of the file to restrict it to the current user and group
316         chmod(filename,0600);
317         // now open it
318         FILE* conf = fopen(filename,"r");
319         char buffer[MAXBUF];
320         if (conf)
321         {
322                 while (!feof(conf))
323                 {
324                         if (fgets(buffer, MAXBUF, conf))
325                         {
326                                 if ((!feof(conf)) && (buffer) && (strlen(buffer)))
327                                 {
328                                         if ((buffer[0] != '#') && (buffer[0] != '\r')  && (buffer[0] != '\n'))
329                                         {
330                                                 bool error = false;
331                                                 std::string data = ConfProcess(buffer,linenumber++,errorstream,error,filename);
332                                                 if (error)
333                                                 {
334                                                         return false;
335                                                 }
336                                                 *target << data;
337                                         }
338                                         else linenumber++;
339                                 }
340                         }
341                 }
342                 fclose(conf);
343         }
344         target->seekg(0);
345         return true;
346 }
347
348 /* Counts the number of tags of a certain type within the config file, e.g. to enumerate opers */
349
350 int EnumConf(std::stringstream *config, const char* tag)
351 {
352         int ptr = 0;
353         char buffer[MAXBUF], c_tag[MAXBUF], c, lastc;
354         int in_token, in_quotes, tptr, j, idx = 0;
355         char* key;
356
357         const char* buf = config->str().c_str();
358         long bptr = 0;
359         long len = strlen(buf);
360         
361         ptr = 0;
362         in_token = 0;
363         in_quotes = 0;
364         lastc = '\0';
365         while (bptr<len)
366         {
367                 lastc = c;
368                 c = buf[bptr++];
369                 if ((c == '#') && (lastc == '\n'))
370                 {
371                         while ((c != '\n') && (bptr<len))
372                         {
373                                 lastc = c;
374                                 c = buf[bptr++];
375                         }
376                 }
377                 if ((c == '<') && (!in_quotes))
378                 {
379                         tptr = 0;
380                         in_token = 1;
381                         do {
382                                 c = buf[bptr++];
383                                 if (c != ' ')
384                                 {
385                                         c_tag[tptr++] = c;
386                                         c_tag[tptr] = '\0';
387                                 }
388                         } while (c != ' ');
389                 }
390                 if (c == '"')
391                 {
392                         in_quotes = (!in_quotes);
393                 }
394                 if ((c == '>') && (!in_quotes))
395                 {
396                         in_token = 0;
397                         if (!strcmp(c_tag,tag))
398                         {
399                                 /* correct tag, but wrong index */
400                                 idx++;
401                         }
402                         c_tag[0] = '\0';
403                         buffer[0] = '\0';
404                         ptr = 0;
405                         tptr = 0;
406                 }
407                 if (c != '>')
408                 {
409                         if ((in_token) && (c != '\n') && (c != '\r'))
410                         {
411                                 buffer[ptr++] = c;
412                                 buffer[ptr] = '\0';
413                         }
414                 }
415         }
416         return idx;
417 }
418
419 /* Counts the number of values within a certain tag */
420
421 int EnumValues(std::stringstream *config, const char* tag, int index)
422 {
423         int ptr = 0;
424         char buffer[MAXBUF], c_tag[MAXBUF], c, lastc;
425         int in_token, in_quotes, tptr, j, idx = 0;
426         char* key;
427         
428         bool correct_tag = false;
429         int num_items = 0;
430
431         const char* buf = config->str().c_str();
432         long bptr = 0;
433         long len = strlen(buf);
434         
435         ptr = 0;
436         in_token = 0;
437         in_quotes = 0;
438         lastc = '\0';
439         while (bptr<len)
440         {
441                 lastc = c;
442                 c = buf[bptr++];
443                 if ((c == '#') && (lastc == '\n'))
444                 {
445                         while ((c != '\n') && (bptr<len))
446                         {
447                                 lastc = c;
448                                 c = buf[bptr++];
449                         }
450                 }
451                 if ((c == '<') && (!in_quotes))
452                 {
453                         tptr = 0;
454                         in_token = 1;
455                         do {
456                                 c = buf[bptr++];
457                                 if (c != ' ')
458                                 {
459                                         c_tag[tptr++] = c;
460                                         c_tag[tptr] = '\0';
461                                         
462                                         if ((!strcmp(c_tag,tag)) && (idx == index))
463                                         {
464                                                 correct_tag = true;
465                                         }
466                                 }
467                         } while (c != ' ');
468                 }
469                 if (c == '"')
470                 {
471                         in_quotes = (!in_quotes);
472                 }
473                 
474                 if ( (correct_tag) && (!in_quotes) && ( (c == ' ') || (c == '\n') || (c == '\r') ) )
475                 {
476                         num_items++;
477                 }
478                 if ((c == '>') && (!in_quotes))
479                 {
480                         in_token = 0;
481                         if (correct_tag)
482                                 correct_tag = false;
483                         if (!strcmp(c_tag,tag))
484                         {
485                                 /* correct tag, but wrong index */
486                                 idx++;
487                         }
488                         c_tag[0] = '\0';
489                         buffer[0] = '\0';
490                         ptr = 0;
491                         tptr = 0;
492                 }
493                 if (c != '>')
494                 {
495                         if ((in_token) && (c != '\n') && (c != '\r'))
496                         {
497                                 buffer[ptr++] = c;
498                                 buffer[ptr] = '\0';
499                         }
500                 }
501         }
502         return num_items+1;
503 }
504
505
506
507 int ConfValueEnum(char* tag, std::stringstream* config)
508 {
509         return EnumConf(config,tag);
510 }
511
512
513
514 /* Retrieves a value from the config file. If there is more than one value of the specified
515  * key and section (e.g. for opers etc) then the index value specifies which to retreive, e.g.
516  *
517  * ConfValue("oper","name",2,result);
518  */
519
520 int ReadConf(std::stringstream *config, const char* tag, const char* var, int index, char *result)
521 {
522         int ptr = 0;
523         char buffer[65535], c_tag[MAXBUF], c, lastc;
524         int in_token, in_quotes, tptr, j, idx = 0;
525         char* key;
526
527         const char* buf = config->str().c_str();
528         long bptr = 0;
529         long len = strlen(buf);
530         
531         ptr = 0;
532         in_token = 0;
533         in_quotes = 0;
534         lastc = '\0';
535         c_tag[0] = '\0';
536         buffer[0] = '\0';
537         while (bptr<len)
538         {
539                 lastc = c;
540                 c = buf[bptr++];
541                 // FIX: Treat tabs as spaces
542                 if (c == 9)
543                         c = 32;
544                 if ((c == '<') && (!in_quotes))
545                 {
546                         tptr = 0;
547                         in_token = 1;
548                         do {
549                                 c = buf[bptr++];
550                                 if (c != ' ')
551                                 {
552                                         c_tag[tptr++] = c;
553                                         c_tag[tptr] = '\0';
554                                 }
555                         // FIX: Tab can follow a tagname as well as space.
556                         } while ((c != ' ') && (c != 9));
557                 }
558                 if (c == '"')
559                 {
560                         in_quotes = (!in_quotes);
561                 }
562                 if ((c == '>') && (!in_quotes))
563                 {
564                         in_token = 0;
565                         if (idx == index)
566                         {
567                                 if (!strcmp(c_tag,tag))
568                                 {
569                                         if ((buffer) && (c_tag) && (var))
570                                         {
571                                                 key = strstr(buffer,var);
572                                                 if (!key)
573                                                 {
574                                                         /* value not found in tag */
575                                                         strcpy(result,"");
576                                                         return 0;
577                                                 }
578                                                 else
579                                                 {
580                                                         key+=strlen(var);
581                                                         while (key[0] !='"')
582                                                         {
583                                                                 if (!strlen(key))
584                                                                 {
585                                                                         /* missing quote */
586                                                                         strcpy(result,"");
587                                                                         return 0;
588                                                                 }
589                                                                 key++;
590                                                         }
591                                                         key++;
592                                                         for (j = 0; j < strlen(key); j++)
593                                                         {
594                                                                 if (key[j] == '"')
595                                                                 {
596                                                                         key[j] = '\0';
597                                                                 }
598                                                         }
599                                                         strlcpy(result,key,MAXBUF);
600                                                         return 1;
601                                                 }
602                                         }
603                                 }
604                         }
605                         if (!strcmp(c_tag,tag))
606                         {
607                                 /* correct tag, but wrong index */
608                                 idx++;
609                         }
610                         c_tag[0] = '\0';
611                         buffer[0] = '\0';
612                         ptr = 0;
613                         tptr = 0;
614                 }
615                 if (c != '>')
616                 {
617                         if ((in_token) && (c != '\n') && (c != '\r'))
618                         {
619                                 buffer[ptr++] = c;
620                                 buffer[ptr] = '\0';
621                         }
622                 }
623         }
624         strcpy(result,""); // value or its tag not found at all
625         return 0;
626 }
627
628
629
630 int ConfValue(char* tag, char* var, int index, char *result,std::stringstream *config)
631 {
632         ReadConf(config, tag, var, index, result);
633         return 0;
634 }
635
636
637
638 // This will bind a socket to a port. It works for UDP/TCP
639 int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr)
640 {
641         bzero((char *)&server,sizeof(server));
642         struct in_addr addy;
643         inet_aton(addr,&addy);
644         server.sin_family = AF_INET;
645         if (!strcmp(addr,""))
646         {
647                 server.sin_addr.s_addr = htonl(INADDR_ANY);
648         }
649         else
650         {
651                 server.sin_addr = addy;
652         }
653         server.sin_port = htons(port);
654         if (bind(sockfd,(struct sockaddr*)&server,sizeof(server))<0)
655         {
656                 return(ERROR);
657         }
658         else
659         {
660                 listen(sockfd,5);
661                 return(TRUE);
662         }
663 }
664
665
666 // Open a TCP Socket
667 int OpenTCPSocket (void)
668 {
669         int sockfd;
670         int on = 0;
671         struct linger linger = { 0 };
672   
673         if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
674                 return (ERROR);
675         else
676         {
677                 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
678                 /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
679                 linger.l_onoff = 1;
680                 linger.l_linger = 0;
681                 setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&linger,sizeof(linger));
682                 return (sockfd);
683         }
684 }
685