servers.c

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

Generated on Sun Dec 30 09:26:53 2007 for Anope by  doxygen 1.5.1-20070107