summaryrefslogtreecommitdiff
path: root/src/hub/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hub/adc.c')
-rw-r--r--src/hub/adc.c257
1 files changed, 155 insertions, 102 deletions
diff --git a/src/hub/adc.c b/src/hub/adc.c
index 1382386..3a0819c 100644
--- a/src/hub/adc.c
+++ b/src/hub/adc.c
@@ -25,6 +25,27 @@
#include <tiger.h>
+__KHASH_IMPL(adcsids, static kh_inline, adc_sid_t, int64_t, 1, kh_int_hash_func, kh_int_hash_equal);
+
+static int64_t hub_adc_sid_get(hub_t *h, adc_sid_t sid) {
+ khiter_t k = kh_get(adcsids, h->a.sids, sid);
+ return k == kh_end(h->a.sids) ? -1 : kh_value(h->a.sids, k);
+}
+
+static void hub_adc_sid_set(hub_t *h, adc_sid_t sid, int64_t uid) {
+ int r;
+ khiter_t k = kh_put(adcsids, h->a.sids, sid, &r);
+ kh_value(h->a.sids, k) = uid;
+}
+
+static void hub_adc_sid_del(hub_t *h, adc_sid_t sid) {
+ khiter_t k = kh_get(adcsids, h->a.sids, sid);
+ if(k != kh_end(h->a.sids))
+ kh_del(adcsids, h->a.sids, k);
+}
+
+
+
/* Finalize, send and free an ADC message */
#define cmd_flush(h, msg) do {\
adc_final(msg);\
@@ -170,117 +191,149 @@ static void hub_adc_inf_user_client(hub_user_update_t *d, const char *ve, const
#define ERR(msg) do {\
- cmd_warn(h, cmd, len, msg);\
- hub_user_update_abort(&d);\
- return;\
+ cmd_warn(d->h, cmd, len, msg);\
+ return false;\
} while(0)
+
#define UINT(param, max) do {\
char *end = NULL;\
uint64_t _v = strtoull(p+2, &end, 10);\
if(!p[2] || !end || !adc_isparamend(*end))\
ERR("Invalid integer value");\
- d.u->param = _v >= max ? max : _v;\
+ d->u->param = _v >= max ? max : _v;\
} while(0)
-static void hub_adc_inf_user(hub_t *h, const char *cmd, int len, adc_sid_t sid) {
- const char *p, *ve = NULL, *ap = NULL;
- hub_user_update_t d;
- hub_user_update_init(h, &d, sid == h->a.mysid ? 0 : hub_users_bysid(h, sid));
- d.u->online = true;
- d.u->a.sid = sid;
- bool isreg = false;
-
- for(p=adc_param_start(cmd); p; p=adc_param_next(p)) {
- switch(adc_param_name(p)) {
- case ADC_PARAM('N','I'): free(d.u->nick); d.u->nick = adc_param_namevalue(p); hub_user_update_field(&d, HUBU_NICK ); break;
- case ADC_PARAM('D','E'): free(d.u->desc); d.u->desc = adc_param_namevalue(p); hub_user_update_field(&d, HUBU_DESCRIPTION); break;
- case ADC_PARAM('E','M'): free(d.u->mail); d.u->mail = adc_param_namevalue(p); hub_user_update_field(&d, HUBU_MAIL ); break;
- case ADC_PARAM('V','E'): ve = p; break;
- case ADC_PARAM('A','P'): ap = p; break;
- case ADC_PARAM('S','S'): UINT(sharesize, UINT64_MAX); hub_user_update_field(&d, HUBU_SHARESIZE ); break;
- case ADC_PARAM('S','F'): UINT(sharedfiles, UINT32_MAX); hub_user_update_field(&d, HUBU_SHAREDFILES); break;
- case ADC_PARAM('H','N'): UINT(hnorm, UINT8_MAX); hub_user_update_field(&d, HUBU_HUBS ); break;
- case ADC_PARAM('H','R'): UINT(hreg, UINT8_MAX); hub_user_update_field(&d, HUBU_HUBS ); break;
- case ADC_PARAM('H','O'): UINT(hop, UINT8_MAX); hub_user_update_field(&d, HUBU_HUBS ); break;
- case ADC_PARAM('S','L'): UINT(hop, UINT8_MAX); hub_user_update_field(&d, HUBU_SLOTS ); break;
- case ADC_PARAM('A','S'): UINT(as, UINT32_MAX); hub_user_update_field(&d, HUBU_AS ); break;
- case ADC_PARAM('U','S'): UINT(conn, UINT32_MAX); hub_user_update_field(&d, HUBU_CONN ); break;
- case ADC_PARAM('I','D'): {
- char *cid = adc_param_namevalue(p);
- if(!isbase32_24(cid)) {
- free(cid);
- ERR("Invalid CID");
- }
- if(d.u->id >= 0) {
- cmd_warn(h, cmd, len, "Ignoring repeated/duplicate ID");
- free(cid);
- break;
- }
- base32_decode(cid, d.u->a.cid, 24);
- hub_user_update_field(&d, HUBU_CID);
+static bool hub_adc_inf_user_param(hub_user_update_t *d, const char *cmd, int len, const char *p, const char **ve, const char **ap, bool *isreg) {
+ switch(adc_param_name(p)) {
+ case ADC_PARAM('N','I'): free(d->u->nick); d->u->nick = adc_param_namevalue(p); hub_user_update_field(d, HUBU_NICK ); break;
+ case ADC_PARAM('D','E'): free(d->u->desc); d->u->desc = adc_param_namevalue(p); hub_user_update_field(d, HUBU_DESCRIPTION); break;
+ case ADC_PARAM('E','M'): free(d->u->mail); d->u->mail = adc_param_namevalue(p); hub_user_update_field(d, HUBU_MAIL ); break;
+ case ADC_PARAM('V','E'): *ve = p; break;
+ case ADC_PARAM('A','P'): *ap = p; break;
+ case ADC_PARAM('S','S'): UINT(sharesize, UINT64_MAX); hub_user_update_field(d, HUBU_SHARESIZE ); break;
+ case ADC_PARAM('S','F'): UINT(sharedfiles, UINT32_MAX); hub_user_update_field(d, HUBU_SHAREDFILES); break;
+ case ADC_PARAM('H','N'): UINT(hnorm, UINT8_MAX); hub_user_update_field(d, HUBU_HUBS ); break;
+ case ADC_PARAM('H','R'): UINT(hreg, UINT8_MAX); hub_user_update_field(d, HUBU_HUBS ); break;
+ case ADC_PARAM('H','O'): UINT(hop, UINT8_MAX); hub_user_update_field(d, HUBU_HUBS ); break;
+ case ADC_PARAM('S','L'): UINT(hop, UINT8_MAX); hub_user_update_field(d, HUBU_SLOTS ); break;
+ case ADC_PARAM('A','S'): UINT(as, UINT32_MAX); hub_user_update_field(d, HUBU_AS ); break;
+ case ADC_PARAM('U','S'): UINT(conn, UINT32_MAX); hub_user_update_field(d, HUBU_CONN ); break;
+ case ADC_PARAM('I','D'): {
+ char *cid = adc_param_namevalue(p);
+ if(!isbase32_24(cid)) {
free(cid);
- break;
- }
- case ADC_PARAM('I','4'): {
- char *v = adc_param_namevalue(p);
- int r = inet_pton(AF_INET, v, &d.u->ip4);
- free(v);
- if(r != 1)
- ERR("Invalid IPv4 address");
- hub_user_update_field(&d, HUBU_IP4);
- break;
- }
- case ADC_PARAM('I','6'): {
- char *v = adc_param_namevalue(p);
- int r = inet_pton(AF_INET6, v, &d.u->ip6);
- free(v);
- if(r != 1)
- ERR("Invalid IPv6 address");
- hub_user_update_field(&d, HUBU_IP6);
- break;
+ ERR("Invalid CID");
}
- case ADC_PARAM('C','T'): {
- char *end = NULL;\
- uint64_t _v = strtoull(p+2, &end, 10);\
- if(!p[2] || !end || !adc_isparamend(*end))\
- ERR("Invalid integer value");\
- isreg = _v & (2|4|8|16);
- bool op = _v & (4|8|16);
- if(op != d.u->op)
- hub_user_update_field(&d, HUBU_FLAGS);
- d.u->op = op;
- break;
- }
- case ADC_PARAM('S','U'): {
- char *v = adc_param_namevalue(p);
- bool active = strstr(v, "TCP4") || strstr(v, "TCP6");
- bool tls = strstr(v, "ADC0") || strstr(v, "ADCS");
- if(active != d.u->active || tls != d.u->tls)
- hub_user_update_field(&d, HUBU_FLAGS);
- d.u->active = active;
- d.u->tls = tls;
- free(v);
- break;
- }
- case ADC_PARAM('A','W'): {
- bool aw = !(adc_isparamend(p[2]) || p[2] == '0');
- if(aw != d.u->away)
- hub_user_update_field(&d, HUBU_FLAGS);
- d.u->away = aw;
+ if(d->u->id >= 0) {
+ cmd_warn(d->h, cmd, len, "Ignoring repeated/duplicate ID");
+ free(cid);
break;
}
- /* TODO: U4 */
- }
+ base32_decode(cid, d->u->a.cid, 24);
+ hub_user_update_field(d, HUBU_CID);
+ free(cid);
+ break;
+ }
+ case ADC_PARAM('I','4'): {
+ char *v = adc_param_namevalue(p);
+ int r = inet_pton(AF_INET, v, &d->u->ip4);
+ free(v);
+ if(r != 1)
+ ERR("Invalid IPv4 address");
+ hub_user_update_field(d, HUBU_IP4);
+ break;
+ }
+ case ADC_PARAM('I','6'): {
+ char *v = adc_param_namevalue(p);
+ int r = inet_pton(AF_INET6, v, &d->u->ip6);
+ free(v);
+ if(r != 1)
+ ERR("Invalid IPv6 address");
+ hub_user_update_field(d, HUBU_IP6);
+ break;
}
+ case ADC_PARAM('C','T'): {
+ char *end = NULL;\
+ uint64_t _v = strtoull(p+2, &end, 10);\
+ if(!p[2] || !end || !adc_isparamend(*end))\
+ ERR("Invalid integer value");\
+ *isreg = _v & (2|4|8|16);
+ bool op = _v & (4|8|16);
+ if(op != d->u->op)
+ hub_user_update_field(d, HUBU_FLAGS);
+ d->u->op = op;
+ break;
+ }
+ case ADC_PARAM('S','U'): {
+ char *v = adc_param_namevalue(p);
+ bool active = strstr(v, "TCP4") || strstr(v, "TCP6");
+ bool tls = strstr(v, "ADC0") || strstr(v, "ADCS");
+ if(active != d->u->active || tls != d->u->tls)
+ hub_user_update_field(d, HUBU_FLAGS);
+ d->u->active = active;
+ d->u->tls = tls;
+ free(v);
+ break;
+ }
+ case ADC_PARAM('A','W'): {
+ bool aw = !(adc_isparamend(p[2]) || p[2] == '0');
+ if(aw != d->u->away)
+ hub_user_update_field(d, HUBU_FLAGS);
+ d->u->away = aw;
+ break;
+ }
+ /* TODO: U4 */
+ }
+ return true;
+}
+
+
+static bool hub_adc_inf_user_update(hub_user_update_t *d, const char *cmd, int len, bool *isreg, bool newuser) {
+ const char *p, *ve = NULL, *ap = NULL;
+
+ for(p=adc_param_start(cmd); p; p=adc_param_next(p))
+ if(!hub_adc_inf_user_param(d, cmd, len, p, &ve, &ap, isreg))
+ return false;
if(ve)
- hub_adc_inf_user_client(&d, ve, ap);
+ hub_adc_inf_user_client(d, ve, ap);
- if(!d.u->nick || !*d.u->nick)
+ if(!d->u->nick || !*d->u->nick)
ERR("No or empty nick");
- if(!hub_user_update_done(&d))
- cmd_warn(h, cmd, len, "No CID in INF for new user");
+ if(newuser) {
+ char emptycid[sizeof(d->u->a.cid)] = {};
+ if(memcmp(d->u->a.cid, emptycid, sizeof(d->u->a.cid)) == 0)
+ ERR("No CID in INF for new user");
+ d->u->id = hub_users_genid(d->h, d->u->a.cid, sizeof(d->u->a.cid));
+ }
+ return true;
+}
+
+#undef UINT
+#undef ERR
+
+
+static void hub_adc_inf_user(hub_t *h, const char *cmd, int len, adc_sid_t sid) {
+ bool isreg = false;
+ hub_user_update_t d[1];
+
+ int64_t uid = hub_adc_sid_get(h, sid);
+ hub_user_t *u = uid >= 0 ? hub_users_get(h, uid) : hub_user_new(true);
+ assert(u != NULL);
+
+ hub_user_update_init(h, d, u);
+ d->u->a.sid = sid;
+
+ bool okay = hub_adc_inf_user_update(d, cmd, len, &isreg, uid < 0);
+ if(uid < 0) {
+ if(okay)
+ hub_adc_sid_set(h, sid, u->id);
+ else
+ hub_user_unref(h, u);
+ }
+ if(okay)
+ hub_user_update_done(d, uid < 0);
/* Our own SID comes last, at which point we're in NORMAL */
if(sid == h->a.mysid && h->a.state != ADC_NORMAL) {
@@ -289,13 +342,10 @@ static void hub_adc_inf_user(hub_t *h, const char *cmd, int len, adc_sid_t sid)
h->a.state = ADC_NORMAL;
hub_users_listcomplete(h);
if(isreg)
- hub_manager_settype(h, d.u->op ? HUBM_HOP : HUBM_HREG);
+ hub_manager_settype(h, u->op ? HUBM_HOP : HUBM_HREG);
}
}
-#undef UINT
-#undef ERR
-
static void hub_adc_inf(hub_t *h, const char *cmd, int len) {
adc_sid_t src = adc_source(cmd);
@@ -325,17 +375,18 @@ static void hub_adc_qui(hub_t *h, const char *cmd, int len) {
}
if(sid != h->a.mysid) {
- int64_t id = hub_users_bysid(h, sid);
+ int64_t id = hub_adc_sid_get(h, sid);
if(id == -1)
cmd_warn(h, cmd, len, "QUI for user not on this hub");
else {
- int64_t initid = initiator == -1 ? -2 : hub_users_bysid(h, initiator);
+ int64_t initid = initiator == -1 ? -2 : hub_adc_sid_get(h, initiator);
hub_user_left(h, id, initid, message ? message : "");
}
} else {
/* We've been disconnected. */
hub_hub_seterror(h, redir ? 0 : HUBCD_RECONNECT, redir ? "Redirect" : "Disconnect", message ? message : "Disconnected from hub", redir);
}
+ hub_adc_sid_del(h, sid);
free(message);
}
@@ -349,7 +400,7 @@ static void hub_adc_msg(hub_t *h, const char *cmd, int len) {
adc_sid_t src = adc_source(cmd);
int64_t user = -1;
- if(src >= 0 && (user = hub_users_bysid(h, src)) == -1) {
+ if(src >= 0 && (user = hub_adc_sid_get(h, src)) == -1) {
cmd_warn(h, cmd, len, "MSG from an unknown SID");
return;
}
@@ -365,7 +416,7 @@ static void hub_adc_msg(hub_t *h, const char *cmd, int len) {
}
int64_t group = -1;
- if(pmsid == -2 || (pmsid >= 0 && (group = hub_users_bysid(h, pmsid)) == -1)) {
+ if(pmsid == -2 || (pmsid >= 0 && (group = hub_adc_sid_get(h, pmsid)) == -1)) {
cmd_warn(h, cmd, len, "MSG with unknown SID in PM param");
free(msg);
return;
@@ -379,7 +430,7 @@ static void hub_adc_msg(hub_t *h, const char *cmd, int len) {
/* If we sent a PM and this message is its echo, make sure to set the group
* to whatever SID we sent it to. */
- if(group == 0 && dest != -1 && (group = hub_users_bysid(h, dest)) == -1) {
+ if(group == 0 && dest != -1 && (group = hub_adc_sid_get(h, dest)) == -1) {
cmd_warn(h, cmd, len, "MSG with unknown SID as target");
free(msg);
return;
@@ -632,6 +683,7 @@ static void hub_adc_connected(hub_t *h) {
kstring_t msg = {};
h->a.state = ADC_PROTOCOL;
h->a.havelastinf = false;
+ h->a.sids = kh_init(adcsids);
adc_create(&msg, 'H', ADC_CMD_SUP, 0, 0);
adc_append(&msg, "ADBASE");
@@ -644,6 +696,7 @@ static void hub_adc_connected(hub_t *h) {
static void hub_adc_disconnected(hub_t *h) {
if(h->a.havelastinf)
hub_adc_myinf_free(&h->a.lastinf);
+ kh_destroy(adcsids, h->a.sids);
hub_manager_settype(h, HUBM_HNONE);
}