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 }