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 }