udphole

Basic UDP wormhole proxy
git clone git://git.finwo.net/app/udphole
Log | Files | Refs | README | LICENSE

resp.c (9788B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 #include <stdio.h>
      4 #include <unistd.h>
      5 #include <errno.h>
      6 
      7 #include "rxi/log.h"
      8 #include "infrastructure/resp.h"
      9 
     10 #define MAX_BULK_LEN    (256 * 1024)
     11 #define LINE_BUF        4096
     12 
     13 static void resp_free_internal(resp_object *o);
     14 
     15 static int resp_read_byte(int fd) {
     16   unsigned char c;
     17   ssize_t n = read(fd, &c, 1);
     18   if (n != 1) {
     19     if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
     20       return -2;
     21     return -1;
     22   }
     23   return (int)c;
     24 }
     25 
     26 static int resp_read_line(int fd, char *buf, size_t buf_size) {
     27   size_t i = 0;
     28   int prev = -1;
     29   while (i + 1 < buf_size) {
     30     int b = resp_read_byte(fd);
     31     if (b < 0) return -1;
     32     if (prev == '\r' && b == '\n') {
     33       buf[i - 1] = '\0';
     34       return 0;
     35     }
     36     prev = b;
     37     buf[i++] = (char)b;
     38   }
     39   return -1;
     40 }
     41 
     42 resp_object *resp_read(int fd) {
     43   int type_c = resp_read_byte(fd);
     44   if (type_c < 0) return NULL;
     45   if (type_c == -2) return NULL;
     46   resp_object *o = calloc(1, sizeof(resp_object));
     47   if (!o) return NULL;
     48   char line[LINE_BUF];
     49   switch ((char)type_c) {
     50     case '+':
     51       o->type = RESPT_SIMPLE;
     52       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
     53       o->u.s = strdup(line);
     54       break;
     55     case '-':
     56       o->type = RESPT_ERROR;
     57       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
     58       o->u.s = strdup(line);
     59       break;
     60     case ':': {
     61       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
     62       o->type = RESPT_INT;
     63       o->u.i = (long long)strtoll(line, NULL, 10);
     64       break;
     65     }
     66     case '$': {
     67       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
     68       long len = strtol(line, NULL, 10);
     69       if (len < 0 || len > (long)MAX_BULK_LEN) { free(o); return NULL; }
     70       o->type = RESPT_BULK;
     71       if (len == 0) {
     72         o->u.s = strdup("");
     73         if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o->u.s); free(o); return NULL; }
     74       } else {
     75         o->u.s = malloc((size_t)len + 1);
     76         if (!o->u.s) { free(o); return NULL; }
     77         if (read(fd, o->u.s, (size_t)len) != (ssize_t)len) { free(o->u.s); free(o); return NULL; }
     78         o->u.s[len] = '\0';
     79         if (resp_read_byte(fd) != '\r' || resp_read_byte(fd) != '\n') { free(o->u.s); free(o); return NULL; }
     80       }
     81       break;
     82     }
     83     case '*': {
     84       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
     85       long n = strtol(line, NULL, 10);
     86       if (n < 0 || n > 65536) { free(o); return NULL; }
     87       o->type = RESPT_ARRAY;
     88       o->u.arr.n = (size_t)n;
     89       o->u.arr.elem = n ? calloc((size_t)n, sizeof(resp_object)) : NULL;
     90       if (n && !o->u.arr.elem) { free(o); return NULL; }
     91       for (size_t i = 0; i < (size_t)n; i++) {
     92         resp_object *sub = resp_read(fd);
     93         if (!sub) {
     94           for (size_t j = 0; j < i; j++) resp_free_internal(&o->u.arr.elem[j]);
     95           free(o->u.arr.elem);
     96           free(o);
     97           return NULL;
     98         }
     99         o->u.arr.elem[i] = *sub;
    100         free(sub);
    101       }
    102       break;
    103     }
    104     default:
    105       free(o);
    106       return NULL;
    107   }
    108   return o;
    109 }
    110 
    111 static void resp_free_internal(resp_object *o) {
    112   if (!o) return;
    113   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    114     free(o->u.s);
    115   } else if (o->type == RESPT_ARRAY) {
    116     for (size_t i = 0; i < o->u.arr.n; i++)
    117       resp_free_internal(&o->u.arr.elem[i]);
    118     free(o->u.arr.elem);
    119   }
    120 }
    121 
    122 void resp_free(resp_object *o) {
    123   resp_free_internal(o);
    124   free(o);
    125 }
    126 
    127 resp_object *resp_deep_copy(const resp_object *o) {
    128   if (!o) return NULL;
    129   resp_object *c = (resp_object *)calloc(1, sizeof(resp_object));
    130   if (!c) return NULL;
    131   c->type = o->type;
    132   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    133     c->u.s = o->u.s ? strdup(o->u.s) : NULL;
    134     if (o->u.s && !c->u.s) { free(c); return NULL; }
    135     return c;
    136   }
    137   if (o->type == RESPT_INT) {
    138     c->u.i = o->u.i;
    139     return c;
    140   }
    141   if (o->type == RESPT_ARRAY) {
    142     c->u.arr.n = o->u.arr.n;
    143     c->u.arr.elem = o->u.arr.n ? (resp_object *)calloc(o->u.arr.n, sizeof(resp_object)) : NULL;
    144     if (o->u.arr.n && !c->u.arr.elem) { free(c); return NULL; }
    145     for (size_t i = 0; i < o->u.arr.n; i++) {
    146       resp_object *sub = resp_deep_copy(&o->u.arr.elem[i]);
    147       if (!sub) {
    148         for (size_t j = 0; j < i; j++) resp_free_internal(&c->u.arr.elem[j]);
    149         free(c->u.arr.elem);
    150         free(c);
    151         return NULL;
    152       }
    153       c->u.arr.elem[i] = *sub;
    154       free(sub);
    155     }
    156     return c;
    157   }
    158   free(c);
    159   return NULL;
    160 }
    161 
    162 resp_object *resp_map_get(const resp_object *o, const char *key) {
    163   if (!o || !key || o->type != RESPT_ARRAY) return NULL;
    164   size_t n = o->u.arr.n;
    165   if (n & 1) return NULL;
    166   for (size_t i = 0; i < n; i += 2) {
    167     const resp_object *k = &o->u.arr.elem[i];
    168     const char *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    169     if (s && strcmp(s, key) == 0 && i + 1 < n)
    170       return (resp_object *)&o->u.arr.elem[i + 1];
    171   }
    172   return NULL;
    173 }
    174 
    175 const char *resp_map_get_string(const resp_object *o, const char *key) {
    176   resp_object *val = resp_map_get(o, key);
    177   if (!val) return NULL;
    178   if (val->type == RESPT_BULK || val->type == RESPT_SIMPLE)
    179     return val->u.s;
    180   return NULL;
    181 }
    182 
    183 void resp_map_set(resp_object *o, const char *key, resp_object *value) {
    184   if (!o || !key || o->type != RESPT_ARRAY) return;
    185   for (size_t i = 0; i + 1 < o->u.arr.n; i += 2) {
    186     const resp_object *k = &o->u.arr.elem[i];
    187     const char *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    188     if (s && strcmp(s, key) == 0 && i + 1 < o->u.arr.n) {
    189       resp_free(&o->u.arr.elem[i + 1]);
    190       o->u.arr.elem[i + 1] = *value;
    191       free(value);
    192       return;
    193     }
    194   }
    195   resp_array_append_bulk(o, key);
    196   resp_array_append_obj(o, value);
    197 }
    198 
    199 static int resp_append_object(char **buf, size_t *cap, size_t *len, const resp_object *o) {
    200   if (!o) return -1;
    201   size_t need = *len + 256;
    202   if (o->type == RESPT_BULK || o->type == RESPT_SIMPLE || o->type == RESPT_ERROR) {
    203     size_t slen = o->u.s ? strlen(o->u.s) : 0;
    204     need = *len + 32 + slen + 2;
    205   } else if (o->type == RESPT_ARRAY) {
    206     need = *len + 32;
    207     for (size_t i = 0; i < o->u.arr.n; i++)
    208       need += 64;
    209   }
    210   if (need > *cap) {
    211     size_t newcap = need + 4096;
    212     char *n = realloc(*buf, newcap);
    213     if (!n) return -1;
    214     *buf = n;
    215     *cap = newcap;
    216   }
    217   switch (o->type) {
    218     case RESPT_SIMPLE: {
    219       const char *s = o->u.s ? o->u.s : "";
    220       *len += (size_t)snprintf(*buf + *len, *cap - *len, "+%s\r\n", s);
    221       break;
    222     }
    223     case RESPT_ERROR: {
    224       const char *s = o->u.s ? o->u.s : "";
    225       *len += (size_t)snprintf(*buf + *len, *cap - *len, "-%s\r\n", s);
    226       break;
    227     }
    228     case RESPT_INT:
    229       *len += (size_t)snprintf(*buf + *len, *cap - *len, ":%lld\r\n", (long long)o->u.i);
    230       break;
    231     case RESPT_BULK: {
    232       const char *s = o->u.s ? o->u.s : "";
    233       size_t slen = strlen(s);
    234       *len += (size_t)snprintf(*buf + *len, *cap - *len, "$%zu\r\n%s\r\n", slen, s);
    235       break;
    236     }
    237     case RESPT_ARRAY: {
    238       size_t n = o->u.arr.n;
    239       *len += (size_t)snprintf(*buf + *len, *cap - *len, "*%zu\r\n", n);
    240       for (size_t i = 0; i < n; i++) {
    241         if (resp_append_object(buf, cap, len, &o->u.arr.elem[i]) != 0)
    242           return -1;
    243       }
    244       break;
    245     }
    246     default:
    247       return -1;
    248   }
    249   return 0;
    250 }
    251 
    252 int resp_encode_array(int argc, const resp_object *const *argv, char **out_buf, size_t *out_len) {
    253   size_t cap = 64;
    254   size_t len = 0;
    255   char *buf = malloc(cap);
    256   if (!buf) return -1;
    257   len += (size_t)snprintf(buf + len, cap - len, "*%d\r\n", argc);
    258   if (len >= cap) { free(buf); return -1; }
    259   for (int i = 0; i < argc; i++) {
    260     if (resp_append_object(&buf, &cap, &len, argv[i]) != 0) {
    261       free(buf);
    262       return -1;
    263     }
    264   }
    265   *out_buf = buf;
    266   *out_len = len;
    267   return 0;
    268 }
    269 
    270 int resp_serialize(const resp_object *o, char **out_buf, size_t *out_len) {
    271   size_t cap = 64;
    272   size_t len = 0;
    273   char *buf = malloc(cap);
    274   if (!buf) return -1;
    275   if (resp_append_object(&buf, &cap, &len, o) != 0) {
    276     free(buf);
    277     return -1;
    278   }
    279   *out_buf = buf;
    280   *out_len = len;
    281   return 0;
    282 }
    283 
    284 resp_object *resp_array_init(void) {
    285   resp_object *o = calloc(1, sizeof(resp_object));
    286   if (!o) return NULL;
    287   o->type = RESPT_ARRAY;
    288   o->u.arr.n = 0;
    289   o->u.arr.elem = NULL;
    290   return o;
    291 }
    292 
    293 int resp_array_append_obj(resp_object *destination, resp_object *value) {
    294   if (!destination || destination->type != RESPT_ARRAY || !value) return -1;
    295   size_t n = destination->u.arr.n;
    296   resp_object *new_elem = realloc(destination->u.arr.elem, (n + 1) * sizeof(resp_object));
    297   if (!new_elem) return -1;
    298   destination->u.arr.elem = new_elem;
    299   destination->u.arr.elem[n] = *value;
    300   destination->u.arr.n++;
    301   free(value);
    302   return 0;
    303 }
    304 
    305 int resp_array_append_simple(resp_object *destination, const char *str) {
    306   resp_object *o = calloc(1, sizeof(resp_object));
    307   if (!o) return -1;
    308   o->type = RESPT_SIMPLE;
    309   o->u.s = strdup(str ? str : "");
    310   if (!o->u.s) { free(o); return -1; }
    311   if (resp_array_append_obj(destination, o) != 0) { free(o->u.s); free(o); return -1; }
    312   return 0;
    313 }
    314 
    315 int resp_array_append_bulk(resp_object *destination, const char *str) {
    316   resp_object *o = calloc(1, sizeof(resp_object));
    317   if (!o) return -1;
    318   o->type = RESPT_BULK;
    319   o->u.s = strdup(str ? str : "");
    320   if (!o->u.s) { free(o); return -1; }
    321   if (resp_array_append_obj(destination, o) != 0) { free(o->u.s); free(o); return -1; }
    322   return 0;
    323 }
    324 
    325 int resp_array_append_int(resp_object *destination, long long i) {
    326   resp_object *o = malloc(sizeof(resp_object));
    327   if (!o) return -1;
    328   o->type = RESPT_INT;
    329   o->u.i = i;
    330   return resp_array_append_obj(destination, o);
    331 }