udphole

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

resp.c (15369B)


      1 #include "common/resp.h"
      2 
      3 #include <errno.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 
      9 #include "rxi/log.h"
     10 
     11 #define MAX_BULK_LEN (256 * 1024)
     12 #define LINE_BUF     4096
     13 
     14 static void resp_free_internal(resp_object *o);
     15 
     16 static int resp_read_byte_from_buf(const char **buf, size_t *len) {
     17   if (*len < 1) return -1;
     18   unsigned char c = (unsigned char)(*buf)[0];
     19   *buf += 1;
     20   *len -= 1;
     21   return (int)c;
     22 }
     23 
     24 static int resp_read_line_from_buf(const char **buf, size_t *len, char *out, size_t out_size) {
     25   size_t i    = 0;
     26   int    prev = -1;
     27   while (i + 1 < out_size) {
     28     if (*len < 1) return -1;
     29     int b = (int)(unsigned char)(*buf)[0];
     30     *buf += 1;
     31     *len -= 1;
     32     if (prev == '\r' && b == '\n') {
     33       out[i - 1] = '\0';
     34       return 0;
     35     }
     36     prev     = b;
     37     out[i++] = (char)b;
     38   }
     39   return -1;
     40 }
     41 
     42 int resp_read_buf(const char *buf, size_t len, resp_object **out_obj) {
     43   if (!out_obj) return -1;
     44 
     45   const char *start = buf;
     46   const char *p = buf;
     47   size_t remaining = len;
     48 
     49   int type_c = resp_read_byte_from_buf(&p, &remaining);
     50   if (type_c < 0) return 0;  // no data yet
     51   if (type_c == -2) return 0;  // no data yet
     52 
     53   resp_object *o = calloc(1, sizeof(resp_object));
     54   if (!o) return -1;
     55 
     56   char line[LINE_BUF];
     57   switch ((char)type_c) {
     58     case '+':
     59       o->type = RESPT_SIMPLE;
     60       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
     61         free(o);
     62         return -1;
     63       }
     64       o->u.s = strdup(line);
     65       break;
     66     case '-':
     67       o->type = RESPT_ERROR;
     68       if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
     69         free(o);
     70         return -1;
     71       }
     72       o->u.s = strdup(line);
     73       break;
     74     case ':':
     75       {
     76         if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
     77           free(o);
     78           return -1;
     79         }
     80         o->type = RESPT_INT;
     81         o->u.i  = (long long)strtoll(line, NULL, 10);
     82         break;
     83       }
     84     case '$':
     85       {
     86         if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
     87           free(o);
     88           return -1;
     89         }
     90         long blen = strtol(line, NULL, 10);
     91         if (blen < 0 || blen > (long)MAX_BULK_LEN) {
     92           free(o);
     93           return -1;
     94         }
     95         o->type = RESPT_BULK;
     96         if (blen == 0) {
     97           o->u.s = strdup("");
     98           if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
     99             free(o->u.s);
    100             free(o);
    101             return -1;
    102           }
    103         } else {
    104           if ((size_t)blen > remaining) {
    105             free(o);
    106             return -1;
    107           }
    108           o->u.s = malloc((size_t)blen + 1);
    109           if (!o->u.s) {
    110             free(o);
    111             return -1;
    112           }
    113           memcpy(o->u.s, p, (size_t)blen);
    114           p += blen;
    115           remaining -= (size_t)blen;
    116           o->u.s[blen] = '\0';
    117           if (remaining < 2) {
    118             free(o->u.s);
    119             free(o);
    120             return -1;
    121           }
    122           if (p[0] != '\r' || p[1] != '\n') {
    123             free(o->u.s);
    124             free(o);
    125             return -1;
    126           }
    127           p += 2;
    128           remaining -= 2;
    129         }
    130         break;
    131       }
    132     case '*':
    133       {
    134         if (resp_read_line_from_buf(&p, &remaining, line, sizeof(line)) != 0) {
    135           free(o);
    136           return -1;
    137         }
    138         long n = strtol(line, NULL, 10);
    139         if (n < 0 || n > 65536) {
    140           free(o);
    141           return -1;
    142         }
    143         o->type       = RESPT_ARRAY;
    144         o->u.arr.n    = (size_t)n;
    145         o->u.arr.elem = n ? calloc((size_t)n, sizeof(resp_object)) : NULL;
    146         if (n && !o->u.arr.elem) {
    147           free(o);
    148           return -1;
    149         }
    150         for (size_t i = 0; i < (size_t)n; i++) {
    151           resp_object *sub = NULL;
    152           int consumed = resp_read_buf(p, remaining, &sub);
    153           if (consumed <= 0) {
    154             for (size_t j = 0; j < i; j++) resp_free_internal(&o->u.arr.elem[j]);
    155             free(o->u.arr.elem);
    156             free(o);
    157             return -1;
    158           }
    159           p += consumed;
    160           remaining -= (size_t)consumed;
    161           o->u.arr.elem[i] = *sub;
    162           free(sub);
    163         }
    164         break;
    165       }
    166     default:
    167       free(o);
    168       return -1;
    169   }
    170 
    171   *out_obj = o;
    172   return (int)(p - start);
    173 }
    174 
    175 static int resp_read_byte(int fd) {
    176   unsigned char c;
    177   ssize_t       n = read(fd, &c, 1);
    178   if (n != 1) {
    179     if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return -2;
    180     return -1;
    181   }
    182   return (int)c;
    183 }
    184 
    185 static int resp_read_line(int fd, char *buf, size_t buf_size) {
    186   size_t i    = 0;
    187   int    prev = -1;
    188   while (i + 1 < buf_size) {
    189     int b = resp_read_byte(fd);
    190     if (b < 0) return -1;
    191     if (prev == '\r' && b == '\n') {
    192       buf[i - 1] = '\0';
    193       return 0;
    194     }
    195     prev     = b;
    196     buf[i++] = (char)b;
    197   }
    198   return -1;
    199 }
    200 
    201 resp_object *resp_read(int fd) {
    202   int type_c = resp_read_byte(fd);
    203   if (type_c < 0) return NULL;
    204   if (type_c == -2) return NULL;
    205   resp_object *o = calloc(1, sizeof(resp_object));
    206   if (!o) return NULL;
    207   char line[LINE_BUF];
    208   switch ((char)type_c) {
    209     case '+':
    210       o->type = RESPT_SIMPLE;
    211       if (resp_read_line(fd, line, sizeof(line)) != 0) {
    212         free(o);
    213         return NULL;
    214       }
    215       o->u.s = strdup(line);
    216       break;
    217     case '-':
    218       o->type = RESPT_ERROR;
    219       if (resp_read_line(fd, line, sizeof(line)) != 0) {
    220         free(o);
    221         return NULL;
    222       }
    223       o->u.s = strdup(line);
    224       break;
    225     case ':':
    226       {
    227         if (resp_read_line(fd, line, sizeof(line)) != 0) {
    228           free(o);
    229           return NULL;
    230         }
    231         o->type = RESPT_INT;
    232         o->u.i  = (long long)strtoll(line, NULL, 10);
    233         break;
    234       }
    235     case '$':
    236       {
    237         if (resp_read_line(fd, line, sizeof(line)) != 0) {
    238           free(o);
    239           return NULL;
    240         }
    241         long len = strtol(line, NULL, 10);
    242         if (len < 0 || len > (long)MAX_BULK_LEN) {
    243           free(o);
    244           return NULL;
    245         }
    246         o->type = RESPT_BULK;
    247         if (len == 0) {
    248           o->u.s = strdup("");
    249           if (resp_read_line(fd, line, sizeof(line)) != 0) {
    250             free(o->u.s);
    251             free(o);
    252             return NULL;
    253           }
    254         } else {
    255           o->u.s = malloc((size_t)len + 1);
    256           if (!o->u.s) {
    257             free(o);
    258             return NULL;
    259           }
    260           if (read(fd, o->u.s, (size_t)len) != (ssize_t)len) {
    261             free(o->u.s);
    262             free(o);
    263             return NULL;
    264           }
    265           o->u.s[len] = '\0';
    266           if (resp_read_byte(fd) != '\r' || resp_read_byte(fd) != '\n') {
    267             free(o->u.s);
    268             free(o);
    269             return NULL;
    270           }
    271         }
    272         break;
    273       }
    274     case '*':
    275       {
    276         if (resp_read_line(fd, line, sizeof(line)) != 0) {
    277           free(o);
    278           return NULL;
    279         }
    280         long n = strtol(line, NULL, 10);
    281         if (n < 0 || n > 65536) {
    282           free(o);
    283           return NULL;
    284         }
    285         o->type       = RESPT_ARRAY;
    286         o->u.arr.n    = (size_t)n;
    287         o->u.arr.elem = n ? calloc((size_t)n, sizeof(resp_object)) : NULL;
    288         if (n && !o->u.arr.elem) {
    289           free(o);
    290           return NULL;
    291         }
    292         for (size_t i = 0; i < (size_t)n; i++) {
    293           resp_object *sub = resp_read(fd);
    294           if (!sub) {
    295             for (size_t j = 0; j < i; j++) resp_free_internal(&o->u.arr.elem[j]);
    296             free(o->u.arr.elem);
    297             free(o);
    298             return NULL;
    299           }
    300           o->u.arr.elem[i] = *sub;
    301           free(sub);
    302         }
    303         break;
    304       }
    305     default:
    306       free(o);
    307       return NULL;
    308   }
    309   return o;
    310 }
    311 
    312 static void resp_free_internal(resp_object *o) {
    313   if (!o) return;
    314   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    315     free(o->u.s);
    316   } else if (o->type == RESPT_ARRAY) {
    317     for (size_t i = 0; i < o->u.arr.n; i++) resp_free_internal(&o->u.arr.elem[i]);
    318     free(o->u.arr.elem);
    319   }
    320 }
    321 
    322 void resp_free(resp_object *o) {
    323   resp_free_internal(o);
    324   free(o);
    325 }
    326 
    327 resp_object *resp_deep_copy(const resp_object *o) {
    328   if (!o) return NULL;
    329   resp_object *c = (resp_object *)calloc(1, sizeof(resp_object));
    330   if (!c) return NULL;
    331   c->type = o->type;
    332   if (o->type == RESPT_SIMPLE || o->type == RESPT_ERROR || o->type == RESPT_BULK) {
    333     c->u.s = o->u.s ? strdup(o->u.s) : NULL;
    334     if (o->u.s && !c->u.s) {
    335       free(c);
    336       return NULL;
    337     }
    338     return c;
    339   }
    340   if (o->type == RESPT_INT) {
    341     c->u.i = o->u.i;
    342     return c;
    343   }
    344   if (o->type == RESPT_ARRAY) {
    345     c->u.arr.n    = o->u.arr.n;
    346     c->u.arr.elem = o->u.arr.n ? (resp_object *)calloc(o->u.arr.n, sizeof(resp_object)) : NULL;
    347     if (o->u.arr.n && !c->u.arr.elem) {
    348       free(c);
    349       return NULL;
    350     }
    351     for (size_t i = 0; i < o->u.arr.n; i++) {
    352       resp_object *sub = resp_deep_copy(&o->u.arr.elem[i]);
    353       if (!sub) {
    354         for (size_t j = 0; j < i; j++) resp_free_internal(&c->u.arr.elem[j]);
    355         free(c->u.arr.elem);
    356         free(c);
    357         return NULL;
    358       }
    359       c->u.arr.elem[i] = *sub;
    360       free(sub);
    361     }
    362     return c;
    363   }
    364   free(c);
    365   return NULL;
    366 }
    367 
    368 resp_object *resp_map_get(const resp_object *o, const char *key) {
    369   if (!o || !key || o->type != RESPT_ARRAY) return NULL;
    370   size_t n = o->u.arr.n;
    371   if (n & 1) return NULL;
    372   for (size_t i = 0; i < n; i += 2) {
    373     const resp_object *k = &o->u.arr.elem[i];
    374     const char        *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    375     if (s && strcmp(s, key) == 0 && i + 1 < n) return (resp_object *)&o->u.arr.elem[i + 1];
    376   }
    377   return NULL;
    378 }
    379 
    380 const char *resp_map_get_string(const resp_object *o, const char *key) {
    381   resp_object *val = resp_map_get(o, key);
    382   if (!val) return NULL;
    383   if (val->type == RESPT_BULK || val->type == RESPT_SIMPLE) return val->u.s;
    384   return NULL;
    385 }
    386 
    387 void resp_map_set(resp_object *o, const char *key, resp_object *value) {
    388   if (!o || !key || o->type != RESPT_ARRAY) return;
    389   for (size_t i = 0; i + 1 < o->u.arr.n; i += 2) {
    390     const resp_object *k = &o->u.arr.elem[i];
    391     const char        *s = (k->type == RESPT_BULK || k->type == RESPT_SIMPLE) ? k->u.s : NULL;
    392     if (s && strcmp(s, key) == 0 && i + 1 < o->u.arr.n) {
    393       resp_free(&o->u.arr.elem[i + 1]);
    394       o->u.arr.elem[i + 1] = *value;
    395       free(value);
    396       return;
    397     }
    398   }
    399   resp_array_append_bulk(o, key);
    400   resp_array_append_obj(o, value);
    401 }
    402 
    403 static int resp_append_object(char **buf, size_t *cap, size_t *len, const resp_object *o) {
    404   if (!o) return -1;
    405   size_t need = *len + 256;
    406   if (o->type == RESPT_BULK || o->type == RESPT_SIMPLE || o->type == RESPT_ERROR) {
    407     size_t slen = o->u.s ? strlen(o->u.s) : 0;
    408     need        = *len + 32 + slen + 2;
    409   } else if (o->type == RESPT_ARRAY) {
    410     need = *len + 32;
    411     for (size_t i = 0; i < o->u.arr.n; i++) need += 64;
    412   }
    413   if (need > *cap) {
    414     size_t newcap = need + 4096;
    415     char  *n      = realloc(*buf, newcap);
    416     if (!n) return -1;
    417     *buf = n;
    418     *cap = newcap;
    419   }
    420   switch (o->type) {
    421     case RESPT_SIMPLE:
    422       {
    423         const char *s = o->u.s ? o->u.s : "";
    424         *len += (size_t)snprintf(*buf + *len, *cap - *len, "+%s\r\n", s);
    425         break;
    426       }
    427     case RESPT_ERROR:
    428       {
    429         const char *s = o->u.s ? o->u.s : "";
    430         *len += (size_t)snprintf(*buf + *len, *cap - *len, "-%s\r\n", s);
    431         break;
    432       }
    433     case RESPT_INT:
    434       *len += (size_t)snprintf(*buf + *len, *cap - *len, ":%lld\r\n", (long long)o->u.i);
    435       break;
    436     case RESPT_BULK:
    437       {
    438         const char *s    = o->u.s ? o->u.s : "";
    439         size_t      slen = strlen(s);
    440         *len += (size_t)snprintf(*buf + *len, *cap - *len, "$%zu\r\n%s\r\n", slen, s);
    441         break;
    442       }
    443     case RESPT_ARRAY:
    444       {
    445         size_t n = o->u.arr.n;
    446         *len += (size_t)snprintf(*buf + *len, *cap - *len, "*%zu\r\n", n);
    447         for (size_t i = 0; i < n; i++) {
    448           if (resp_append_object(buf, cap, len, &o->u.arr.elem[i]) != 0) return -1;
    449         }
    450         break;
    451       }
    452     default:
    453       return -1;
    454   }
    455   return 0;
    456 }
    457 
    458 int resp_encode_array(int argc, const resp_object *const *argv, char **out_buf, size_t *out_len) {
    459   size_t cap = 64;
    460   size_t len = 0;
    461   char  *buf = malloc(cap);
    462   if (!buf) return -1;
    463   len += (size_t)snprintf(buf + len, cap - len, "*%d\r\n", argc);
    464   if (len >= cap) {
    465     free(buf);
    466     return -1;
    467   }
    468   for (int i = 0; i < argc; i++) {
    469     if (resp_append_object(&buf, &cap, &len, argv[i]) != 0) {
    470       free(buf);
    471       return -1;
    472     }
    473   }
    474   *out_buf = buf;
    475   *out_len = len;
    476   return 0;
    477 }
    478 
    479 int resp_serialize(const resp_object *o, char **out_buf, size_t *out_len) {
    480   size_t cap = 64;
    481   size_t len = 0;
    482   char  *buf = malloc(cap);
    483   if (!buf) return -1;
    484   if (resp_append_object(&buf, &cap, &len, o) != 0) {
    485     free(buf);
    486     return -1;
    487   }
    488   *out_buf = buf;
    489   *out_len = len;
    490   return 0;
    491 }
    492 
    493 resp_object *resp_array_init(void) {
    494   resp_object *o = calloc(1, sizeof(resp_object));
    495   if (!o) return NULL;
    496   o->type       = RESPT_ARRAY;
    497   o->u.arr.n    = 0;
    498   o->u.arr.elem = NULL;
    499   return o;
    500 }
    501 
    502 resp_object *resp_simple_init(const char *value) {
    503   resp_object *o = calloc(1, sizeof(resp_object));
    504   if (!o) return NULL;
    505   o->type = RESPT_SIMPLE;
    506   o->u.s  = value ? strdup(value) : NULL;
    507   return o;
    508 }
    509 
    510 int resp_array_append_obj(resp_object *destination, resp_object *value) {
    511   if (!destination || destination->type != RESPT_ARRAY || !value) return -1;
    512   size_t       n        = destination->u.arr.n;
    513   resp_object *new_elem = realloc(destination->u.arr.elem, (n + 1) * sizeof(resp_object));
    514   if (!new_elem) return -1;
    515   destination->u.arr.elem    = new_elem;
    516   destination->u.arr.elem[n] = *value;
    517   destination->u.arr.n++;
    518   free(value);
    519   return 0;
    520 }
    521 
    522 resp_object *resp_error_init(const char *value) {
    523   resp_object *o = calloc(1, sizeof(resp_object));
    524   if (!o) return NULL;
    525   o->type = RESPT_ERROR;
    526   o->u.s  = strdup(value ? value : "");
    527   if (!o->u.s) {
    528     free(o);
    529     return NULL;
    530   }
    531   return o;
    532 }
    533 
    534 int resp_array_append_simple(resp_object *destination, const char *str) {
    535   resp_object *o = calloc(1, sizeof(resp_object));
    536   if (!o) return -1;
    537   o->type = RESPT_SIMPLE;
    538   o->u.s  = strdup(str ? str : "");
    539   if (!o->u.s) {
    540     free(o);
    541     return -1;
    542   }
    543   if (resp_array_append_obj(destination, o) != 0) {
    544     free(o->u.s);
    545     free(o);
    546     return -1;
    547   }
    548   return 0;
    549 }
    550 
    551 int resp_array_append_error(resp_object *destination, const char *str) {
    552   resp_object *o = calloc(1, sizeof(resp_object));
    553   if (!o) return -1;
    554   o->type = RESPT_ERROR;
    555   o->u.s  = strdup(str ? str : "");
    556   if (!o->u.s) {
    557     free(o);
    558     return -1;
    559   }
    560   if (resp_array_append_obj(destination, o) != 0) {
    561     free(o->u.s);
    562     free(o);
    563     return -1;
    564   }
    565   return 0;
    566 }
    567 
    568 int resp_array_append_bulk(resp_object *destination, const char *str) {
    569   resp_object *o = calloc(1, sizeof(resp_object));
    570   if (!o) return -1;
    571   o->type = RESPT_BULK;
    572   o->u.s  = strdup(str ? str : "");
    573   if (!o->u.s) {
    574     free(o);
    575     return -1;
    576   }
    577   if (resp_array_append_obj(destination, o) != 0) {
    578     free(o->u.s);
    579     free(o);
    580     return -1;
    581   }
    582   return 0;
    583 }
    584 
    585 int resp_array_append_int(resp_object *destination, long long i) {
    586   resp_object *o = malloc(sizeof(resp_object));
    587   if (!o) return -1;
    588   o->type = RESPT_INT;
    589   o->u.i  = i;
    590   return resp_array_append_obj(destination, o);
    591 }