- while ((acptr = FindClient(host)) ||
- (parc > 7 && (acptr = FindNServer(parv[6]))))
- {
- /*
- * This link is trying feed me a server that I already have
- * access through another path
- *
- * Do not allow Uworld to do this.
- * Do not allow servers that are juped.
- * Do not allow servers that have older link timestamps
- * then this try.
- * Do not allow servers that use the same numeric as an existing
- * server, but have a different name.
- *
- * If my ircd.conf sucks, I can try to connect to myself:
- */
- if (acptr == &me)
- return exit_client_msg(cptr, cptr, &me,
- "nick collision with me, check server number in M:? (%s)", host);
- /*
- * Detect wrong numeric.
- */
- if (0 != ircd_strcmp(cli_name(acptr), host))
- {
- sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
- ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
- host);
- return exit_client_msg(cptr, cptr, &me,
- "NUMERIC collision between %s and %s."
- " Is your server numeric correct ?", host, cli_name(acptr));
- }
- /*
- * Kill our try, if we had one.
- */
- if (IsConnecting(acptr))
- {
- if (!active_lh_line && exit_client(cptr, acptr, &me,
- "Just connected via another link") == CPTR_KILLED)
- return CPTR_KILLED;
- /*
- * We can have only ONE 'IsConnecting', 'IsHandshake' or
- * 'IsServer', because new 'IsConnecting's are refused to
- * the same server if we already had it.
- */
- break;
- }
- /*
- * Avoid other nick collisions...
- * This is a doubtfull test though, what else would it be
- * when it has a server.name ?
- */
- else if (!IsServer(acptr) && !IsHandshake(acptr))
- return exit_client_msg(cptr, cptr, &me,
- "Nickname %s already exists!", host);
- /*
- * Our new server might be a juped server,
- * or someone trying abuse a second Uworld:
- */
- else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
- find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
- {
- if (!IsServer(sptr))
- return exit_client(cptr, sptr, &me, cli_info(acptr));
- sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
- "from %s !?!", parv[0], parv[1], cli_name(cptr));
- return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
- }
- /*
- * Of course we find the handshake this link was before :)
- */
- else if (IsHandshake(acptr) && acptr == cptr)
- break;
- /*
- * Here we have a server nick collision...
- * We don't want to kill the link that was last /connected,
- * but we neither want to kill a good (old) link.
- * Therefor we kill the second youngest link.
- */
- if (1)
- {
- struct Client* c2ptr = 0;
- struct Client* c3ptr = acptr;
- struct Client* ac2ptr;
- struct Client* ac3ptr;
-
- /* Search youngest link: */
- for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
- if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
- c3ptr = ac3ptr;
- if (IsServer(sptr))
- {
- for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
- if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
- c3ptr = ac3ptr;
- }
- if (timestamp > cli_serv(c3ptr)->timestamp)
- {
- c3ptr = 0;
- c2ptr = acptr; /* Make sure they differ */
- }
- /* Search second youngest link: */
- for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
- if (ac2ptr != c3ptr &&
- cli_serv(ac2ptr)->timestamp >
- (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
- c2ptr = ac2ptr;
- if (IsServer(sptr))
- {
- for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
- if (ac2ptr != c3ptr &&
- cli_serv(ac2ptr)->timestamp >
- (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
- c2ptr = ac2ptr;
- }
- if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
- c2ptr = 0;
- /* If timestamps are equal, decide which link to break
- * by name.
- */
- if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
- (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
- {
- char* n2;
- char* n2up;
- char* n3;
- char* n3up;
- if (c2ptr)
- {
- n2 = cli_name(c2ptr);
- n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
- }
- else
- {
- n2 = host;
- n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
- }
- if (c3ptr)
- {
- n3 = cli_name(c3ptr);
- n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
- }
- else
- {
- n3 = host;
- n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
- }
- if (strcmp(n2, n2up) > 0)
- n2 = n2up;
- if (strcmp(n3, n3up) > 0)
- n3 = n3up;
- if (strcmp(n3, n2) > 0)
- {
- ac2ptr = c2ptr;
- c2ptr = c3ptr;
- c3ptr = ac2ptr;
- }
- }
- /* Now squit the second youngest link: */
- if (!c2ptr)
- return exit_new_server(cptr, sptr, host, timestamp,
- "server %s already exists and is %ld seconds younger.",
- host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
- else if (cli_from(c2ptr) == cptr || IsServer(sptr))
- {
- struct Client *killedptrfrom = cli_from(c2ptr);
- if (active_lh_line)
- {
- /*
- * If the L: or H: line also gets rid of this link,
- * we sent just one squit.
- */
- if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
- break;
- /*
- * If breaking the loop here solves the L: or H:
- * line problem, we don't squit that.
- */
- if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
- active_lh_line = 0;
- else
- {
- /*
- * If we still have a L: or H: line problem,
- * we prefer to squit the new server, solving
- * loop and L:/H: line problem with only one squit.
- */
- LHcptr = 0;
- break;
- }
- }
- /*
- * If the new server was introduced by a server that caused a
- * Ghost less then 20 seconds ago, this is probably also
- * a Ghost... (20 seconds is more then enough because all
- * SERVER messages are at the beginning of a net.burst). --Run
- */
- if (CurrentTime - cli_serv(cptr)->ghost < 20)
- {
- killedptrfrom = cli_from(acptr);
- if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
- return CPTR_KILLED;
- }
- else if (exit_client_msg(cptr, c2ptr, &me,
- "Loop <-- %s (new link is %ld seconds younger)", host,
- (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
- (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
- return CPTR_KILLED;
- /*
- * Did we kill the incoming server off already ?
- */
- if (killedptrfrom == cptr)
- return 0;
- }
- else
- {
- if (active_lh_line)
- {
- if (LHcptr && a_kills_b_too(LHcptr, acptr))
- break;
- if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
- active_lh_line = 0;
- else
- {
- LHcptr = 0;
- break;
- }
- }
- /*
- * We can't believe it is a lagged server message
- * when it directly connects to us...
- * kill the older link at the ghost, rather then
- * at the second youngest link, assuming it isn't
- * a REAL loop.
- */
- ghost = CurrentTime; /* Mark that it caused a ghost */
- if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
- return CPTR_KILLED;
- break;
- }
- }
- }