udphole

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

resp.c (13157B)


      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 "common/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_from_buf(const char **buf, size_t *len) {
     16   if (*len < 1) return -1;
     17   unsigned char c = (unsigned char)(*buf)[0];
     18   *buf += 1;
     19   *len -= 1;
     20   return (int)c;
     21 }
     22 
     23 static int resp_read_line_from_buf(const char **buf, size_t *len, char *out, size_t out_size) {
     24   size_t i = 0;
     25   int prev = -1;
     26   while (i + 1 < out_size) {
     27     if (*len < 1) return -1;
     28     int b = (int)(unsigned char)(*buf)[0];
     29     *buf += 1;
     30     *len -= 1;
     31     if (prev == '\r' && b == '\n') {
     32       out[i - 1] = '\0';
     33       return 0;
     34     }
     35     prev = b;
     36     out[i++] = (char)b;
     37   }
     38   return -1;
     39 }
     40 
     41 resp_object *resp_read_buf(const char *buf, size_t len) {
     42   const char *p = buf;
     43   size_t remaining = len;
     44 
     45   int type_c = resp_read_byte_from_buf(&p, &remaining);
     46   if (type_c < 0) return NULL;
     47   if (type_c == -2) return NULL;
     48   resp_object *o = calloc(1, sizeof(resp_object));
     49   if (!o) return NULL;
     50   char line[LINE_BUF];
     51   switch ((char)type_c) {
     52     case '+':
     53       o->type = RESPT_SIMPLE;
     54       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o); return NULL; }
     55       o->u.s = strdup(line);
     56       break;
     57     case '-':
     58       o->type = RESPT_ERROR;
     59       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o); return NULL; }
     60       o->u.s = strdup(line);
     61       break;
     62     case ':': {
     63       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o); return NULL; }
     64       o->type = RESPT_INT;
     65       o->u.i = (long long)strtoll(line, NULL, 10);
     66       break;
     67     }
     68     case '$': {
     69       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o); return NULL; }
     70       long blen = strtol(line, NULL, 10);
     71       if (blen < 0 || blen > (long)MAX_BULK_LEN) { free(o); return NULL; }
     72       o->type = RESPT_BULK;
     73       if (blen == 0) {
     74         o->u.s = strdup("");
     75         if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o->u.s); free(o); return NULL; }
     76       } else {
     77         if ((size_t)blen > remaining) { free(o); return NULL; }
     78         o->u.s = malloc((size_t)blen + 1);
     79         if (!o->u.s) { free(o); return NULL; }
     80         memcpy(o->u.s, p, (size_t)blen);
     81         p += blen;
     82         remaining -= (size_t)blen;
     83         o->u.s[blen] = '\0';
     84         if (remaining < 2) { free(o->u.s); free(o); return NULL; }
     85         if (p[0] != '\r' || p[1] != '\n') { free(o->u.s); free(o); return NULL; }
     86         p += 2;
     87         remaining -= 2;
     88       }
     89       break;
     90     }
     91     case '*': {
     92       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) { free(o); return NULL; }
     93       long n = strtol(line, NULL, 10);
     94       if (n < 0 || n > 65536) { free(o); return NULL; }
     95       o->type = RESPT_ARRAY;
     96       o->u.arr.n = (size_t)n;
     97       o->u.arr.elem = n ? calloc((size_t)n, sizeof(resp_object)) : NULL;
     98       if (n && !o->u.arr.elem) { free(o); return NULL; }
     99       for (size_t i = 0; i < (size_t)n; i++) {
    100         resp_object *sub = resp_read_buf(p, remaining);
    101         if (!sub) {
    102           for (size_t j = 0; j < i; j++) resp_free_internal(&o->u.arr.elem[j]);
    103           free(o->u.arr.elem);
    104           free(o);
    105           return NULL;
    106         }
    107         p += remaining - (sub ? remaining : 0);
    108         remaining = 0;
    109         o->u.arr.elem[i] = *sub;
    110         free(sub);
    111       }
    112       break;
    113     }
    114     default:
    115       free(o);
    116       return NULL;
    117   }
    118   return o;
    119 }
    120 
    121 static int resp_read_byte(int fd) {
    122   unsigned char c;
    123   ssize_t n = read(fd, &c, 1);
    124   if (n != 1) {
    125     if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
    126       return -2;
    127     return -1;
    128   }
    129   return (int)c;
    130 }
    131 
    132 static int resp_read_line(int fd, char *buf, size_t buf_size) {
    133   size_t i = 0;
    134   int prev = -1;
    135   while (i + 1 < buf_size) {
    136     int b = resp_read_byte(fd);
    137     if (b < 0) return -1;
    138     if (prev == '\r' && b == '\n') {
    139       buf[i - 1] = '\0';
    140       return 0;
    141     }
    142     prev = b;
    143     buf[i++] = (char)b;
    144   }
    145   return -1;
    146 }
    147 
    148 resp_object *resp_read(int fd) {
    149   int type_c = resp_read_byte(fd);
    150   if (type_c < 0) return NULL;
    151   if (type_c == -2) return NULL;
    152   resp_object *o = calloc(1, sizeof(resp_object));
    153   if (!o) return NULL;
    154   char line[LINE_BUF];
    155   switch ((char)type_c) {
    156     case '+':
    157       o->type = RESPT_SIMPLE;
    158       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
    159       o->u.s = strdup(line);
    160       break;
    161     case '-':
    162       o->type = RESPT_ERROR;
    163       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
    164       o->u.s = strdup(line);
    165       break;
    166     case ':': {
    167       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
    168       o->type = RESPT_INT;
    169       o->u.i = (long long)strtoll(line, NULL, 10);
    170       break;
    171     }
    172     case '$': {
    173       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
    174       long len = strtol(line, NULL, 10);
    175       if (len < 0 || len > (long)MAX_BULK_LEN) { free(o); return NULL; }
    176       o->type = RESPT_BULK;
    177       if (len == 0) {
    178         o->u.s = strdup("");
    179         if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o->u.s); free(o); return NULL; }
    180       } else {
    181         o->u.s = malloc((size_t)len + 1);
    182         if (!o->u.s) { free(o); return NULL; }
    183         if (read(fd, o->u.s, (size_t)len) != (ssize_t)len) { free(o->u.s); free(o); return NULL; }
    184         o->u.s[len] = '\0';
    185         if (resp_read_byte(fd) != '\r' || resp_read_byte(fd) != '\n') { free(o->u.s); free(o); return NULL; }
    186       }
    187       break;
    188     }
    189     case '*': {
    190       if (resp_read_line(fd, line, sizeof(line)) != 0) { free(o); return NULL; }
    191       long n = strtol(line, NULL, 10);
    192       if (n < 0 || n > 65536) { free(o); return NULL; }
    193       o->type = RESPT_ARRAY;
    194       o->u.arr.n = (size_t)n;
    195       o->u.arr.elem = n ? calloc((size_t)n, sizeof(resp_object)) : NULL;
    196       if (n && !o->u.arr.elem) { free(o); return NULL; }
    197       for (size_t i = 0; i < (size_t)n; i++) {
    198         resp_object *sub = resp_read(fd);
    199         if (!sub) {
    200           for (size_t j = 0; j < i; j++) resp_free_internal(&o->u.arr.elem[j]);
    201           free(o->u.arr.elem);
    202           free(o);
    203           return NULL;
    204         }
    205         o->u.arr.elem[i] = *sub;
    206         free(sub);
    207       }
    208       break;
    209     }
    210     default:
    211       free(o);
    212       return NULL;
    213   }
    214   return o;
    215 }
    216 
    217 static void resp_free_internal(resp_object *o) {
    218   if (!o) return;
    219   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    220     free(o->u.s);
    221   } else if (o->type == RESPT_ARRAY) {
    222     for (size_t i = 0; i < o->u.arr.n; i++)
    223       resp_free_internal(&o->u.arr.elem[i]);
    224     free(o->u.arr.elem);
    225   }
    226 }
    227 
    228 void resp_free(resp_object *o) {
    229   resp_free_internal(o);
    230   free(o);
    231 }
    232 
    233 resp_object *resp_deep_copy(const resp_object *o) {
    234   if (!o) return NULL;
    235   resp_object *c = (resp_object *)calloc(1, sizeof(resp_object));
    236   if (!c) return NULL;
    237   c->type = o->type;
    238   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    239     c->u.s = o->u.s ? strdup(o->u.s) : NULL;
    240     if (o->u.s && !c->u.s) { free(c); return NULL; }
    241     return c;
    242   }
    243   if (o->type == RESPT_INT) {
    244     c->u.i = o->u.i;
    245     return c;
    246   }
    247   if (o->type == RESPT_ARRAY) {
    248     c->u.arr.n = o->u.arr.n;
    249     c->u.arr.elem = o->u.arr.n ? (resp_object *)calloc(o->u.arr.n, sizeof(resp_object)) : NULL;
    250     if (o->u.arr.n && !c->u.arr.elem) { free(c); return NULL; }
    251     for (size_t i = 0; i < o->u.arr.n; i++) {
    252       resp_object *sub = resp_deep_copy(&o->u.arr.elem[i]);
    253       if (!sub) {
    254         for (size_t j = 0; j < i; j++) resp_free_internal(&c->u.arr.elem[j]);
    255         free(c->u.arr.elem);
    256         free(c);
    257         return NULL;
    258       }
    259       c->u.arr.elem[i] = *sub;
    260       free(sub);
    261     }
    262     return c;
    263   }
    264   free(c);
    265   return NULL;
    266 }
    267 
    268 resp_object *resp_map_get(const resp_object *o, const char *key) {
    269   if (!o || !key || o->type != RESPT_ARRAY) return NULL;
    270   size_t n = o->u.arr.n;
    271   if (n & 1) return NULL;
    272   for (size_t i = 0; i < n; i += 2) {
    273     const resp_object *k = &o->u.arr.elem[i];
    274     const char *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    275     if (s && strcmp(s, key) == 0 && i + 1 < n)
    276       return (resp_object *)&o->u.arr.elem[i + 1];
    277   }
    278   return NULL;
    279 }
    280 
    281 const char *resp_map_get_string(const resp_object *o, const char *key) {
    282   resp_object *val = resp_map_get(o, key);
    283   if (!val) return NULL;
    284   if (val->type == RESPT_BULK || val->type == RESPT_SIMPLE)
    285     return val->u.s;
    286   return NULL;
    287 }
    288 
    289 void resp_map_set(resp_object *o, const char *key, resp_object *value) {
    290   if (!o || !key || o->type != RESPT_ARRAY) return;
    291   for (size_t i = 0; i + 1 < o->u.arr.n; i += 2) {
    292     const resp_object *k = &o->u.arr.elem[i];
    293     const char *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    294     if (s && strcmp(s, key) == 0 && i + 1 < o->u.arr.n) {
    295       resp_free(&o->u.arr.elem[i + 1]);
    296       o->u.arr.elem[i + 1] = *value;
    297       free(value);
    298       return;
    299     }
    300   }
    301   resp_array_append_bulk(o, key);
    302   resp_array_append_obj(o, value);
    303 }
    304 
    305 static int resp_append_object(char **buf, size_t *cap, size_t *len, const resp_object *o) {
    306   if (!o) return -1;
    307   size_t need = *len + 256;
    308   if (o->type == RESPT_BULK || o->type == RESPT_SIMPLE || o->type == RESPT_ERROR) {
    309     size_t slen = o->u.s ? strlen(o->u.s) : 0;
    310     need = *len + 32 + slen + 2;
    311   } else if (o->type == RESPT_ARRAY) {
    312     need = *len + 32;
    313     for (size_t i = 0; i < o->u.arr.n; i++)
    314       need += 64;
    315   }
    316   if (need > *cap) {
    317     size_t newcap = need + 4096;
    318     char *n = realloc(*buf, newcap);
    319     if (!n) return -1;
    320     *buf = n;
    321     *cap = newcap;
    322   }
    323   switch (o->type) {
    324     case RESPT_SIMPLE: {
    325       const char *s = o->u.s ? o->u.s : "";
    326       *len += (size_t)snprintf(*buf + *len, *cap - *len, "+%s\r\n", s);
    327       break;
    328     }
    329     case RESPT_ERROR: {
    330       const char *s = o->u.s ? o->u.s : "";
    331       *len += (size_t)snprintf(*buf + *len, *cap - *len, "-%s\r\n", s);
    332       break;
    333     }
    334     case RESPT_INT:
    335       *len += (size_t)snprintf(*buf + *len, *cap - *len, ":%lld\r\n", (long long)o->u.i);
    336       break;
    337     case RESPT_BULK: {
    338       const char *s = o->u.s ? o->u.s : "";
    339       size_t slen = strlen(s);
    340       *len += (size_t)snprintf(*buf + *len, *cap - *len, "$%zu\r\n%s\r\n", slen, s);
    341       break;
    342     }
    343     case RESPT_ARRAY: {
    344       size_t n = o->u.arr.n;
    345       *len += (size_t)snprintf(*buf + *len, *cap - *len, "*%zu\r\n", n);
    346       for (size_t i = 0; i < n; i++) {
    347         if (resp_append_object(buf, cap, len, &o->u.arr.elem[i]) != 0)
    348           return -1;
    349       }
    350       break;
    351     }
    352     default:
    353       return -1;
    354   }
    355   return 0;
    356 }
    357 
    358 int resp_encode_array(int argc, const resp_object *const *argv, char **out_buf, size_t *out_len) {
    359   size_t cap = 64;
    360   size_t len = 0;
    361   char *buf = malloc(cap);
    362   if (!buf) return -1;
    363   len += (size_t)snprintf(buf + len, cap - len, "*%d\r\n", argc);
    364   if (len >= cap) { free(buf); return -1; }
    365   for (int i = 0; i < argc; i++) {
    366     if (resp_append_object(&buf, &cap, &len, argv[i]) != 0) {
    367       free(buf);
    368       return -1;
    369     }
    370   }
    371   *out_buf = buf;
    372   *out_len = len;
    373   return 0;
    374 }
    375 
    376 int resp_serialize(const resp_object *o, char **out_buf, size_t *out_len) {
    377   size_t cap = 64;
    378   size_t len = 0;
    379   char *buf = malloc(cap);
    380   if (!buf) return -1;
    381   if (resp_append_object(&buf, &cap, &len, o) != 0) {
    382     free(buf);
    383     return -1;
    384   }
    385   *out_buf = buf;
    386   *out_len = len;
    387   return 0;
    388 }
    389 
    390 resp_object *resp_array_init(void) {
    391   resp_object *o = calloc(1, sizeof(resp_object));
    392   if (!o) return NULL;
    393   o->type = RESPT_ARRAY;
    394   o->u.arr.n = 0;
    395   o->u.arr.elem = NULL;
    396   return o;
    397 }
    398 
    399 int resp_array_append_obj(resp_object *destination, resp_object *value) {
    400   if (!destination || destination->type != RESPT_ARRAY || !value) return -1;
    401   size_t n = destination->u.arr.n;
    402   resp_object *new_elem = realloc(destination->u.arr.elem, (n + 1) * sizeof(resp_object));
    403   if (!new_elem) return -1;
    404   destination->u.arr.elem = new_elem;
    405   destination->u.arr.elem[n] = *value;
    406   destination->u.arr.n++;
    407   free(value);
    408   return 0;
    409 }
    410 
    411 int resp_array_append_simple(resp_object *destination, const char *str) {
    412   resp_object *o = calloc(1, sizeof(resp_object));
    413   if (!o) return -1;
    414   o->type = RESPT_SIMPLE;
    415   o->u.s = strdup(str ? str : "");
    416   if (!o->u.s) { free(o); return -1; }
    417   if (resp_array_append_obj(destination, o) != 0) { free(o->u.s); free(o); return -1; }
    418   return 0;
    419 }
    420 
    421 int resp_array_append_bulk(resp_object *destination, const char *str) {
    422   resp_object *o = calloc(1, sizeof(resp_object));
    423   if (!o) return -1;
    424   o->type = RESPT_BULK;
    425   o->u.s = strdup(str ? str : "");
    426   if (!o->u.s) { free(o); return -1; }
    427   if (resp_array_append_obj(destination, o) != 0) { free(o->u.s); free(o); return -1; }
    428   return 0;
    429 }
    430 
    431 int resp_array_append_int(resp_object *destination, long long i) {
    432   resp_object *o = malloc(sizeof(resp_object));
    433   if (!o) return -1;
    434   o->type = RESPT_INT;
    435   o->u.i = i;
    436   return resp_array_append_obj(destination, o);
    437 }