diff options
Diffstat (limited to 'src/hub/adc.c')
-rw-r--r-- | src/hub/adc.c | 257 |
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); } |