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