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 }