servers.c

Go to the documentation of this file.
00001 /* Routines to maintain a list of connected servers
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  *
00012  */
00013 
00014 #include "services.h"
00015 
00016 Server *servlist = NULL;
00017 Server *me_server = NULL;       /* This are we        */
00018 Server *serv_uplink = NULL;     /* This is our uplink */
00019 uint32 uplink_capab;
00020 char *uplink;
00021 char *TS6UPLINK;
00022 char *TS6SID;
00023 
00024 /* For first_server / next_server */
00025 static Server *server_cur;
00026 
00027 CapabInfo capab_info[] = {
00028     {"NOQUIT", CAPAB_NOQUIT},
00029     {"TSMODE", CAPAB_TSMODE},
00030     {"UNCONNECT", CAPAB_UNCONNECT},
00031     {"NICKIP", CAPAB_NICKIP},
00032     {"SSJOIN", CAPAB_NSJOIN},
00033     {"ZIP", CAPAB_ZIP},
00034     {"BURST", CAPAB_BURST},
00035     {"TS5", CAPAB_TS5},
00036     {"TS3", CAPAB_TS3},
00037     {"DKEY", CAPAB_DKEY},
00038     {"PT4", CAPAB_PT4},
00039     {"SCS", CAPAB_SCS},
00040     {"QS", CAPAB_QS},
00041     {"UID", CAPAB_UID},
00042     {"KNOCK", CAPAB_KNOCK},
00043     {"CLIENT", CAPAB_CLIENT},
00044     {"IPV6", CAPAB_IPV6},
00045     {"SSJ5", CAPAB_SSJ5},
00046     {"SN2", CAPAB_SN2},
00047     {"TOK1", CAPAB_TOKEN},
00048     {"TOKEN", CAPAB_TOKEN},
00049     {"VHOST", CAPAB_VHOST},
00050     {"SSJ3", CAPAB_SSJ3},
00051     {"SJB64", CAPAB_SJB64},
00052     {"CHANMODES", CAPAB_CHANMODE},
00053     {"NICKCHARS", CAPAB_NICKCHARS},
00054     {NULL, 0}
00055 };
00056 
00057 /*************************************************************************/
00058 
00064 Server *first_server(int flags)
00065 {
00066     server_cur = servlist;
00067     if (flags > -1) {
00068         while (server_cur && (server_cur->flags != flags))
00069             server_cur = next_server(flags);
00070     }
00071     return server_cur;
00072 }
00073 
00074 /*************************************************************************/
00075 
00081 Server *next_server(int flags)
00082 {
00083     if (!server_cur)
00084         return NULL;
00085 
00086     do {
00087         if (server_cur->links) {
00088             server_cur = server_cur->links;
00089         } else if (server_cur->next) {
00090             server_cur = server_cur->next;
00091         } else {
00092             do {
00093                 server_cur = server_cur->uplink;
00094                 if (server_cur && server_cur->next) {
00095                     server_cur = server_cur->next;
00096                     break;
00097                 }
00098             } while (server_cur);
00099         }
00100     } while (server_cur && ((flags > -1) && (server_cur->flags != flags)));
00101 
00102     return server_cur;
00103 }
00104 
00105 /*************************************************************************/
00106 
00119 Server *new_server(Server * uplink, const char *name, const char *desc,
00120                    uint16 flags, char *suid)
00121 {
00122     Server *serv;
00123 
00124     if (debug) 
00125         alog("debug: Creating %s(%s) uplinked to %s", name, suid ? suid : "", 
00126                 uplink ? uplink->name : "No uplink");
00127 
00128     serv = scalloc(sizeof(Server), 1);
00129     if (!name)
00130         name = "";
00131     serv->name = sstrdup(name);
00132     serv->desc = sstrdup(desc);
00133     serv->flags = flags;
00134     serv->uplink = uplink;
00135     if (suid) {
00136         serv->suid = sstrdup(suid);
00137     } else {
00138         serv->suid = NULL;
00139     }
00140     if (ircd->sync)
00141         serv->sync = SSYNC_IN_PROGRESS;
00142     else
00143         serv->sync = SSYNC_UNKNOWN;
00144     serv->links = NULL;
00145     serv->prev = NULL;
00146 
00147     if (!uplink) {
00148         serv->hops = 0;
00149         serv->next = servlist;
00150         if (servlist)
00151             servlist->prev = serv;
00152         servlist = serv;
00153     } else {
00154         serv->hops = uplink->hops + 1;
00155         serv->next = uplink->links;
00156         if (uplink->links)
00157             uplink->links->prev = serv;
00158         uplink->links = serv;
00159     }
00160     /* Check if this is our uplink server */
00161     if ((uplink == me_server) && !(flags & SERVER_JUPED)) {
00162         serv_uplink = serv;
00163         serv->flags |= SERVER_ISUPLINK;
00164     }
00165 
00166     /* Write the StartGlobal (to non-juped servers) */
00167     if (GlobalOnCycle && GlobalOnCycleUP && !(flags & SERVER_JUPED))
00168         notice_server(s_GlobalNoticer, serv, "%s", GlobalOnCycleUP);
00169 
00170     return serv;
00171 }
00172 
00173 /*************************************************************************/
00174 
00185 static void delete_server(Server * serv, const char *quitreason)
00186 {
00187     Server *s, *snext;
00188     User *u, *unext;
00189     NickAlias *na;
00190 
00191     if (!serv) {
00192         if (debug)
00193             alog("debug: delete_server() called with NULL arg!");
00194         return;
00195     }
00196 
00197     if (debug)
00198         alog("debug: Deleting %s(%s) uplinked to %s(%s)", serv->name, 
00199                 serv->suid ? serv->suid : "", serv->uplink ? serv->uplink->name : "???",
00200                 serv->uplink ? serv->uplink->suid : "");
00201 
00202     if (ircdcap->noquit || ircdcap->qs) {
00203         if ((uplink_capab & ircdcap->noquit)
00204             || (uplink_capab & ircdcap->qs)) {
00205             u = firstuser();
00206             while (u) {
00207                 unext = nextuser();
00208                 if (u->server == serv) {
00209                     if ((na = u->na) && !(na->status & NS_VERBOTEN)
00210                         && (!(na->nc->flags & NI_SUSPENDED))
00211                         && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
00212                         na->last_seen = time(NULL);
00213                         if (na->last_quit)
00214                             free(na->last_quit);
00215                         na->last_quit =
00216                             (quitreason ? sstrdup(quitreason) : NULL);
00217                     }
00218                     if (LimitSessions && !is_ulined(u->server->name)) {
00219                         del_session(u->host);
00220                     }
00221                     delete_user(u);
00222                 }
00223                 u = unext;
00224             }
00225             if (debug)
00226                 alog("debug: delete_server() cleared all users");
00227         }
00228     }
00229 
00230     s = serv->links;
00231     while (s) {
00232         snext = s->next;
00233         delete_server(s, quitreason);
00234         s = snext;
00235     }
00236 
00237     if (debug)
00238         alog("debug: delete_server() cleared all servers");
00239 
00240     free(serv->name);
00241     free(serv->desc);
00242     if (serv->prev)
00243         serv->prev->next = serv->next;
00244     if (serv->next)
00245         serv->next->prev = serv->prev;
00246     if (serv->uplink && serv->uplink->links == serv)
00247         serv->uplink->links = serv->next;
00248 
00249     if (debug)
00250         alog("debug: delete_server() completed");
00251 }
00252 
00253 /*************************************************************************/
00254 
00261 Server *findserver(Server * s, const char *name)
00262 {
00263     Server *sl;
00264 
00265     if (!name || !*name) {
00266         return NULL;
00267     }
00268 
00269     if (debug >= 3) {
00270         alog("debug: findserver(%p)", name);
00271     }
00272     while (s && (stricmp(s->name, name) != 0)) {
00273         if (s->links) {
00274             sl = findserver(s->links, name);
00275             if (sl) {
00276                 s = sl;
00277             } else {
00278                 s = s->next;
00279             }
00280         } else {
00281             s = s->next;
00282         }
00283     }
00284     if (debug >= 3) {
00285         alog("debug: findserver(%s) -> %p", name, (void *) s);
00286     }
00287     return s;
00288 }
00289 
00290 /*************************************************************************/
00291 
00298 Server *findserver_uid(Server * s, const char *name)
00299 {
00300     Server *sl;
00301 
00302     if (!name || !*name) {
00303         return NULL;
00304     }
00305 
00306     if (debug >= 3) {
00307         alog("debug: findserver_uid(%p)", name);
00308     }
00309     while (s && s->suid && (stricmp(s->suid, name) != 0)) {
00310         if (s->links) {
00311             sl = findserver_uid(s->links, name);
00312             if (sl) {
00313                 s = sl;
00314             } else {
00315                 s = s->next;
00316             }
00317         } else {
00318             s = s->next;
00319         }
00320     }
00321     if (debug >= 3) {
00322         alog("debug: findserver_uid(%s) -> %p", name, (void *) s);
00323     }
00324     return s;
00325 }
00326 
00327 /*************************************************************************/
00328 
00335 int anope_check_sync(const char *name)
00336 {
00337     Server *s;
00338     s = findserver(servlist, name);
00339 
00340     if (!s)
00341         return 0;
00342 
00343     if (is_sync(s))
00344         return 1;
00345     else
00346         return -1;
00347 }
00348 
00349 /*************************************************************************/
00350 
00360 void do_server(const char *source, char *servername, char *hops,
00361                char *descript, char *numeric)
00362 {
00363     Server *s;
00364 
00365     if (debug) {
00366         if (!*source) {
00367             alog("debug: Server introduced (%s)", servername);
00368         } else {
00369             alog("debug: Server introduced (%s) from %s", servername,
00370                  source);
00371         }
00372     }
00373     if (source[0] == '\0')
00374         s = me_server;
00375     else if (UseTS6 && ircd->ts6) {
00376         s = findserver_uid(servlist, source);
00377         if (!s)
00378             s = findserver(servlist, source);
00379     } else
00380         s = findserver(servlist, source);
00381 
00382     if (!s)
00383         fatal("FATAL ERROR: Received new server from nonexistant uplink.");
00384 
00385     new_server(s, servername, descript, 0, numeric);
00386     send_event(EVENT_SERVER_CONNECT, 1, servername);
00387 }
00388 
00389 /*************************************************************************/
00390 
00398 void do_squit(const char *source, int ac, char **av)
00399 {
00400     char buf[BUFSIZE];
00401     Server *s;
00402 
00403     if (UseTS6 && ircd->ts6) {
00404         s = findserver_uid(servlist, av[0]);
00405         if (!s) {
00406             s = findserver(servlist, av[0]);
00407         }
00408     } else {
00409         s = findserver(servlist, av[0]);
00410     }
00411     if (!s) {
00412         alog("SQUIT for nonexistent server (%s)!!", av[0]);
00413         return;
00414     }
00415     send_event(EVENT_SERVER_SQUIT, 1, s->name);
00416 
00417     /* If this is a juped server, send a nice global to inform the online
00418      * opers that we received it.
00419      */
00420     if (s->flags & SERVER_JUPED) {
00421         snprintf(buf, BUFSIZE, "Received SQUIT for juped server %s",
00422                  s->name);
00423         anope_cmd_global(s_OperServ, buf);
00424     }
00425 
00426     snprintf(buf, sizeof(buf), "%s %s", s->name,
00427              (s->uplink ? s->uplink->name : ""));
00428 
00429     if (ircdcap->unconnect) {
00430         if ((s->uplink == me_server)
00431             && (uplink_capab & ircdcap->unconnect)) {
00432             if (debug) {
00433                 alog("debug: Sending UNCONNECT SQUIT for %s", s->name);
00434             }
00435             /* need to fix */
00436             anope_cmd_squit(s->name, buf);
00437         }
00438     }
00439 
00440     delete_server(s, buf);
00441 }
00442 
00443 /*************************************************************************/
00444 
00451 void capab_parse(int ac, char **av)
00452 {
00453     int i;
00454     int j;
00455     char *s, *tmp;
00456 
00457     char *temp;
00458 
00459     for (i = 0; i < ac; i++) {
00460         temp = av[i];
00461 
00462         s = myStrGetToken(temp, '=', 0);
00463         tmp = myStrGetTokenRemainder(temp, '=', 1);
00464 
00465         if (!s)
00466             continue;
00467 
00468         for (j = 0; capab_info[j].token; j++) {
00469             if (stricmp(s, capab_info[j].token) == 0)
00470                 uplink_capab |= capab_info[j].flag;
00471             /* Special cases */
00472             if ((stricmp(s, "NICKIP") == 0) && !ircd->nickip)
00473                 ircd->nickip = 1;
00474             if ((stricmp(s, "CHANMODES") == 0) && tmp)
00475                 ircd->chanmodes = sstrdup(tmp);
00476             if ((stricmp(s, "NICKCHARS") == 0) && tmp)
00477                 ircd->nickchars = sstrdup(tmp);
00478         }
00479 
00480         if (s)
00481             free(s);
00482         if (tmp)
00483             free(tmp);
00484     }
00485 }
00486 
00487 /*************************************************************************/
00488 
00495 int is_ulined(char *server)
00496 {
00497     int j;
00498 
00499     for (j = 0; j < NumUlines; j++) {
00500         if (stricmp(Ulines[j], server) == 0) {
00501             return 1;
00502         }
00503     }
00504 
00505     return 0;
00506 }
00507 
00508 /*************************************************************************/
00509 
00516 int is_sync(Server * server)
00517 {
00518     if ((server->sync == SSYNC_DONE) || (server->sync == SSYNC_UNKNOWN))
00519         return 1;
00520     return 0;
00521 }
00522 
00523 /*************************************************************************/
00524 
00525 /* Finish the syncing process for this server and (optionally) for all
00526  * it's leaves as well
00527  * @param serv Server to finish syncing
00528  * @param sync_links Should all leaves be synced as well? (1: yes, 0: no)
00529  * @return void
00530  */
00531 void finish_sync(Server * serv, int sync_links)
00532 {
00533     Server *s;
00534 
00535     if (!serv || is_sync(serv))
00536         return;
00537 
00538     /* Mark each server as in sync */
00539     s = serv;
00540     do {
00541         if (!is_sync(s)) {
00542             if (debug)
00543                 alog("debug: Finishing sync for server %s", s->name);
00544 
00545             s->sync = SSYNC_DONE;
00546         }
00547 
00548         if (!sync_links)
00549             break;
00550 
00551         if (s->links) {
00552             s = s->links;
00553         } else if (s->next) {
00554             s = s->next;
00555         } else {
00556             do {
00557                 s = s->uplink;
00558                 if (s == serv)
00559                     s = NULL;
00560                 if (s == me_server)
00561                     s = NULL;
00562             } while (s && !(s->next));
00563             if (s)
00564                 s = s->next;
00565         }
00566     } while (s);
00567 
00568     /* Do some general stuff which should only be done once */
00569     restore_unsynced_topics();
00570     alog("Server %s is done syncing", serv->name);
00571 }
00572 
00573 /*******************************************************************/
00574 
00575 /* TS6 UID generator common code.
00576  *
00577  * Derived from atheme-services, uid.c (hg 2954:116d46894b4c).
00578  *         -nenolod
00579  */
00580 static int ts6_uid_initted = 0;
00581 static char ts6_new_uid[10];    /* allow for \0 */
00582 static unsigned int ts6_uid_index = 9;  /* last slot in uid buf */
00583 
00584 void ts6_uid_init(void)
00585 {
00586     /* check just in case... you can never be too safe. */
00587     if (TS6SID != NULL) {
00588         snprintf(ts6_new_uid, 10, "%sAAAAAA", TS6SID);
00589         ts6_uid_initted = 1;
00590     } else {
00591         alog("warning: no TS6SID specified, disabling TS6 support.");
00592         UseTS6 = 0;
00593 
00594         return;
00595     }
00596 }
00597 
00598 void ts6_uid_increment(unsigned int slot)
00599 {
00600     if (slot != strlen(TS6SID)) {
00601         if (ts6_new_uid[slot] == 'Z')
00602             ts6_new_uid[slot] = '0';
00603         else if (ts6_new_uid[slot] == '9') {
00604             ts6_new_uid[slot] = 'A';
00605             ts6_uid_increment(slot - 1);
00606         } else
00607             ts6_new_uid[slot]++;
00608     } else {
00609         if (ts6_new_uid[slot] == 'Z')
00610             for (slot = 3; slot < 9; slot++)
00611                 ts6_new_uid[slot] = 'A';
00612         else
00613             ts6_new_uid[slot]++;
00614     }
00615 }
00616 
00617 char *ts6_uid_retrieve(void)
00618 {
00619     if (ts6_uid_initted != 1)
00620         ts6_uid_init();
00621 
00622     ts6_uid_increment(ts6_uid_index - 1);
00623 
00624     return ts6_new_uid;
00625 }
00626 
00627 /* EOF */