==> 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}