]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd_io.cpp
combine a couple of if()'s
[user/henk/code/inspircd.git] / src / inspircd_io.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 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 using namespace std;
18
19 #include "inspircd_config.h"
20 #include <sys/time.h>
21 #include <sys/resource.h>
22 #include <sys/types.h>
23 #include <string>
24 #include <unistd.h>
25 #include <sstream>
26 #include <iostream>
27 #include <fstream>
28 #include "message.h"
29 #include "inspircd.h"
30 #include "inspircd_io.h"
31 #include "inspstring.h"
32 #include "helperfuncs.h"
33 #include "userprocess.h"
34 #include "xline.h"
35
36 extern ServerConfig *Config;
37 extern InspIRCd* ServerInstance;
38 extern int openSockfd[MAX_DESCRIPTORS];
39 extern time_t TIME;
40
41 extern int MODCOUNT;
42 extern std::vector<Module*> modules;
43 extern std::vector<ircd_module*> factory;
44
45 std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
46
47 ServerConfig::ServerConfig()
48 {
49         this->ClearStack();
50         *TempDir = *ServerName = *Network = *ServerDesc = *AdminName = '\0';
51         *HideWhoisServer = *AdminEmail = *AdminNick = *diepass = *restartpass = '\0';
52         *CustomVersion = *motd = *rules = *PrefixQuit = *DieValue = *DNSServer = '\0';
53         *OperOnlyStats = *ModPath = *MyExecutable = *DisabledCommands = *PID = '\0';
54         log_file = NULL;
55         OperSpyWhois = nofork = HideBans = HideSplits = false;
56         AllowHalfop = true;
57         dns_timeout = DieDelay = 5;
58         MaxTargets = 20;
59         NetBufferSize = 10240;
60         SoftLimit = MAXCLIENTS;
61         MaxConn = SOMAXCONN;
62         MaxWhoResults = 100;
63         debugging = 0;
64         LogLevel = DEFAULT;
65         maxbans.clear();
66 }
67
68 void ServerConfig::ClearStack()
69 {
70         include_stack.clear();
71 }
72
73 Module* ServerConfig::GetIOHook(int port)
74 {
75         std::map<int,Module*>::iterator x = IOHookModule.find(port);
76         return (x != IOHookModule.end() ? x->second : NULL);
77 }
78
79 bool ServerConfig::AddIOHook(int port, Module* iomod)
80 {
81         if (!GetIOHook(port))
82         {
83                 IOHookModule[port] = iomod;
84                 return true;
85         }
86         else
87         {
88                 ModuleException err("Port already hooked by another module");
89                 throw(err);
90                 return false;
91         }
92 }
93
94 bool ServerConfig::DelIOHook(int port)
95 {
96         std::map<int,Module*>::iterator x = IOHookModule.find(port);
97         if (x != IOHookModule.end())
98         {
99                 IOHookModule.erase(x);
100                 return true;
101         }
102         return false;
103 }
104
105 bool ServerConfig::CheckOnce(char* tag, bool bail, userrec* user)
106 {
107         int count = ConfValueEnum(Config->config_data, tag);
108         
109         if (count > 1)
110         {
111                 if (bail)
112                 {
113                         printf("There were errors in your configuration:\nYou have more than one <%s> tag, this is not permitted.\n",tag);
114                         Exit(0);
115                 }
116                 else
117                 {
118                         if (user)
119                         {
120                                 WriteServ(user->fd,"There were errors in your configuration:");
121                                 WriteServ(user->fd,"You have more than one <%s> tag, this is not permitted.\n",tag);
122                         }
123                         else
124                         {
125                                 WriteOpers("There were errors in the configuration file:");
126                                 WriteOpers("You have more than one <%s> tag, this is not permitted.\n",tag);
127                         }
128                 }
129                 return false;
130         }
131         if (count < 1)
132         {
133                 if (bail)
134                 {
135                         printf("There were errors in your configuration:\nYou have not defined a <%s> tag, this is required.\n",tag);
136                         Exit(0);
137                 }
138                 else
139                 {
140                         if (user)
141                         {
142                                 WriteServ(user->fd,"There were errors in your configuration:");
143                                 WriteServ(user->fd,"You have not defined a <%s> tag, this is required.",tag);
144                         }
145                         else
146                         {
147                                 WriteOpers("There were errors in the configuration file:");
148                                 WriteOpers("You have not defined a <%s> tag, this is required.",tag);
149                         }
150                 }
151                 return false;
152         }
153         return true;
154 }
155
156 bool NoValidation(const char* tag, const char* value, void* data)
157 {
158         log(DEBUG,"No validation for <%s:%s>",tag,value);
159         return true;
160 }
161
162 bool ValidateTempDir(const char* tag, const char* value, void* data)
163 {
164         char* x = (char*)data;
165         if (!*x)
166                 strlcpy(x,"/tmp",1024);
167         return true;
168 }
169  
170 bool ValidateMaxTargets(const char* tag, const char* value, void* data)
171 {
172         int* x = (int*)data;
173         if ((*x < 0) || (*x > 31))
174         {
175                 log(DEFAULT,"WARNING: <options:maxtargets> value is greater than 31 or less than 0, set to 20.");
176                 *x = 20;
177         }
178         return true;
179 }
180
181 bool ValidateSoftLimit(const char* tag, const char* value, void* data)
182 {
183         int* x = (int*)data;    
184         if ((*x < 1) || (*x > MAXCLIENTS))
185         {
186                 log(DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS);
187                 *x = MAXCLIENTS;
188         }
189         return true;
190 }
191
192 bool ValidateMaxConn(const char* tag, const char* value, void* data)
193 {
194         int* x = (int*)data;    
195         if (*x > SOMAXCONN)
196                 log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");
197         if (!*x)
198                 *x = SOMAXCONN;
199         return true;
200 }
201
202 bool ValidateDnsTimeout(const char* tag, const char* value, void* data)
203 {
204         int* x = (int*)data;
205         if (!*x)
206                 *x = 5;
207         return true;
208 }
209
210 bool ValidateDnsServer(const char* tag, const char* value, void* data)
211 {
212         char* x = (char*)data;
213         if (!*x)
214         {
215                 // attempt to look up their nameserver from /etc/resolv.conf
216                 log(DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf...");
217                 ifstream resolv("/etc/resolv.conf");
218                 std::string nameserver;
219                 bool found_server = false;
220
221                 if (resolv.is_open())
222                 {
223                         while (resolv >> nameserver)
224                         {
225                                 if ((nameserver == "nameserver") && (!found_server))
226                                 {
227                                         resolv >> nameserver;
228                                         strlcpy(x,nameserver.c_str(),MAXBUF);
229                                         found_server = true;
230                                         log(DEFAULT,"<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",nameserver.c_str());
231                                 }
232                         }
233
234                         if (!found_server)
235                         {
236                                 log(DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!");
237                                 strlcpy(x,"127.0.0.1",MAXBUF);
238                         }
239                 }
240                 else
241                 {
242                         log(DEFAULT,"/etc/resolv.conf can't be opened! Defaulting to nameserver '127.0.0.1'!");
243                         strlcpy(x,"127.0.0.1",MAXBUF);
244                 }
245         }
246         return true;
247 }
248
249 bool ValidateModPath(const char* tag, const char* value, void* data)
250 {
251         char* x = (char*)data;  
252         if (!*x)
253                 strlcpy(x,MOD_PATH,MAXBUF);
254         return true;
255 }
256
257
258 bool ValidateServerName(const char* tag, const char* value, void* data)
259 {
260         char* x = (char*)data;
261         if (!strchr(x,'.'))
262         {
263                 log(DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",x,x,'.');
264                 charlcat(x,'.',MAXBUF);
265         }
266         //strlower(x);
267         return true;
268 }
269
270 bool ValidateNetworkName(const char* tag, const char* value, void* data)
271 {
272         char* x = (char*)data;
273
274         log(DEFAULT,"<server:network> '%s'",x);
275
276         return true;
277 }
278
279 bool ValidateServerDesc(const char* tag, const char* value, void* data)
280 {
281         char* x = (char*)data;
282
283         log(DEFAULT,"<server:description> '%s'",x);
284
285         return true;
286 }
287
288 bool ValidateNetBufferSize(const char* tag, const char* value, void* data)
289 {
290         if ((!Config->NetBufferSize) || (Config->NetBufferSize > 65535) || (Config->NetBufferSize < 1024))
291         {
292                 log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
293                 Config->NetBufferSize = 10240;
294         }
295         return true;
296 }
297
298 bool ValidateMaxWho(const char* tag, const char* value, void* data)
299 {
300         if ((!Config->MaxWhoResults) || (Config->MaxWhoResults > 65535) || (Config->MaxWhoResults < 1))
301         {
302                 log(DEFAULT,"No MaxWhoResults specified or size out of range, setting to default of 128.");
303                 Config->MaxWhoResults = 128;
304         }
305         return true;
306 }
307
308 bool ValidateLogLevel(const char* tag, const char* value, void* data)
309 {
310         const char* dbg = (const char*)data;
311         Config->LogLevel = DEFAULT;
312         if (!strcmp(dbg,"debug"))
313         {
314                 Config->LogLevel = DEBUG;
315                 Config->debugging = 1;
316         }
317         else if (!strcmp(dbg,"verbose"))
318                 Config->LogLevel = VERBOSE;
319         else if (!strcmp(dbg,"default"))
320                 Config->LogLevel = DEFAULT;
321         else if (!strcmp(dbg,"sparse"))
322                 Config->LogLevel = SPARSE;
323         else if (!strcmp(dbg,"none"))
324                 Config->LogLevel = NONE;
325         return true;
326 }
327
328 bool ValidateMotd(const char* tag, const char* value, void* data)
329 {
330         readfile(Config->MOTD,Config->motd);
331         return true;
332 }
333
334 bool ValidateRules(const char* tag, const char* value, void* data)
335 {
336         readfile(Config->RULES,Config->rules);
337         return true;
338 }
339
340 /* Callback called before processing the first <connect> tag
341  */
342 bool InitConnect(const char* tag)
343 {
344         log(DEFAULT,"Reading connect classes...");
345         Config->Classes.clear();
346         return true;
347 }
348
349 /* Callback called to process a single <connect> tag
350  */
351 bool DoConnect(const char* tag, char** entries, void** values, int* types)
352 {
353         ConnectClass c;
354         char* allow = (char*)values[0]; /* Yeah, there are a lot of values. Live with it. */
355         char* deny = (char*)values[1];
356         char* password = (char*)values[2];
357         int* timeout = (int*)values[3];
358         int* pingfreq = (int*)values[4];
359         int* flood = (int*)values[5];
360         int* threshold = (int*)values[6];
361         int* sendq = (int*)values[7];
362         int* recvq = (int*)values[8];
363         int* localmax = (int*)values[9];
364         int* globalmax = (int*)values[10];
365
366         if (*allow)
367         {
368                 c.host = allow;
369                 c.type = CC_ALLOW;
370                 c.pass = password;
371                 c.registration_timeout = *timeout;
372                 c.pingtime = *pingfreq;
373                 c.flood = *flood;
374                 c.threshold = *threshold;
375                 c.sendqmax = *sendq;
376                 c.recvqmax = *recvq;
377                 c.maxlocal = *localmax;
378                 c.maxglobal = *globalmax;
379
380
381                 if (c.maxlocal == 0)
382                         c.maxlocal = 3;
383                 if (c.maxglobal == 0)
384                         c.maxglobal = 3;
385                 if (c.threshold == 0)
386                 {
387                         c.threshold = 1;
388                         c.flood = 999;
389                         log(DEFAULT,"Warning: Connect allow line '%s' has no flood/threshold settings. Setting this tag to 999 lines in 1 second.",c.host.c_str());
390                 }
391                 if (c.sendqmax == 0)
392                         c.sendqmax = 262114;
393                 if (c.recvqmax == 0)
394                         c.recvqmax = 4096;
395                 if (c.registration_timeout == 0)
396                         c.registration_timeout = 90;
397                 if (c.pingtime == 0)
398                         c.pingtime = 120;
399                 Config->Classes.push_back(c);
400         }
401         else
402         {
403                 c.host = deny;
404                 c.type = CC_DENY;
405                 Config->Classes.push_back(c);
406                 log(DEBUG,"Read connect class type DENY, host=%s",deny);
407         }
408
409         return true;
410 }
411
412 /* Callback called when there are no more <connect> tags
413  */
414 bool DoneConnect(const char* tag)
415 {
416         log(DEBUG,"DoneConnect called for tag: %s",tag);
417         return true;
418 }
419
420 /* Callback called before processing the first <uline> tag
421  */
422 bool InitULine(const char* tag)
423 {
424         Config->ulines.clear();
425         return true;
426 }
427
428 /* Callback called to process a single <uline> tag
429  */
430 bool DoULine(const char* tag, char** entries, void** values, int* types)
431 {
432         char* server = (char*)values[0];
433         log(DEBUG,"Read ULINE '%s'",server);
434         Config->ulines.push_back(server);
435         return true;
436 }
437
438 /* Callback called when there are no more <uline> tags
439  */
440 bool DoneULine(const char* tag)
441 {
442         return true;
443 }
444
445 /* Callback called before processing the first <module> tag
446  */
447 bool InitModule(const char* tag)
448 {
449         old_module_names.clear();
450         new_module_names.clear();
451         added_modules.clear();
452         removed_modules.clear();
453         for (std::vector<std::string>::iterator t = Config->module_names.begin(); t != Config->module_names.end(); t++)
454         {
455                 old_module_names.push_back(*t);
456         }
457         return true;
458 }
459
460 /* Callback called to process a single <module> tag
461  */
462 bool DoModule(const char* tag, char** entries, void** values, int* types)
463 {
464         char* modname = (char*)values[0];
465         new_module_names.push_back(modname);
466         return true;
467 }
468
469 /* Callback called when there are no more <module> tags
470  */
471 bool DoneModule(const char* tag)
472 {
473         // now create a list of new modules that are due to be loaded
474         // and a seperate list of modules which are due to be unloaded
475         for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
476         {
477                 bool added = true;
478
479                 for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
480                 {
481                         if (*old == *_new)
482                                 added = false;
483                 }
484
485                 if (added)
486                         added_modules.push_back(*_new);
487         }
488
489         for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
490         {
491                 bool removed = true;
492                 for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
493                 {
494                         if (*newm == *oldm)
495                                 removed = false;
496                 }
497
498                 if (removed)
499                         removed_modules.push_back(*oldm);
500         }
501         return true;
502 }
503
504 /* Callback called before processing the first <banlist> tag
505  */
506 bool InitMaxBans(const char* tag)
507 {
508         Config->maxbans.clear();
509         return true;
510 }
511
512 /* Callback called to process a single <banlist> tag
513  */
514 bool DoMaxBans(const char* tag, char** entries, void** values, int* types)
515 {
516         char* channel = (char*)values[0];
517         int* limit = (int*)values[1];
518         Config->maxbans[channel] = *limit;
519         return true;
520 }
521
522 /* Callback called when there are no more <banlist> tags.
523  */
524 bool DoneMaxBans(const char* tag)
525 {
526         return true;
527 }
528
529 void ServerConfig::Read(bool bail, userrec* user)
530 {
531         char debug[MAXBUF];             /* Temporary buffer for debugging value */
532         char* data[12];                 /* Temporary buffers for reading multiple occurance tags into */
533         void* ptr[12];                  /* Temporary pointers for passing to callbacks */
534         int r_i[12];                    /* Temporary array for casting */
535         int rem = 0, add = 0;           /* Number of modules added, number of modules removed */
536         std::ostringstream errstr;      /* String stream containing the error output */
537
538         /* These tags MUST occur and must ONLY occur once in the config file */
539         static char* Once[] = { "server", "admin", "files", "power", "options", "pid", NULL };
540
541         /* These tags can occur ONCE or not at all */
542         static InitialConfig Values[] = {
543                 {"options",             "softlimit",            &this->SoftLimit,               DT_INTEGER, ValidateSoftLimit},
544                 {"options",             "somaxconn",            &this->MaxConn,                 DT_INTEGER, ValidateMaxConn},
545                 {"server",              "name",                         &this->ServerName,              DT_CHARPTR, ValidateServerName},
546                 {"server",              "description",          &this->ServerDesc,              DT_CHARPTR, ValidateServerDesc},
547                 {"server",              "network",                      &this->Network,                 DT_CHARPTR, ValidateNetworkName},
548                 {"admin",               "name",                         &this->AdminName,               DT_CHARPTR, NoValidation},
549                 {"admin",               "email",                        &this->AdminEmail,              DT_CHARPTR, NoValidation},
550                 {"admin",               "nick",                         &this->AdminNick,               DT_CHARPTR, NoValidation},
551                 {"files",               "motd",                         &this->motd,                    DT_CHARPTR, ValidateMotd},
552                 {"files",               "rules",                        &this->rules,                   DT_CHARPTR, ValidateRules},
553                 {"power",               "diepass",                      &this->diepass,                 DT_CHARPTR, NoValidation},      
554                 {"power",               "pauseval",                     &this->DieDelay,                DT_INTEGER, NoValidation},
555                 {"power",               "restartpass",          &this->restartpass,             DT_CHARPTR, NoValidation},
556                 {"options",             "prefixquit",           &this->PrefixQuit,              DT_CHARPTR, NoValidation},
557                 {"die",                 "value",                        &this->DieValue,                DT_CHARPTR, NoValidation},
558                 {"options",             "loglevel",                     &debug,                                 DT_CHARPTR, ValidateLogLevel},
559                 {"options",             "netbuffersize",        &this->NetBufferSize,   DT_INTEGER, ValidateNetBufferSize},
560                 {"options",             "maxwho",                       &this->MaxWhoResults,   DT_INTEGER, ValidateMaxWho},
561                 {"options",             "allowhalfop",          &this->AllowHalfop,             DT_BOOLEAN, NoValidation},
562                 {"dns",                 "server",                       &this->DNSServer,               DT_CHARPTR, ValidateDnsServer},
563                 {"dns",                 "timeout",                      &this->dns_timeout,             DT_INTEGER, ValidateDnsTimeout},
564                 {"options",             "moduledir",            &this->ModPath,                 DT_CHARPTR, ValidateModPath},
565                 {"disabled",    "commands",                     &this->DisabledCommands,DT_CHARPTR, NoValidation},
566                 {"options",             "operonlystats",        &this->OperOnlyStats,   DT_CHARPTR, NoValidation},
567                 {"options",             "customversion",        &this->CustomVersion,   DT_CHARPTR, NoValidation},
568                 {"options",             "hidesplits",           &this->HideSplits,              DT_BOOLEAN, NoValidation},
569                 {"options",             "hidebans",                     &this->HideBans,                DT_BOOLEAN, NoValidation},
570                 {"options",             "hidewhois",            &this->HideWhoisServer, DT_CHARPTR, NoValidation},
571                 {"options",             "operspywhois",         &this->OperSpyWhois,    DT_BOOLEAN, NoValidation},
572                 {"options",             "tempdir",                      &this->TempDir,                 DT_CHARPTR, ValidateTempDir},
573                 {"pid",                 "file",                         &this->PID,                             DT_CHARPTR, NoValidation},
574                 {NULL}
575         };
576
577         /* These tags can occur multiple times, and therefore they have special code to read them
578          * which is different to the code for reading the singular tags listed above.
579          */
580         static MultiConfig MultiValues[] = {
581
582                 {"connect",
583                                 {"allow",       "deny",         "password",     "timeout",      "pingfreq",     "flood",
584                                 "threshold",    "sendq",        "recvq",        "localmax",     "globalmax",    NULL},
585                                 {DT_CHARPTR,    DT_CHARPTR,     DT_CHARPTR,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,
586                                  DT_INTEGER,    DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER},
587                                 InitConnect, DoConnect, DoneConnect},
588
589                 {"uline",
590                                 {"server",      NULL},
591                                 {DT_CHARPTR},
592                                 InitULine,DoULine,DoneULine},
593
594                 {"banlist",
595                                 {"chan",        "limit",        NULL},
596                                 {DT_CHARPTR,    DT_INTEGER},
597                                 InitMaxBans, DoMaxBans, DoneMaxBans},
598
599                 {"module",
600                                 {"name",        NULL},
601                                 {DT_CHARPTR},
602                                 InitModule, DoModule, DoneModule},
603
604                 {"badip",
605                                 {"reason",      "ipmask",       NULL},
606                                 {DT_CHARPTR,    DT_CHARPTR},
607                                 InitXLine, DoZLine, DoneXLine},
608
609                 {"badnick",
610                                 {"reason",      "nick",         NULL},
611                                 {DT_CHARPTR,    DT_CHARPTR},
612                                 InitXLine, DoQLine, DoneXLine},
613
614                 {"badhost",
615                                 {"reason",      "host",         NULL},
616                                 {DT_CHARPTR,    DT_CHARPTR},
617                                 InitXLine, DoKLine, DoneXLine},
618
619                 {"exception",
620                                 {"reason",      "host",         NULL},
621                                 {DT_CHARPTR,    DT_CHARPTR},
622                                 InitXLine, DoELine, DoneXLine},
623
624                 {"type",
625                                 {"name",        "classes",      NULL},
626                                 {DT_CHARPTR,    DT_CHARPTR},
627                                 InitTypes, DoType, DoneClassesAndTypes},
628
629                 {"class",
630                                 {"name",        "commands",     NULL},
631                                 {DT_CHARPTR,    DT_CHARPTR},
632                                 InitClasses, DoClass, DoneClassesAndTypes},
633
634                 {NULL}
635         };
636
637         include_stack.clear();
638
639         /* Load and parse the config file, if there are any errors then explode */
640         
641         /* Make a copy here so if it fails then we can carry on running with an unaffected config */
642         ConfigDataHash newconfig;
643         
644         if (this->LoadConf(newconfig, CONFIG_FILE, errstr))
645         {
646                 /* If we succeeded, set the ircd config to the new one */
647                 Config->config_data = newconfig;
648                 
649                 int c = 1;
650                 std::string last;
651                 
652                 for(ConfigDataHash::const_iterator i = this->config_data.begin(); i != this->config_data.end(); i++)
653                 {
654                         if(i->first != last)
655                                 c = 1;
656                         else
657                                 c++;
658                         
659                         std::cout << "[" << i->first << " " << c << "/" << this->config_data.count(i->first) << "]" << std::endl;
660                         
661                         for(KeyValList::const_iterator j = i->second.begin(); j != i->second.end(); j++)
662                         {
663                                 std::cout << "\t" << j->first << " = " << j->second << std::endl;
664                         }
665                         
666                         std::cout << "[/" << i->first << " " << c << "/" << this->config_data.count(i->first) << "]" << std::endl;
667                         
668                         last = i->first;
669                 }
670                 
671                 for(ConfigDataHash::const_iterator i = this->config_data.begin(); i != this->config_data.end(); i++)
672                 {
673                         std::cout << "There are " << ConfValueEnum(this->config_data, i->first) << " <" << i->first << "> tags" << std::endl;
674                         
675                         for(int j = 0; j < ConfValueEnum(this->config_data, i->first); j++)
676                         {
677                                 std::string foo;
678                                 if(ConfValue(this->config_data, i->first, "name", j, foo))
679                                 {
680                                         std::cout << "<" << i->first << ":name> " << foo << std::endl;
681                                 }
682                                 else
683                                 {
684                                         std::cout << "<" << i->first << ":name> undef" << std::endl;
685                                 }
686                         }
687                 }
688         }
689         else
690         {
691                 log(DEFAULT, "There were errors in your configuration:\n%s", errstr.str().c_str());
692
693                 if (bail)
694                 {
695                         printf("There were errors in your configuration:\n%s",errstr.str().c_str());
696                         Exit(0);
697                 }
698                 else
699                 {
700                         std::string errors = errstr.str();
701                         std::string::size_type start;
702                         unsigned int prefixlen;
703                         
704                         start = 0;
705                         /* ":Config->ServerName NOTICE user->nick :" */
706                         prefixlen = strlen(Config->ServerName) + strlen(user->nick) + 11;
707         
708                         if (user)
709                         {
710                                 WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick);
711                                 
712                                 while(start < errors.length())
713                                 {
714                                         WriteServ(user->fd, "NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str());
715                                         start += 510 - prefixlen;
716                                 }
717                         }
718                         else
719                         {
720                                 WriteOpers("There were errors in the configuration file:");
721                                 
722                                 while(start < errors.length())
723                                 {
724                                         WriteOpers(errors.substr(start, 360).c_str());
725                                         start += 360;
726                                 }
727                         }
728
729                         return;
730                 }
731         }
732
733         /* Check we dont have more than one of singular tags, or any of them missing
734          */
735         for (int Index = 0; Once[Index]; Index++)
736                 if (!CheckOnce(Once[Index],bail,user))
737                         return;
738
739         /* Read the values of all the tags which occur once or not at all, and call their callbacks.
740          */
741         for (int Index = 0; Values[Index].tag; Index++)
742         {
743                 int* val_i = (int*) Values[Index].val;
744                 char* val_c = (char*) Values[Index].val;
745
746                 switch (Values[Index].datatype)
747                 {
748                         case DT_CHARPTR:
749                                 /* Assuming MAXBUF here, potentially unsafe */
750                                 ConfValue(this->config_data, Values[Index].tag, Values[Index].value, 0, val_c, MAXBUF);
751                         break;
752
753                         case DT_INTEGER:
754                                 ConfValueInteger(this->config_data, Values[Index].tag, Values[Index].value, 0, *val_i);
755                         break;
756
757                         case DT_BOOLEAN:
758                                 *val_i = ConfValueBool(this->config_data, Values[Index].tag, Values[Index].value, 0);
759                         break;
760
761                         case DT_NOTHING:
762                         break;
763                 }
764
765                 Values[Index].validation_function(Values[Index].tag, Values[Index].value, Values[Index].val);
766         }
767
768         /* Claim memory for use when reading multiple tags
769          */
770         for (int n = 0; n < 12; n++)
771                 data[n] = new char[MAXBUF];
772
773         /* Read the multiple-tag items (class tags, connect tags, etc)
774          * and call the callbacks associated with them. We have three
775          * callbacks for these, a 'start', 'item' and 'end' callback.
776          */
777         
778         /* XXX - Make this use ConfValueInteger and so on */
779         for (int Index = 0; MultiValues[Index].tag; Index++)
780         {
781                 MultiValues[Index].init_function(MultiValues[Index].tag);
782
783                 int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag);
784
785                 for (int tagnum = 0; tagnum < number_of_tags; tagnum++)
786                 {
787                         for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)
788                         {
789                                 ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum, data[valuenum], MAXBUF);
790
791                                 switch (MultiValues[Index].datatype[valuenum])
792                                 {
793                                         case DT_CHARPTR:
794                                                 ptr[valuenum] = data[valuenum];
795                                         break;
796                                         case DT_INTEGER:
797                                                 r_i[valuenum] = atoi(data[valuenum]);
798                                                 ptr[valuenum] = &r_i[valuenum];
799                                         break;
800                                         case DT_BOOLEAN:
801                                                 r_i[valuenum] = ((*data[valuenum] == tolower('y')) || (*data[valuenum] == tolower('t')) || (*data[valuenum] == '1'));
802                                                 ptr[valuenum] = &r_i[valuenum];
803                                         break;
804                                         default:
805                                         break;
806                                 }
807                         }
808                         MultiValues[Index].validation_function(MultiValues[Index].tag, (char**)MultiValues[Index].items, ptr, MultiValues[Index].datatype);
809                 }
810
811                 MultiValues[Index].finish_function(MultiValues[Index].tag);
812         }
813
814         /* Free any memory we claimed
815          */
816         for (int n = 0; n < 12; n++)
817                 delete[] data[n];
818
819         // write once here, to try it out and make sure its ok
820         WritePID(Config->PID);
821
822         log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
823
824         /* If we're rehashing, let's load any new modules, and unload old ones
825          */
826         if (!bail)
827         {
828                 ServerInstance->stats->BoundPortCount = BindPorts(false);
829
830                 if (!removed_modules.empty())
831                         for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
832                         {
833                                 if (ServerInstance->UnloadModule(removing->c_str()))
834                                 {
835                                         WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
836
837                                         if (user)
838                                                 WriteServ(user->fd,"973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
839
840                                         rem++;
841                                 }
842                                 else
843                                 {
844                                         if (user)
845                                                 WriteServ(user->fd,"972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->ModuleError());
846                                 }
847                         }
848
849                 if (!added_modules.empty())
850                 for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
851                 {
852                         if (ServerInstance->LoadModule(adding->c_str()))
853                         {
854                                 WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
855
856                                 if (user)
857                                         WriteServ(user->fd,"975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
858
859                                 add++;
860                         }
861                         else
862                         {
863                                 if (user)
864                                         WriteServ(user->fd,"974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->ModuleError());
865                         }
866                 }
867
868                 log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
869         }
870 }
871
872 void Exit(int status)
873 {
874         if (Config->log_file)
875                 fclose(Config->log_file);
876         send_error("Server shutdown.");
877         exit (status);
878 }
879
880 void Killed(int status)
881 {
882         if (Config->log_file)
883                 fclose(Config->log_file);
884         send_error("Server terminated.");
885         exit(status);
886 }
887
888 char* CleanFilename(char* name)
889 {
890         char* p = name + strlen(name);
891         while ((p != name) && (*p != '/')) p--;
892         return (p != name ? ++p : p);
893 }
894
895
896 void Rehash(int status)
897 {
898         WriteOpers("Rehashing config file %s due to SIGHUP",CleanFilename(CONFIG_FILE));
899         fclose(Config->log_file);
900         OpenLog(NULL,0);
901         Config->Read(false,NULL);
902         FOREACH_MOD(I_OnRehash,OnRehash(""));
903 }
904
905
906
907 void Start()
908 {
909         printf("\033[1;32mInspire Internet Relay Chat Server, compiled %s at %s\n",__DATE__,__TIME__);
910         printf("(C) ChatSpike Development team.\033[0m\n\n");
911         printf("Developers:\t\t\033[1;32mBrain, FrostyCoolSlug, w00t, Om\033[0m\n");
912         printf("Others:\t\t\t\033[1;32mSee /INFO Output\033[0m\n");
913         printf("Name concept:\t\t\033[1;32mLord_Zathras\033[0m\n\n");
914 }
915
916 void WritePID(const std::string &filename)
917 {
918         ofstream outfile(filename.c_str());
919         if (outfile.is_open())
920         {
921                 outfile << getpid();
922                 outfile.close();
923         }
924         else
925         {
926                 printf("Failed to write PID-file '%s', exiting.\n",filename.c_str());
927                 log(DEFAULT,"Failed to write PID-file '%s', exiting.",filename.c_str());
928                 Exit(0);
929         }
930 }
931
932 void SetSignals()
933 {
934         signal (SIGALRM, SIG_IGN);
935         signal (SIGHUP, Rehash);
936         signal (SIGPIPE, SIG_IGN);
937         signal (SIGTERM, Exit);
938         signal (SIGSEGV, Error);
939 }
940
941
942 bool DaemonSeed()
943 {
944         int childpid;
945         if ((childpid = fork ()) < 0)
946                 return (ERROR);
947         else if (childpid > 0)
948         {
949                 /* We wait a few seconds here, so that the shell prompt doesnt come back over the output */
950                 sleep(6);
951                 exit (0);
952         }
953         setsid ();
954         umask (007);
955         printf("InspIRCd Process ID: \033[1;32m%lu\033[0m\n",(unsigned long)getpid());
956
957         rlimit rl;
958         if (getrlimit(RLIMIT_CORE, &rl) == -1)
959         {
960                 log(DEFAULT,"Failed to getrlimit()!");
961                 return false;
962         }
963         else
964         {
965                 rl.rlim_cur = rl.rlim_max;
966                 if (setrlimit(RLIMIT_CORE, &rl) == -1)
967                         log(DEFAULT,"setrlimit() failed, cannot increase coredump size.");
968         }
969   
970         return true;
971 }
972
973
974 /* Make Sure Modules Are Avaliable!
975  * (BugFix By Craig.. See? I do work! :p)
976  * Modified by brain, requires const char*
977  * to work with other API functions
978  */
979
980 /* XXX - Needed? */
981 bool FileExists (const char* file)
982 {
983         FILE *input;
984         if ((input = fopen (file, "r")) == NULL)
985         {
986                 return(false);
987         }
988         else
989         {
990                 fclose (input);
991                 return(true);
992         }
993 }
994
995 bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream)
996 {
997         std::ifstream conf(filename);
998         std::string line;
999         char ch;
1000         long linenumber;
1001         bool in_tag;
1002         bool in_quote;
1003         bool in_comment;
1004         
1005         linenumber = 1;
1006         in_tag = false;
1007         in_quote = false;
1008         in_comment = false;
1009         
1010         /* Check if the file open failed first */
1011         if (!conf)
1012         {
1013                 errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl;
1014                 return false;
1015         }
1016         
1017         /* Fix the chmod of the file to restrict it to the current user and group */
1018         chmod(filename,0600);
1019         
1020         for (unsigned int t = 0; t < include_stack.size(); t++)
1021         {
1022                 if (std::string(filename) == include_stack[t])
1023                 {
1024                         errorstream << "File " << filename << " is included recursively (looped inclusion)." << std::endl;
1025                         return false;
1026                 }
1027         }
1028         
1029         /* It's not already included, add it to the list of files we've loaded */
1030         include_stack.push_back(filename);
1031         
1032         /* Start reading characters... */       
1033         while(conf.get(ch))
1034         {
1035                 /*
1036                  * Here we try and get individual tags on separate lines,
1037                  * this would be so easy if we just made people format
1038                  * their config files like that, but they don't so...
1039                  * We check for a '<' and then know the line is over when
1040                  * we get a '>' not inside quotes. If we find two '<' and
1041                  * no '>' then die with an error.
1042                  */
1043                 
1044                 if((ch == '#') && !in_quote)
1045                 {
1046                         in_comment = true;
1047                         continue;
1048                 }
1049                 
1050                 switch(ch)
1051                 {
1052                         case '\n':
1053                                 linenumber++;
1054                         case '\r':
1055                                 in_comment = false;
1056                         case '\0':
1057                                 continue;
1058                         case '\t':
1059                                 ch = ' ';
1060                 }
1061                 
1062                 line += ch;
1063                 
1064                 if(ch == '<')
1065                 {
1066                         if(in_tag)
1067                         {
1068                                 if(!in_quote)
1069                                 {
1070                                         errorstream << "Got another opening < when the first one wasn't closed on line " << linenumber << std::endl;
1071                                         return false;
1072                                 }
1073                         }
1074                         else
1075                         {
1076                                 if(in_quote)
1077                                 {
1078                                         errorstream << "We're in a quote but outside a tag, interesting. Line: " << linenumber << std::endl;
1079                                         return false;
1080                                 }
1081                                 else
1082                                 {
1083                                         // errorstream << "Opening new config tag on line " << linenumber << std::endl;
1084                                         in_tag = true;
1085                                 }
1086                         }
1087                 }
1088                 else if(ch == '"')
1089                 {
1090                         if(in_tag)
1091                         {
1092                                 if(in_quote)
1093                                 {
1094                                         // errorstream << "Closing quote in config tag on line " << linenumber << std::endl;
1095                                         in_quote = false;
1096                                 }
1097                                 else
1098                                 {
1099                                         // errorstream << "Opening quote in config tag on line " << linenumber << std::endl;
1100                                         in_quote = true;
1101                                 }
1102                         }
1103                         else
1104                         {
1105                                 if(in_quote)
1106                                 {
1107                                         errorstream << "Found a (closing) \" outside a tag on line " << linenumber << std::endl;
1108                                 }
1109                                 else
1110                                 {
1111                                         errorstream << "Found a (opening) \" outside a tag on line " << linenumber << std::endl;
1112                                 }
1113                         }
1114                 }
1115                 else if(ch == '>')
1116                 {
1117                         if(!in_quote)
1118                         {
1119                                 if(in_tag)
1120                                 {
1121                                         // errorstream << "Closing config tag on line " << linenumber << std::endl;
1122                                         in_tag = false;
1123
1124                                         /*
1125                                          * If this finds an <include> then ParseLine can simply call
1126                                          * LoadConf() and load the included config into the same ConfigDataHash
1127                                          */
1128                                         
1129                                         if(!this->ParseLine(target, line, linenumber, errorstream))
1130                                                 return false;
1131                                         
1132                                         line.clear();
1133                                 }
1134                                 else
1135                                 {
1136                                         errorstream << "Got a closing > when we weren't inside a tag on line " << linenumber << std::endl;
1137                                         return false;
1138                                 }
1139                         }
1140                 }
1141         }
1142         
1143         return true;
1144 }
1145
1146 bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream)
1147 {
1148         return this->LoadConf(target, filename.c_str(), errorstream);
1149 }
1150
1151 bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream)
1152 {
1153         std::string tagname;
1154         std::string current_key;
1155         std::string current_value;
1156         KeyValList results;
1157         bool got_name;
1158         bool got_key;
1159         bool in_quote;
1160         
1161         got_name = got_key = in_quote = false;
1162         
1163         std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl;
1164         
1165         for(std::string::iterator c = line.begin(); c != line.end(); c++)
1166         {
1167                 if(!got_name)
1168                 {
1169                         /* We don't know the tag name yet. */
1170                         
1171                         if(*c != ' ')
1172                         {
1173                                 if(*c != '<')
1174                                 {
1175                                         tagname += *c;
1176                                 }
1177                         }
1178                         else
1179                         {
1180                                 /* We got to a space, we should have the tagname now. */
1181                                 if(tagname.length())
1182                                 {
1183                                         got_name = true;
1184                                 }
1185                         }
1186                 }
1187                 else
1188                 {
1189                         /* We have the tag name */
1190                         if(!got_key)
1191                         {
1192                                 /* We're still reading the key name */
1193                                 if(*c != '=')
1194                                 {
1195                                         if(*c != ' ')
1196                                         {
1197                                                 current_key += *c;
1198                                         }
1199                                 }
1200                                 else
1201                                 {
1202                                         /* We got an '=', end of the key name. */
1203                                         got_key = true;
1204                                 }
1205                         }
1206                         else
1207                         {
1208                                 /* We have the key name, now we're looking for quotes and the value */
1209                                 if(*c == '"')
1210                                 {
1211                                         if(!in_quote)
1212                                         {
1213                                                 /* We're not already in a quote. */
1214                                                 in_quote = true;
1215                                         }
1216                                         else
1217                                         {
1218                                                 /* Leaving quotes, we have the value */
1219                                                 results.push_back(KeyVal(current_key, current_value));
1220                                                 std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl;
1221                                                 in_quote = false;
1222                                                 got_key = false;
1223                                                 
1224                                                 if((tagname == "include") && (current_key == "file"))
1225                                                 {
1226                                                         this->DoInclude(target, current_value, errorstream);
1227                                                 }
1228                                                 
1229                                                 current_key.clear();
1230                                                 current_value.clear();
1231                                         }
1232                                 }
1233                                 else
1234                                 {
1235                                         if(in_quote)
1236                                         {
1237                                                 current_value += *c;
1238                                         }
1239                                 }
1240                         }
1241                 }
1242         }
1243         
1244         /* Finished parsing the tag, add it to the config hash */
1245         target.insert(std::pair<std::string, KeyValList > (tagname, results));
1246         std::cout << "Finished parsing " << tagname << std::endl;
1247         std::cout << "Count of <server> tag: " << target.count("server") << std::endl;
1248         
1249         return true;
1250 }
1251
1252 bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
1253 {
1254         std::string confpath;
1255         std::string newfile;
1256         std::string::size_type pos;
1257         
1258         confpath = CONFIG_FILE;
1259         newfile = file;
1260         
1261         for (std::string::iterator c = newfile.begin(); c != newfile.end(); c++)
1262         {
1263                 if (*c == '\\')
1264                 {
1265                         *c = '/';
1266                 }
1267         }
1268
1269         if (file[0] != '/')
1270         {
1271                 if((pos = confpath.find("/inspircd.conf")) != std::string::npos)
1272                 {
1273                         /* Leaves us with just the path */
1274                         newfile = confpath.substr(0, pos) + std::string("/") + newfile;
1275                 }
1276                 else
1277                 {
1278                         errorstream << "Couldn't get config path from: " << confpath << std::endl;
1279                         return false;
1280                 }
1281         }
1282         
1283         return LoadConf(target, newfile, errorstream);
1284 }
1285
1286 bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length)
1287 {
1288         std::string value;
1289         bool r = ConfValue(target, std::string(tag), std::string(var), index, value);
1290         strlcpy(result, value.c_str(), length);
1291         return r;
1292 }
1293
1294 bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result)
1295 {
1296         ConfigDataHash::size_type pos = index;
1297         if((pos >= 0) && (pos < target.count(tag)))
1298         {
1299                 ConfigDataHash::const_iterator iter = target.find(tag);
1300                 
1301                 for(int i = 0; i < index; i++)
1302                         iter++;
1303                 
1304                 for(KeyValList::const_iterator j = iter->second.begin(); j != iter->second.end(); j++)
1305                 {
1306                         if(j->first == var)
1307                         {
1308                                 result = j->second;
1309                                 return true;
1310                         }
1311                 }
1312         }
1313         else
1314         {
1315                 log(DEBUG, "ConfValue got an out-of-range index %d", index);
1316         }
1317         
1318         return false;
1319 }
1320         
1321 bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result)
1322 {
1323         return ConfValueInteger(target, std::string(tag), std::string(var), index, result);
1324 }
1325
1326 bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result)
1327 {
1328         std::string value;
1329         std::istringstream stream;
1330         bool r = ConfValue(target, tag, var, index, value);
1331         stream.str(value);
1332         if(!(stream >> result))
1333                 return false;
1334         return r;
1335 }
1336         
1337 bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index)
1338 {
1339         return ConfValueBool(target, std::string(tag), std::string(var), index);
1340 }
1341
1342 bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index)
1343 {
1344         std::string result;
1345         if(!ConfValue(target, tag, var, index, result))
1346                 return false;
1347         
1348         return ((result == "yes") || (result == "true") || (result == "1"));
1349 }
1350         
1351 int ServerConfig::ConfValueEnum(ConfigDataHash &target, const char* tag)
1352 {
1353         return ConfValueEnum(target, std::string(tag));
1354 }
1355
1356 int ServerConfig::ConfValueEnum(ConfigDataHash &target, const std::string &tag)
1357 {
1358         return target.count(tag);
1359 }
1360         
1361 int ServerConfig::ConfVarEnum(ConfigDataHash &target, const char* tag, int index)
1362 {
1363         return 1;
1364 }
1365
1366 int ServerConfig::ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index)
1367 {
1368         ConfigDataHash::size_type pos = index;
1369         
1370         if((pos >= 0) && (pos < target.count(tag)))
1371         {
1372                 ConfigDataHash::const_iterator iter = target.find(tag);
1373                 
1374                 for(int i = 0; i < index; i++)
1375                         iter++;
1376                 
1377                 return iter->second.size();
1378         }
1379         else
1380         {
1381                 log(DEBUG, "ConfVarEnum got an out-of-range index %d", index);
1382         }
1383         
1384         return 0;
1385 }
1386
1387 /** This will bind a socket to a port. It works for UDP/TCP.
1388  * If a hostname is given to bind to, the function will first
1389  * attempt to resolve the hostname, then bind to the IP the 
1390  * hostname resolves to. This is a blocking lookup blocking for
1391  * a maximum of one second before it times out, using the DNS
1392  * server specified in the configuration file.
1393  */ 
1394 bool BindSocket(int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr)
1395 {
1396         memset(&server,0,sizeof(server));
1397         struct in_addr addy;
1398         bool resolved = false;
1399         char resolved_addr[128];
1400
1401         if (*addr == '*')
1402                 *addr = 0;
1403
1404         if (*addr && !inet_aton(addr,&addy))
1405         {
1406                 /* If they gave a hostname, bind to the IP it resolves to */
1407                 if (CleanAndResolve(resolved_addr, addr, true))
1408                 {
1409                         inet_aton(resolved_addr,&addy);
1410                         log(DEFAULT,"Resolved binding '%s' -> '%s'",addr,resolved_addr);
1411                         server.sin_addr = addy;
1412                         resolved = true;
1413                 }
1414                 else
1415                 {
1416                         log(DEFAULT,"WARNING: Could not resolve '%s' to an IP for binding to on port %d",addr,port);
1417                         return false;
1418                 }
1419         }
1420         server.sin_family = AF_INET;
1421         if (!resolved)
1422         {
1423                 if (!*addr)
1424                 {
1425                         server.sin_addr.s_addr = htonl(INADDR_ANY);
1426                 }
1427                 else
1428                 {
1429                         server.sin_addr = addy;
1430                 }
1431         }
1432         server.sin_port = htons(port);
1433         if (bind(sockfd,(struct sockaddr*)&server,sizeof(server)) < 0)
1434         {
1435                 return false;
1436         }
1437         else
1438         {
1439                 log(DEBUG,"Bound port %s:%d",*addr ? addr : "*",port);
1440                 if (listen(sockfd, Config->MaxConn) == -1)
1441                 {
1442                         log(DEFAULT,"ERROR in listen(): %s",strerror(errno));
1443                         return false;
1444                 }
1445                 else
1446                 {
1447                         NonBlocking(sockfd);
1448                         return true;
1449                 }
1450         }
1451 }
1452
1453
1454 // Open a TCP Socket
1455 int OpenTCPSocket()
1456 {
1457         int sockfd;
1458         int on = 1;
1459         struct linger linger = { 0 };
1460   
1461         if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1462         {
1463                 log(DEFAULT,"Error creating TCP socket: %s",strerror(errno));
1464                 return (ERROR);
1465         }
1466         else
1467         {
1468                 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1469                 /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
1470                 linger.l_onoff = 1;
1471                 linger.l_linger = 1;
1472                 setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &linger,sizeof(linger));
1473                 return (sockfd);
1474         }
1475 }
1476
1477 bool HasPort(int port, char* addr)
1478 {
1479         for (int count = 0; count < ServerInstance->stats->BoundPortCount; count++)
1480         {
1481                 if ((port == Config->ports[count]) && (!strcasecmp(Config->addrs[count],addr)))
1482                 {
1483                         return true;
1484                 }
1485         }
1486         return false;
1487 }
1488
1489 int BindPorts(bool bail)
1490 {
1491         char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
1492         sockaddr_in client,server;
1493         int clientportcount = 0;
1494         int BoundPortCount = 0;
1495
1496         if (!bail)
1497         {
1498                 int InitialPortCount = ServerInstance->stats->BoundPortCount;
1499                 log(DEBUG,"Initial port count: %d",InitialPortCount);
1500
1501                 for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++)
1502                 {
1503                         Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF);
1504                         Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF);
1505                         Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF);
1506
1507                         if (((!*Type) || (!strcmp(Type,"clients"))) && (!HasPort(atoi(configToken),Addr)))
1508                         {
1509                                 // modules handle server bind types now
1510                                 Config->ports[clientportcount+InitialPortCount] = atoi(configToken);
1511                                 if (*Addr == '*')
1512                                         *Addr = 0;
1513
1514                                 strlcpy(Config->addrs[clientportcount+InitialPortCount],Addr,256);
1515                                 clientportcount++;
1516                                 log(DEBUG,"NEW binding %s:%s [%s] from config",Addr,configToken, Type);
1517                         }
1518                 }
1519                 int PortCount = clientportcount;
1520                 if (PortCount)
1521                 {
1522                         for (int count = InitialPortCount; count < InitialPortCount + PortCount; count++)
1523                         {
1524                                 if ((openSockfd[count] = OpenTCPSocket()) == ERROR)
1525                                 {
1526                                         log(DEBUG,"Bad fd %d binding port [%s:%d]",openSockfd[count],Config->addrs[count],Config->ports[count]);
1527                                         return ERROR;
1528                                 }
1529                                 if (!BindSocket(openSockfd[count],client,server,Config->ports[count],Config->addrs[count]))
1530                                 {
1531                                         log(DEFAULT,"Failed to bind port [%s:%d]: %s",Config->addrs[count],Config->ports[count],strerror(errno));
1532                                 }
1533                                 else
1534                                 {
1535                                         /* Associate the new open port with a slot in the socket engine */
1536                                         ServerInstance->SE->AddFd(openSockfd[count],true,X_LISTEN);
1537                                         BoundPortCount++;
1538                                 }
1539                         }
1540                         return InitialPortCount + BoundPortCount;
1541                 }
1542                 else
1543                 {
1544                         log(DEBUG,"There is nothing new to bind!");
1545                 }
1546                 return InitialPortCount;
1547         }
1548
1549         for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++)
1550         {
1551                 Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF);
1552                 Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF);
1553                 Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF);
1554
1555                 if ((!*Type) || (!strcmp(Type,"clients")))
1556                 {
1557                         // modules handle server bind types now
1558                         Config->ports[clientportcount] = atoi(configToken);
1559
1560                         // If the client put bind "*", this is an unrealism.
1561                         // We don't actually support this as documented, but
1562                         // i got fed up of people trying it, so now it converts
1563                         // it to an empty string meaning the same 'bind to all'.
1564                         if (*Addr == '*')
1565                                 *Addr = 0;
1566
1567                         strlcpy(Config->addrs[clientportcount],Addr,256);
1568                         clientportcount++;
1569                         log(DEBUG,"Binding %s:%s [%s] from config",Addr,configToken, Type);
1570                 }
1571         }
1572
1573         int PortCount = clientportcount;
1574
1575         for (int count = 0; count < PortCount; count++)
1576         {
1577                 if ((openSockfd[BoundPortCount] = OpenTCPSocket()) == ERROR)
1578                 {
1579                         log(DEBUG,"Bad fd %d binding port [%s:%d]",openSockfd[BoundPortCount],Config->addrs[count],Config->ports[count]);
1580                         return ERROR;
1581                 }
1582
1583                 if (!BindSocket(openSockfd[BoundPortCount],client,server,Config->ports[count],Config->addrs[count]))
1584                 {
1585                         log(DEFAULT,"Failed to bind port [%s:%d]: %s",Config->addrs[count],Config->ports[count],strerror(errno));
1586                 }
1587                 else
1588                 {
1589                         /* well we at least bound to one socket so we'll continue */
1590                         BoundPortCount++;
1591                 }
1592         }
1593
1594         /* if we didn't bind to anything then abort */
1595         if (!BoundPortCount)
1596         {
1597                 log(DEFAULT,"No ports bound, bailing!");
1598                 printf("\nERROR: Could not bind any of %d ports! Please check your configuration.\n\n", PortCount);
1599                 return ERROR;
1600         }
1601
1602         return BoundPortCount;
1603 }