/*
- * charybdis: an advanced ircd.
+ * Solanum: a slightly advanced ircd
* client.c: Controls clients.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
- * Copyright (C) 2007 William Pitcock
+ * Copyright (C) 2007 Ariadne Conill <ariadne@dereferenced.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
- *
- * $Id: client.c 3514 2007-06-06 16:25:21Z nenolod $
*/
#include "stdinc.h"
-#include "config.h"
+#include "defaults.h"
#include "client.h"
#include "class.h"
-#include "common.h"
#include "hash.h"
#include "match.h"
#include "ircd.h"
#include "numeric.h"
#include "packet.h"
-#include "s_auth.h"
+#include "authproc.h"
#include "s_conf.h"
#include "s_newconf.h"
#include "logger.h"
#include "hook.h"
#include "msg.h"
#include "monitor.h"
-#include "blacklist.h"
#include "reject.h"
#include "scache.h"
-#include "irc_dictionary.h"
+#include "rb_dictionary.h"
#include "sslproc.h"
+#include "wsproc.h"
#include "s_assert.h"
#define DEBUG_EXITED_CLIENTS
static rb_bh *user_heap = NULL;
static rb_bh *away_heap = NULL;
static char current_uid[IDLEN];
-static int32_t current_connid = 0;
-
-struct Dictionary *nd_dict = NULL;
+static uint32_t current_connid = 0;
-enum
-{
- D_LINED,
- K_LINED
-};
+rb_dictionary *nd_dict = NULL;
rb_dlink_list dead_list;
#ifdef DEBUG_EXITED_CLIENTS
rb_event_addish("exit_aborted_clients", exit_aborted_clients, NULL, 1);
rb_event_add("flood_recalc", flood_recalc, NULL, 1);
- nd_dict = irc_dictionary_create("nickdelay", irccmp);
+ nd_dict = rb_dictionary_create("nickdelay", irccmp);
}
+/*
+ * connid_get - allocate a connid
+ *
+ * inputs - none
+ * outputs - a connid token which is used to represent a logical circuit
+ * side effects - current_connid is incremented, possibly multiple times.
+ * the association of the connid to it's client is committed.
+ */
+uint32_t
+connid_get(struct Client *client_p)
+{
+ s_assert(MyConnect(client_p));
+ if (!MyConnect(client_p))
+ return 0;
+
+ /* find a connid that is available */
+ while (find_cli_connid_hash(++current_connid) != NULL)
+ {
+ /* handle wraparound, current_connid must NEVER be 0 */
+ if (current_connid == 0)
+ ++current_connid;
+ }
+
+ add_to_cli_connid_hash(client_p, current_connid);
+ rb_dlinkAddAlloc(RB_UINT_TO_POINTER(current_connid), &client_p->localClient->connids);
+
+ return current_connid;
+}
+
+/*
+ * connid_put - free a connid
+ *
+ * inputs - connid to free
+ * outputs - nothing
+ * side effects - connid bookkeeping structures are freed
+ */
+void
+connid_put(uint32_t id)
+{
+ struct Client *client_p;
+
+ s_assert(id != 0);
+ if (id == 0)
+ return;
+
+ client_p = find_cli_connid_hash(id);
+ if (client_p == NULL)
+ return;
+
+ del_from_cli_connid_hash(id);
+ rb_dlinkFindDestroy(RB_UINT_TO_POINTER(id), &client_p->localClient->connids);
+}
+
+/*
+ * client_release_connids - release any connids still attached to a client
+ *
+ * inputs - client to garbage collect
+ * outputs - none
+ * side effects - client's connids are garbage collected
+ */
+void
+client_release_connids(struct Client *client_p)
+{
+ rb_dlink_node *ptr, *ptr2;
+
+ if (client_p->localClient->connids.head)
+ s_assert(MyConnect(client_p));
+
+ if (!MyConnect(client_p))
+ return;
+
+ RB_DLINK_FOREACH_SAFE(ptr, ptr2, client_p->localClient->connids.head)
+ connid_put(RB_POINTER_TO_UINT(ptr->data));
+}
/*
* make_client - create a new Client struct and set it to initial state.
client_p->localClient->F = NULL;
- if(current_connid+1 == 0)
- current_connid++;
-
- client_p->localClient->connid = ++current_connid;
-
- if(current_connid+1 == 0)
- current_connid++;
-
- client_p->localClient->zconnid = ++current_connid;
- add_to_cli_connid_hash(client_p);
-
client_p->preClient = rb_bh_alloc(pclient_heap);
/* as good a place as any... */
}
SetUnknown(client_p);
- strcpy(client_p->username, "unknown");
+ rb_strlcpy(client_p->username, "unknown", sizeof(client_p->username));
return client_p;
}
void
free_pre_client(struct Client *client_p)
{
- struct Blacklist *blptr;
-
s_assert(NULL != client_p);
if(client_p->preClient == NULL)
return;
- blptr = client_p->preClient->dnsbl_listed;
- if (blptr != NULL)
- unref_blacklist(blptr);
- s_assert(rb_dlink_list_length(&client_p->preClient->dnsbl_queries) == 0);
+ s_assert(client_p->preClient->auth.cid == 0);
+
+ rb_free(client_p->preClient->auth.data);
+ rb_free(client_p->preClient->auth.reason);
rb_bh_free(pclient_heap, client_p->preClient);
client_p->preClient = NULL;
client_p->localClient->listener = 0;
}
- del_from_cli_connid_hash(client_p);
+ client_release_connids(client_p);
if(client_p->localClient->F != NULL)
{
rb_close(client_p->localClient->F);
rb_free(client_p->localClient->auth_user);
rb_free(client_p->localClient->challenge);
rb_free(client_p->localClient->fullcaps);
- rb_free(client_p->localClient->opername);
rb_free(client_p->localClient->mangledhost);
- if (client_p->localClient->privset)
- privilegeset_unref(client_p->localClient->privset);
- if(IsSSL(client_p))
- ssld_decrement_clicount(client_p->localClient->ssl_ctl);
+ if (IsSSL(client_p))
+ ssld_decrement_clicount(client_p->localClient->ssl_ctl);
- if(IsCapable(client_p, CAP_ZIP))
- ssld_decrement_clicount(client_p->localClient->z_ctl);
+ rb_free(client_p->localClient->cipher_string);
+
+ if (client_p->localClient->ws_ctl != NULL)
+ wsockd_decrement_clicount(client_p->localClient->ws_ctl);
rb_bh_free(lclient_heap, client_p->localClient);
client_p->localClient = NULL;
}
-void
+static void
free_client(struct Client *client_p)
{
s_assert(NULL != client_p);
{
if(IsServer(client_p))
{
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"No response from %s, closing link",
client_p->name);
ilog(L_SERVER,
"No response from %s, closing link",
log_client_name(client_p, HIDE_IP));
}
- (void) rb_snprintf(scratch, sizeof(scratch),
+ (void) snprintf(scratch, sizeof(scratch),
"Ping timeout: %d seconds",
(int) (rb_current_time() - client_p->localClient->lasttime));
if(IsDead(client_p) || IsClosing(client_p))
continue;
- /* still has DNSbls to validate against */
- if(client_p->preClient != NULL &&
- rb_dlink_list_length(&client_p->preClient->dnsbl_queries) > 0)
+ /* Still querying with authd */
+ if(client_p->preClient != NULL && client_p->preClient->auth.cid != 0)
continue;
/*
{
if(IsAnyServer(client_p))
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"No response from %s, closing link",
client_p->name);
ilog(L_SERVER,
}
}
-static void
+void
notify_banned_client(struct Client *client_p, struct ConfItem *aconf, int ban)
{
static const char conn_closed[] = "Connection closed";
check_xlines();
}
-/* check_klines_event()
- *
- * inputs -
- * outputs -
- * side effects - check_klines() is called, kline_queued unset
- */
-void
-check_klines_event(void *unused)
-{
- kline_queued = 0;
- check_klines();
-}
-
/* check_klines
*
* inputs -
{
if(IsExemptKline(client_p))
{
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
get_client_name(client_p, HIDE_IP),
aconf->user, aconf->host);
continue;
}
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "KLINE active for %s",
- get_client_name(client_p, HIDE_IP));
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "Disconnecting K-Lined user %s (%s@%s)",
+ get_client_name(client_p, HIDE_IP), aconf->user, aconf->host);
notify_banned_client(client_p, aconf, K_LINED);
continue;
}
}
+
+/* check_one_kline()
+ *
+ * This process needs to be kept in sync with find_kline() aka find_conf_by_address().
+ *
+ * inputs - pointer to kline to check
+ * outputs -
+ * side effects - all clients will be checked against given kline
+ */
+void
+check_one_kline(struct ConfItem *kline)
+{
+ struct Client *client_p;
+ rb_dlink_node *ptr;
+ rb_dlink_node *next_ptr;
+ int masktype;
+ int bits;
+ struct rb_sockaddr_storage sockaddr;
+ struct sockaddr_in ip4;
+
+ masktype = parse_netmask(kline->host, (struct sockaddr_storage *)&sockaddr, &bits);
+
+ RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+ {
+ int matched = 0;
+
+ client_p = ptr->data;
+
+ if(IsMe(client_p) || !IsPerson(client_p))
+ continue;
+
+ if(!match(kline->user, client_p->username))
+ continue;
+
+ /* match one kline */
+ switch (masktype) {
+ case HM_IPV4:
+ case HM_IPV6:
+ if (IsConfDoSpoofIp(client_p->localClient->att_conf) &&
+ IsConfKlineSpoof(client_p->localClient->att_conf))
+ break;
+ if (client_p->localClient->ip.ss_family == AF_INET6 && sockaddr.ss_family == AF_INET &&
+ rb_ipv4_from_ipv6((struct sockaddr_in6 *)&client_p->localClient->ip, &ip4)
+ && comp_with_mask_sock((struct sockaddr *)&ip4, (struct sockaddr *)&sockaddr, bits))
+ matched = 1;
+ else if (client_p->localClient->ip.ss_family == sockaddr.ss_family &&
+ comp_with_mask_sock((struct sockaddr *)&client_p->localClient->ip,
+ (struct sockaddr *)&sockaddr, bits))
+ matched = 1;
+ break;
+ case HM_HOST:
+ if (match(kline->host, client_p->orighost))
+ matched = 1;
+ if (IsConfDoSpoofIp(client_p->localClient->att_conf) &&
+ IsConfKlineSpoof(client_p->localClient->att_conf))
+ break;
+ if (match(kline->host, client_p->sockhost))
+ matched = 1;
+ break;
+ }
+
+ if (!matched)
+ continue;
+
+ if(IsExemptKline(client_p))
+ {
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
+ get_client_name(client_p, HIDE_IP),
+ kline->user, kline->host);
+ continue;
+ }
+
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "Disconnecting K-Lined user %s (%s@%s)",
+ get_client_name(client_p, HIDE_IP), kline->user, kline->host);
+
+ notify_banned_client(client_p, kline, K_LINED);
+ }
+}
+
+
/* check_dlines()
*
* inputs -
if(IsMe(client_p))
continue;
- if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
+ if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL)
{
if(aconf->status & CONF_EXEMPTDLINE)
continue;
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "DLINE active for %s",
- get_client_name(client_p, HIDE_IP));
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "Disconnecting D-Lined user %s (%s)",
+ get_client_name(client_p, HIDE_IP), aconf->host);
notify_banned_client(client_p, aconf, D_LINED);
continue;
{
client_p = ptr->data;
- if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
+ if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL)
{
if(aconf->status & CONF_EXEMPTDLINE)
continue;
{
if(IsExemptKline(client_p))
{
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"XLINE over-ruled for %s, client is kline_exempt [%s]",
get_client_name(client_p, HIDE_IP),
aconf->host);
continue;
}
- sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s",
- get_client_name(client_p, HIDE_IP));
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+ "Disconnecting X-Lined user %s (%s)",
+ get_client_name(client_p, HIDE_IP), aconf->host);
(void) exit_client(client_p, client_p, &me, "Bad user info");
continue;
nick = client_p->id;
/* Tell opers. */
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"RESV forced nick change for %s!%s@%s to %s; nick matched [%s] (%s)",
client_p->name, client_p->username, client_p->host, nick, mask, reason);
- sendto_realops_snomask(SNO_NCHANGE, L_ALL,
+ sendto_realops_snomask(SNO_NCHANGE, L_NETWIDE,
"Nick change: From %s to %s [%s@%s]",
client_p->name, nick, client_p->username, client_p->host);
/* Do all of the nick-changing gymnastics. */
client_p->tsinfo = rb_current_time();
- add_history(client_p, 1);
+ whowas_add_history(client_p, 1);
monitor_signoff(client_p);
rb_dlinkDestroy(ptr, &client_p->on_allow_list);
}
- rb_snprintf(note, sizeof(note), "Nick: %s", nick);
+ snprintf(note, sizeof(note), "Nick: %s", nick);
rb_note(client_p->localClient->F, note);
}
}
if(who || IsDigit(*user))
return who;
- if(!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
+ if(!(who = whowas_get_history(user, (long) KILLCHASETIMELIMIT)))
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
form_str(ERR_NOSUCHNICK), user);
switch (showip)
{
case SHOW_IP:
- rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
client->name, client->username,
client->sockhost);
break;
case MASK_IP:
- rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
client->name, client->username);
break;
default:
- rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
client->name, client->username, client->host);
}
return nbuf;
switch (showip)
{
case SHOW_IP:
- rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
target_p->username, target_p->sockhost);
break;
default:
- rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
target_p->username, target_p->host);
}
{
s_assert(0);
sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "On abort_list: %s stat: %u flags: %u/%u handler: %c",
+ "On abort_list: %s stat: %u flags: %llu handler: %c",
target_p->name, (unsigned int) target_p->status,
- target_p->flags, target_p->flags2, target_p->handler);
+ (unsigned long long)target_p->flags, target_p->handler);
sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "Please report this to the charybdis developers!");
+ "Please report this to the solanum developers!");
found++;
}
}
** already been sent. we make sure to exit a server's dependent clients
** and servers before the server itself; exit_one_client takes care of
** actually removing things off llists. tweaked from +CSr31 -orabidoo
-*/
+ */
/*
* added sanity test code.... source_p->serv might be NULL...
*/
** Remove *everything* that depends on source_p, from all lists, and sending
** all necessary SQUITs. source_p itself is still on the lists,
** and its SQUITs have been sent except for the upstream one -orabidoo
-*/
+ */
static void
remove_dependents(struct Client *client_p,
struct Client *source_p,
{
s_assert(0);
sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "On dead_list: %s stat: %u flags: %u/%u handler: %c",
+ "On dead_list: %s stat: %u flags: %llu handler: %c",
abt->client->name, (unsigned int) abt->client->status,
- abt->client->flags, abt->client->flags2, abt->client->handler);
+ (unsigned long long)abt->client->flags, abt->client->handler);
sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "Please report this to the charybdis developers!");
+ "Please report this to the solanum developers!");
continue;
}
}
rb_dlinkDelete(ptr, &abort_list);
if(IsAnyServer(abt->client))
- sendto_realops_snomask(SNO_GENERAL, L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Closing link to %s: %s",
abt->client->name, abt->notice);
/*
* dead_link - Adds client to a list of clients that need an exit_client()
- *
*/
void
dead_link(struct Client *client_p, int sendqex)
if(sendqex)
rb_strlcpy(abt->notice, "Max SendQ exceeded", sizeof(abt->notice));
else
- rb_snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno));
+ snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno));
abt->client = client_p;
SetIOError(client_p);
/* Clean up allow lists */
del_all_accepts(source_p);
- add_history(source_p, 0);
- off_history(source_p);
+ whowas_add_history(source_p, 0);
+ whowas_off_history(source_p);
monitor_signoff(source_p);
}
/*
- * This assumes IsUnknown(source_p) == TRUE and MyConnect(source_p) == TRUE
+ * This assumes IsUnknown(source_p) == true and MyConnect(source_p) == true
*/
static int
-exit_unknown_client(struct Client *client_p, struct Client *source_p, struct Client *from,
- const char *comment)
+exit_unknown_client(struct Client *client_p, /* The local client originating the
+ * exit or NULL, if this exit is
+ * generated by this server for
+ * internal reasons.
+ * This will not get any of the
+ * generated messages. */
+ struct Client *source_p, /* Client exiting */
+ struct Client *from, /* Client firing off this Exit,
+ * never NULL! */
+ const char *comment)
{
- delete_auth_queries(source_p);
- abort_blacklist_queries(source_p);
+ authd_abort_client(source_p);
rb_dlinkDelete(&source_p->localClient->tnode, &unknown_list);
if(!IsIOError(source_p))
del_from_id_hash(source_p->id, source_p);
del_from_hostname_hash(source_p->host, source_p);
- del_from_client_hash(source_p->name, source_p);
+ if (!IsAnyServer(source_p))
+ del_from_client_hash(source_p->name, source_p);
remove_client_from_list(source_p);
SetDead(source_p);
rb_dlinkAddAlloc(source_p, &dead_list);
strcat(comment1, source_p->name);
}
if (IsPerson(from))
- rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s",
+ snprintf(newcomment, sizeof(newcomment), "by %s: %s",
from->name, comment);
- if(source_p->serv != NULL)
- remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
+ remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
- if(source_p->servptr && source_p->servptr->serv)
- rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
- else
- s_assert(0);
+ rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
rb_dlinkFindDestroy(source_p, &global_serv_list);
target_p = source_p->from;
del_from_client_hash(source_p->name, source_p);
remove_client_from_list(source_p);
+
scache_split(source_p->serv->nameinfo);
SetDead(source_p);
/* Always show source here, so the server notices show
* which side initiated the split -- jilles
*/
- rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s",
+ snprintf(newcomment, sizeof(newcomment), "by %s: %s",
from == source_p ? me.name : from->name, comment);
if (!IsIOError(source_p))
sendto_one(source_p, "SQUIT %s :%s", use_id(source_p),
/*
- * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE
+ * This assumes IsPerson(source_p) == true && MyConnect(source_p) == true
*/
static int
**
** CLIENT_EXITED if (client_p == source_p)
** 0 if (client_p != source_p)
-*/
+ */
int
exit_client(struct Client *client_p, /* The local client originating the
* exit or NULL, if this exit is
const char *comment /* Reason for the exit */
)
{
+ int ret = -1;
+
hook_data_client_exit hdata;
if(IsClosing(source_p))
return -1;
{
/* Local clients of various types */
if(IsPerson(source_p))
- return exit_local_client(client_p, source_p, from, comment);
+ ret = exit_local_client(client_p, source_p, from, comment);
else if(IsServer(source_p))
- return exit_local_server(client_p, source_p, from, comment);
+ ret = exit_local_server(client_p, source_p, from, comment);
/* IsUnknown || IsConnecting || IsHandShake */
else if(!IsReject(source_p))
- return exit_unknown_client(client_p, source_p, from, comment);
+ ret = exit_unknown_client(client_p, source_p, from, comment);
}
else
{
/* Remotes */
if(IsPerson(source_p))
- return exit_remote_client(client_p, source_p, from, comment);
+ ret = exit_remote_client(client_p, source_p, from, comment);
else if(IsServer(source_p))
- return exit_remote_server(client_p, source_p, from, comment);
+ ret = exit_remote_server(client_p, source_p, from, comment);
}
- return -1;
+ call_hook(h_after_client_exit, NULL);
+
+ return ret;
}
/*
* to local opers.
*/
if(!ConfigFileEntry.hide_spoof_ips &&
- (source_p == NULL || MyOper(source_p)))
+ (source_p == NULL || HasPrivilege(source_p, "auspex:hostname")))
return 1;
return 0;
}
- else if(IsDynSpoof(target_p) && (source_p != NULL && !IsOper(source_p)))
+ else if(IsDynSpoof(target_p) && (source_p != NULL && !HasPrivilege(source_p, "auspex:hostname")))
return 0;
else
return 1;
{
if(user->away)
rb_free((char *) user->away);
+ rb_free(user->opername);
+ if (user->privset)
+ privilegeset_unref(user->privset);
/*
* sanity check
*/
if(user->refcnt < 0 || user->invited.head || user->channel.head)
{
sendto_realops_snomask(SNO_GENERAL, L_ALL,
- "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *",
- (unsigned long) client_p,
+ "* %p user (%s!%s@%s) %p %p %p %lu %d *",
+ client_p,
client_p ? client_p->
name : "<noname>",
client_p->username,
client_p->host,
- (unsigned long) user,
- (unsigned long) user->invited.head,
- (unsigned long) user->channel.head,
+ user,
+ user->invited.head,
+ user->channel.head,
rb_dlink_list_length(&user->channel),
user->refcnt);
s_assert(!user->refcnt);
char *
generate_uid(void)
{
+ static int flipped = 0;
int i;
+uid_restart:
for(i = 8; i > 3; i--)
{
if(current_uid[i] == 'Z')
{
current_uid[i] = '0';
- return current_uid;
+ goto out;
}
else if(current_uid[i] != '9')
{
current_uid[i]++;
- return current_uid;
+ goto out;
}
else
current_uid[i] = 'A';
if(current_uid[3] == 'Z')
{
current_uid[i] = 'A';
- s_assert(0);
+ flipped = 1;
}
else
current_uid[i]++;
-
+out:
+ /* if this happens..well, i'm not sure what to say, but lets handle it correctly */
+ if(rb_unlikely(flipped))
+ {
+ /* this slows down uid generation a bit... */
+ if(find_id(current_uid) != NULL)
+ goto uid_restart;
+ }
return current_uid;
}
else
ServerStats.is_ni++;
+ client_release_connids(client_p);
+
if(client_p->localClient->F != NULL)
{
/* attempt to flush any pending dbufs. Evil, but .. -- adrian */
if(!IsIOError(client_p))
send_queued(client_p);
- del_from_cli_connid_hash(client_p);
rb_close(client_p->localClient->F);
client_p->localClient->F = NULL;
}
{
if(error == 0)
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Server %s closed the connection",
client_p->name);
}
else
{
- sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
+ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Lost connection to %s: %s",
client_p->name, strerror(current_error));
ilog(L_SERVER, "Lost connection to %s: %s",
if(error == 0)
rb_strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg));
else
- rb_snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
+ snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
exit_client(client_p, client_p, &me, errmsg);
}