skip to content
==> src/infer_svc.c <==
1/* The members' service addresses (infer.rs Svc). */
2#include "mesh/infer_svc.h"
3#include "mesh/buf.h"
4#include "mesh/rsfmt.h"
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10/* "host:port" split at the last ':'; the port a u16. */
11static int split_hp(const char *a, char *host, size_t hn, uint16_t *port, char **err) {
12    const char *c = strrchr(a, ':');
13    mesh_buf e = MESH_BUF_INIT;
14    if (!c) {
15        mesh_rs_debug_cstr(&e, a);
16        mesh_buf_puts(&e, ": host:port");
17        *err = mesh_buf_take(&e);
18        return -1;
19    }
20    const char *p = c + 1 + (c[1] == '+' && c[2]);
21    unsigned long v = 0;
22    int ok = *p != 0;
23    for (; ok && *p; p++) { ok = *p >= '0' && *p <= '9'; v = v * 10 + (unsigned long)(*p - '0'); ok = ok && v <= 65535; }
24    if (!ok) {
25        mesh_rs_debug_cstr(&e, a);
26        mesh_buf_puts(&e, ": bad port");
27        *err = mesh_buf_take(&e);
28        return -1;
29    }
30    snprintf(host, hn, "%.*s", (int)(c - a), a);
31    *port = (uint16_t)v;
32    return 0;
33}
34
35int mesh_infer_svc_single(mesh_infer_svc *s, const char *control, char **err) {
36    memset(s, 0, sizeof *s);
37    char host[256];
38    uint16_t port;
39    if (split_hp(control, host, sizeof host, &port, err)) return -1;
40    s->n = 1;
41    strcpy(s->hosts[0], "127.0.0.1");
42    s->bases[0] = port;
43    return 0;
44}
45
46int mesh_infer_svc_cluster(mesh_infer_svc *s, const char *(*get)(void *, const char *), void *ctx, uint32_t me, uint32_t n,
47                           char **err) {
48    memset(s, 0, sizeof *s);
49    s->me = me;
50    for (uint32_t k = 0; k < n && k < MESH_INFER_SVC_MAX; k++) {
51        char key[32];
52        snprintf(key, sizeof key, "%u.peer", k);
53        const char *a = get(ctx, key);
54        if (!a) { *err = mesh_buf_fmt("cluster: no %u.peer", k); return -1; }
55        if (split_hp(a, s->hosts[k], sizeof s->hosts[k], &s->bases[k], err)) return -1;
56        snprintf(key, sizeof key, "%u.lan", k);
57        const char *lan = get(ctx, key);
58        snprintf(s->lans[k], sizeof s->lans[k], "%s", lan ? lan : "");
59        s->n = k + 1;
60    }
61    return 0;
62}
63
64/* An IPv4 address's first three octets (std's strict parser: four decimal octets, no leading zeros). */
65static int subnet24(const char *h, unsigned char o[3]) {
66    unsigned v[4];
67    const char *p = h;
68    for (int i = 0; i < 4; i++) {
69        const char *s = p;
70        unsigned x = 0;
71        while (*p >= '0' && *p <= '9' && p - s < 3) { x = x * 10 + (unsigned)(*p - '0'); p++; }
72        if (p == s || x > 255 || (p - s > 1 && *s == '0')) return 0;
73        v[i] = x;
74        if (i < 3) { if (*p != '.') return 0; p++; }
75    }
76    if (*p) return 0;
77    for (int i = 0; i < 3; i++) o[i] = (unsigned char)v[i];
78    return 1;
79}
80
81void mesh_infer_svc_addr(const mesh_infer_svc *s, uint32_t from, uint32_t to, uint32_t param, char out[300]) {
82    uint32_t port = (uint32_t)s->bases[to] + param;
83    if (from == to) { snprintf(out, 300, "127.0.0.1:%u", port); return; }
84    unsigned char a[3], b[3];
85    int same = subnet24(s->hosts[from], a) && subnet24(s->hosts[to], b) && memcmp(a, b, 3) == 0;
86    const char *host = same || !s->lans[to][0] ? s->hosts[to] : s->lans[to];
87    snprintf(out, 300, "%s:%u", host, port);
88}