1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 
3 #include "proxy.h"
4 
5 /*
6  * !!!WARNING!!!
7  * This is an experimental interface and is not to be used in production until
8  * after this warning has been removed.
9  * The req/res mutator system is currently an experimental draft, merged to
10  * allow code experiments and further information gathering before completing
11  * the interface.
12  *
13  * it currently has bugs, unfinished features, and will not immediately
14  * release request or result buffers after a request completes.
15  */
16 
17 // space or \r\n
18 #define MIN_BUF_SPACE 2
19 
20 enum mcp_mut_type {
21     MUT_REQ = 1,
22     MUT_RES,
23 };
24 
25 enum mcp_mut_steptype {
26     mcp_mut_step_none = 0,
27     mcp_mut_step_cmdset,
28     mcp_mut_step_cmdcopy,
29     mcp_mut_step_keycopy,
30     mcp_mut_step_keyset,
31     mcp_mut_step_rescodeset,
32     mcp_mut_step_rescodecopy,
33     mcp_mut_step_reserr,
34     mcp_mut_step_flagset,
35     mcp_mut_step_flagcopy,
36     mcp_mut_step_valcopy,
37     mcp_mut_step_final, // not used.
38 };
39 
40 enum mcp_mut_step_arg {
41     mcp_mut_step_arg_none = 0,
42     mcp_mut_step_arg_request,
43     mcp_mut_step_arg_response,
44     mcp_mut_step_arg_string,
45     mcp_mut_step_arg_int,
46 };
47 
48 // START STEP STRUCTS
49 
50 // struct forward declarations for entry/step function pointers
51 struct mcp_mut_step;
52 struct mcp_mutator;
53 struct mcp_mut_run;
54 struct mcp_mut_part;
55 
56 typedef int (*mcp_mut_c)(lua_State *L, int tidx);
57 typedef int (*mcp_mut_i)(lua_State *L, int tidx, int sc, struct mcp_mutator *mut);
58 typedef int (*mcp_mut_r)(struct mcp_mut_run *run, struct mcp_mut_step *s, struct mcp_mut_part *p);
59 
60 struct mcp_mut_entry {
61     const char *s; // string name
62     mcp_mut_c c; // argument checker
63     mcp_mut_i i; // argument initializer
64     mcp_mut_r n; // runtime length totaller
65     mcp_mut_r r; // runtime assembly
66     unsigned int t; // allowed object types
67     int rc; // number of results to expect
68 };
69 
70 struct mcp_mut_string {
71     unsigned int str; // arena offset for match string.
72     unsigned int len;
73 };
74 
75 struct mcp_mut_flag {
76     uint64_t bit; // flag converted for bitmask test
77     char f;
78 };
79 
80 #define RESERR_ERROR 1
81 #define RESERR_ERROR_STR "ERROR"
82 #define RESERR_CLIENT 2
83 #define RESERR_CLIENT_STR "CLIENT_ERROR"
84 #define RESERR_SERVER 3
85 #define RESERR_SERVER_STR "SERVER_ERROR"
86 
87 struct mcp_mut_flagval {
88     struct mcp_mut_flag flag;
89     struct mcp_mut_string str;
90 };
91 
92 struct mcp_mut_step {
93     enum mcp_mut_steptype type;
94     unsigned int idx; // common: input argument position
95     enum mcp_mut_step_arg arg; // common: type of input argument
96     mcp_mut_r n; // totaller function
97     mcp_mut_r r; // data copy function
98     union {
99         struct mcp_mut_string string;
100         struct mcp_mut_flag flag;
101         struct mcp_mut_flagval flagval;
102     } c;
103 };
104 
105 // END STEP STRUCTS
106 
107 struct mcp_mutator {
108     enum mcp_mut_type type;
109     int scount;
110     unsigned int aused; // arena memory used
111     unsigned int rcount; // number of results to expect
112     char *arena; // string/data storage for steps
113     struct mcp_mut_step steps[];
114 };
115 
116 // scratch space for steps between total and execution stages.
117 struct mcp_mut_part {
118     const char *src;
119     size_t slen;
120 };
121 
122 // stack scratch variables for mutation execution
123 struct mcp_mut_run {
124     lua_State *L;
125     struct mcp_mutator *mut;
126     void *arg;
127     char *numbuf; // stack space for rendering numerics
128     char *d_pos; // current offset to the write string.
129 
130     const char *vbuf; // buffer or ptr if a value is being attached
131     size_t vlen; // length of the actual value buffer.
132 };
133 
134 #define mut_step_c(n) static int mcp_mutator_##n##_c(lua_State *L, int tidx)
135 #define mut_step_i(n) static int mcp_mutator_##n##_i(lua_State *L, int tidx, int sc, struct mcp_mutator *mut)
136 #define mut_step_r(n) static int mcp_mutator_##n##_r(struct mcp_mut_run *run, struct mcp_mut_step *s, struct mcp_mut_part *p)
137 #define mut_step_n(n) static int mcp_mutator_##n##_n(struct mcp_mut_run *run, struct mcp_mut_step *s, struct mcp_mut_part *p)
138 
139 // PRIVATE INTERFACE
140 
141 // COMMON ARG HANDLERS
142 
_mut_check_idx(lua_State * L,int tidx)143 static void _mut_check_idx(lua_State *L, int tidx) {
144     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
145         luaL_checktype(L, -1, LUA_TNUMBER);
146         int isnum = 0;
147         lua_Integer i = lua_tointegerx(L, -1, &isnum);
148         if (!isnum) {
149             proxy_lua_ferror(L, "mutator step %d: must provide 'idx' argument as an integer", tidx);
150         }
151         if (i < 2) {
152             proxy_lua_ferror(L, "mutator step %d: 'idx' argument must be greater than 1", tidx);
153         }
154     } else {
155         proxy_lua_ferror(L, "mutator step %d: must provide 'idx' argument", tidx);
156     }
157     lua_pop(L, 1);
158 }
159 
_mut_check_strlen(lua_State * L,int tidx,const char * n)160 static size_t _mut_check_strlen(lua_State *L, int tidx, const char *n) {
161     size_t len = 0;
162 
163     if (lua_getfield(L, tidx, n) != LUA_TNIL) {
164         lua_tolstring(L, -1, &len);
165     } else {
166         proxy_lua_ferror(L, "mutator step %d: must provide '%s' argument", tidx, n);
167     }
168     lua_pop(L, 1);
169 
170     return len;
171 }
172 
_mut_check_flag(lua_State * L,int tidx)173 static void _mut_check_flag(lua_State *L, int tidx) {
174     if (lua_getfield(L, tidx, "flag") != LUA_TNIL) {
175         size_t len = 0;
176         const char *flag = lua_tolstring(L, -1, &len);
177         if (len != 1) {
178             proxy_lua_ferror(L, "mutator step %d: 'flag' must be a single character", tidx);
179         }
180         if (mcp_is_flag_invalid(flag[0])) {
181             proxy_lua_ferror(L, "mutator step %d: 'flag' must be alphanumeric", tidx);
182         }
183     } else {
184         proxy_lua_ferror(L, "mutator step %d: must provide 'flag' argument", tidx);
185     }
186     lua_pop(L, 1); // val or nil
187 }
188 
_mut_init_flag(lua_State * L,int tidx,struct mcp_mut_flag * c)189 static void _mut_init_flag(lua_State *L, int tidx, struct mcp_mut_flag *c) {
190     if (lua_getfield(L, tidx, "flag") != LUA_TNIL) {
191         const char *flag = lua_tostring(L, -1);
192         c->f = flag[0];
193         c->bit = (uint64_t)1 << (c->f - 65);
194     }
195     lua_pop(L, 1); // val or nil
196 }
197 
198 // END COMMMON ARG HANDLERS
199 
200 // START STEPS
201 
202 // FIXME: decide on if this should take an mcp.CMD_etc instead, or at least
203 // optionally.
204 // we could also parse this into the int to avoid copying a string here.
205 // FIXME: track step progress and validate we're the first one.
mut_step_c(cmdset)206 mut_step_c(cmdset) {
207     size_t len = 0;
208 
209     if (lua_getfield(L, tidx, "cmd") != LUA_TNIL) {
210         lua_tolstring(L, -1, &len);
211         // TODO: know either exact max length or parse for valid commands
212         // this small sanity check should help against user error for now.
213         if (len > 20) {
214             proxy_lua_ferror(L, "mutator step %d: 'cmd' too long", tidx);
215         }
216     } else {
217         proxy_lua_ferror(L, "mutator step %d: must provide 'cmd' argument", tidx);
218     }
219     lua_pop(L, 1);
220 
221     return len;
222 }
223 
mut_step_i(cmdset)224 mut_step_i(cmdset) {
225     struct mcp_mut_step *s = &mut->steps[sc];
226     struct mcp_mut_string *c = &s->c.string;
227     size_t len = 0;
228 
229     if (lua_getfield(L, tidx, "cmd") != LUA_TNIL) {
230         const char *cmd = lua_tolstring(L, -1, &len);
231         c->str = mut->aused;
232         c->len = len;
233         char *a = mut->arena + mut->aused;
234         memcpy(a, cmd, len);
235         mut->aused += len;
236     }
237     lua_pop(L, 1);
238 
239     return 0;
240 }
241 
mut_step_n(cmdset)242 mut_step_n(cmdset) {
243     struct mcp_mut_string *c = &s->c.string;
244     return c->len;
245 }
246 
mut_step_r(cmdset)247 mut_step_r(cmdset) {
248     struct mcp_mutator *mut = run->mut;
249     struct mcp_mut_string *c = &s->c.string;
250 
251     const char *str = mut->arena + c->str;
252 
253     memcpy(run->d_pos, str, c->len);
254     run->d_pos += c->len;
255 
256     return 0;
257 }
258 
259 // TODO: validate we're at the right stage to copy a command (no command set)
mut_step_c(cmdcopy)260 mut_step_c(cmdcopy) {
261     _mut_check_idx(L, tidx);
262     return 0;
263 }
264 
mut_step_i(cmdcopy)265 mut_step_i(cmdcopy) {
266     struct mcp_mut_step *s = &mut->steps[sc];
267     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
268         s->idx = lua_tointeger(L, -1);
269     }
270     lua_pop(L, 1);
271 
272     return 0;
273 }
274 
mut_step_n(cmdcopy)275 mut_step_n(cmdcopy) {
276     unsigned idx = s->idx;
277     // TODO: validate metatable matches or pull from cached entry
278     mcp_request_t *srq = lua_touserdata(run->L, idx);
279 
280     // command must be at the start
281     const char *cmd = srq->pr.request;
282     // command ends at the first token
283     int clen = srq->pr.tokens[1];
284     if (cmd[clen] == ' ') {
285         clen--;
286     }
287     p->src = cmd;
288     p->slen = clen;
289 
290     return clen;
291 }
292 
mut_step_r(cmdcopy)293 mut_step_r(cmdcopy) {
294     memcpy(run->d_pos, p->src, p->slen);
295     run->d_pos += p->slen;
296     return 0;
297 }
298 
299 // TODO: validate a cmd is already slated to be set
300 // NOTE: we might need to know the integer CMD because key position can move
301 // with the stupid GAT command.
mut_step_c(keycopy)302 mut_step_c(keycopy) {
303     _mut_check_idx(L, tidx);
304     return 0;
305 }
306 
307 // FIXME: idx_i_g?
mut_step_i(keycopy)308 mut_step_i(keycopy) {
309     struct mcp_mut_step *s = &mut->steps[sc];
310     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
311         s->idx = lua_tointeger(L, -1);
312     }
313     lua_pop(L, 1);
314     return 0;
315 }
316 
mut_step_n(keycopy)317 mut_step_n(keycopy) {
318     unsigned idx = s->idx;
319     // TODO: validate metatable table matches or pull from cached entry
320     mcp_request_t *srq = lua_touserdata(run->L, idx);
321 
322     p->src = MCP_PARSER_KEY(srq->pr);
323     p->slen = srq->pr.klen;
324 
325     return p->slen;
326 }
327 
mut_step_r(keycopy)328 mut_step_r(keycopy) {
329     memcpy(run->d_pos, p->src, p->slen);
330     run->d_pos += p->slen;
331     return 0;
332 }
333 
334 // TODO: check we're okay to set a key
mut_step_c(keyset)335 mut_step_c(keyset) {
336     size_t len = 0;
337 
338     if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
339         lua_tolstring(L, -1, &len);
340         if (len < 1) {
341             proxy_lua_ferror(L, "mutator step %d: 'str' must have nonzero length", tidx);
342         }
343     } else {
344         proxy_lua_ferror(L, "mutator step %d: must provide 'str' argument", tidx);
345     }
346     lua_pop(L, 1); // val or nil
347 
348     return len;
349 }
350 
mut_step_i(keyset)351 mut_step_i(keyset) {
352     struct mcp_mut_step *s = &mut->steps[sc];
353     struct mcp_mut_string *c = &s->c.string;
354     size_t len = 0;
355 
356     // store our match string in the arena space that we reserved before.
357     if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
358         const char *str = lua_tolstring(L, -1, &len);
359         c->str = mut->aused;
360         c->len = len;
361         char *a = mut->arena + mut->aused;
362         memcpy(a, str, len);
363         mut->aused += len;
364     }
365     lua_pop(L, 1); // val or nil
366 
367     return len;
368 }
369 
mut_step_n(keyset)370 mut_step_n(keyset) {
371     struct mcp_mut_string *c = &s->c.string;
372     return c->len;
373 }
374 
mut_step_r(keyset)375 mut_step_r(keyset) {
376     struct mcp_mutator *mut = run->mut;
377     struct mcp_mut_string *c = &s->c.string;
378 
379     const char *str = mut->arena + c->str;
380 
381     memcpy(run->d_pos, str, c->len);
382     run->d_pos += c->len;
383     return 0;
384 }
385 
386 // TODO: ensure step is first
387 // TODO: pre-validate that it's an accepted code?
mut_step_c(rescodeset)388 mut_step_c(rescodeset) {
389     return _mut_check_strlen(L, tidx, "str");
390 }
391 
mut_step_i(rescodeset)392 mut_step_i(rescodeset) {
393     struct mcp_mut_step *s = &mut->steps[sc];
394     struct mcp_mut_string *c = &s->c.string;
395     size_t len = 0;
396 
397     if (lua_getfield(L, tidx, "str") != LUA_TNIL) {
398         const char *str = lua_tolstring(L, -1, &len);
399         c->str = mut->aused;
400         c->len = len;
401         char *a = mut->arena + mut->aused;
402         memcpy(a, str, len);
403         mut->aused += len;
404     }
405     lua_pop(L, 1);
406 
407     return 0;
408 }
409 
mut_step_n(rescodeset)410 mut_step_n(rescodeset) {
411     struct mcp_mut_string *c = &s->c.string;
412     return c->len;
413 }
414 
mut_step_r(rescodeset)415 mut_step_r(rescodeset) {
416     struct mcp_mutator *mut = run->mut;
417     struct mcp_mut_string *c = &s->c.string;
418 
419     const char *str = mut->arena + c->str;
420 
421     memcpy(run->d_pos, str, c->len);
422     run->d_pos += c->len;
423     return 0;
424 }
425 
426 // TODO: check we're the first step
mut_step_c(rescodecopy)427 mut_step_c(rescodecopy) {
428     _mut_check_idx(L, tidx);
429     return 0;
430 }
431 
mut_step_i(rescodecopy)432 mut_step_i(rescodecopy) {
433     struct mcp_mut_step *s = &mut->steps[sc];
434     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
435         s->idx = lua_tointeger(L, -1);
436     }
437     lua_pop(L, 1);
438 
439     return 0;
440 }
441 
mut_step_n(rescodecopy)442 mut_step_n(rescodecopy) {
443     unsigned idx = s->idx;
444     // TODO: validate metatable matches or pull from cached entry
445     mcp_resp_t *srs = lua_touserdata(run->L, idx);
446 
447     // TODO: can't recover the exact from the mcmc resp object, so lets make
448     // sure it's tokenized and copy the first token.
449     if (srs->resp.type == MCMC_RESP_META) {
450         mcmc_tokenize_res(srs->buf, srs->resp.reslen, &srs->tok);
451     } else {
452         // FIXME: above only does meta responses
453         assert(1 == 0);
454     }
455     int len = 0;
456     p->src = mcmc_token_get(srs->buf, &srs->tok, 0, &len);
457     p->slen = len;
458     return len;
459 }
460 
461 // TODO: take a string or number from that position.
mut_step_r(rescodecopy)462 mut_step_r(rescodecopy) {
463     // FIXME: error propagation
464     // FIXME: can we do all the error handling in the totalling phase?
465     if (p->slen < 2) {
466         return -1;
467     }
468     memcpy(run->d_pos, p->src, p->slen);
469     run->d_pos += p->slen;
470     return 0;
471 }
472 
473 // TODO: can be no other steps after an error is set.
mut_step_c(reserr)474 mut_step_c(reserr) {
475     size_t total = 0;
476     char *code = NULL;
477 
478     // FIXME: add code length to len
479     if (lua_getfield(L, tidx, "code") != LUA_TNIL) {
480         const char *val = lua_tostring(L, -1);
481 
482         if (strcmp(val, "error") == 0) {
483             code = RESERR_ERROR_STR;
484         } else if (strcmp(val, "server") == 0) {
485             code = RESERR_SERVER_STR;
486         } else if (strcmp(val, "client") == 0) {
487             code = RESERR_CLIENT_STR;
488         } else {
489             proxy_lua_ferror(L, "mutator step %d: mode must be 'error', server', or 'client'", tidx);
490         }
491 
492         total += strlen(code);
493     } else {
494         proxy_lua_ferror(L, "mutator step %d: must provide 'mode' argument", tidx);
495     }
496     lua_pop(L, 1);
497 
498     if (lua_getfield(L, tidx, "msg") != LUA_TNIL) {
499         size_t len = 0;
500         lua_tolstring(L, -1, &len);
501         if (len < 1) {
502             proxy_lua_ferror(L, "mutator step %d: 'msg' must be a nonzero length string", tidx);
503         }
504         total += len + 1; // room for space between code and msg
505     }
506     lua_pop(L, 1);
507 
508     return total;
509 }
510 
mut_step_i(reserr)511 mut_step_i(reserr) {
512     struct mcp_mut_step *s = &mut->steps[sc];
513     struct mcp_mut_string *c = &s->c.string;
514     size_t len = 0;
515     const char *code = NULL;
516 
517     char *a = mut->arena + mut->aused;
518     if (lua_getfield(L, tidx, "code") != LUA_TNIL) {
519         const char *val = lua_tostring(L, -1);
520         if (strcmp(val, "error") == 0) {
521             code = RESERR_ERROR_STR;
522         } else if (strcmp(val, "server") == 0) {
523             code = RESERR_SERVER_STR;
524         } else if (strcmp(val, "client") == 0) {
525             code = RESERR_CLIENT_STR;
526         } else {
527             // shouldn't be possible
528             proxy_lua_ferror(L, "mutator step %d: code must be 'error', server', or 'client'", tidx);
529         }
530 
531         size_t clen = strlen(code);
532         memcpy(a, code, clen);
533         a += clen;
534         *a = ' ';
535         a++;
536         mut->aused += clen + 1;
537     } else {
538         proxy_lua_ferror(L, "mutator step %d: must provide 'code' argument", tidx);
539     }
540     lua_pop(L, 1);
541 
542     if (lua_getfield(L, tidx, "msg") != LUA_TNIL) {
543         const char *str = lua_tolstring(L, -1, &len);
544         c->str = mut->aused;
545         c->len = len;
546         memcpy(a, str, len);
547         mut->aused += len;
548     } else {
549         // TODO: note no error msg
550     }
551     lua_pop(L, 1);
552 
553     return len;
554 }
555 
mut_step_n(reserr)556 mut_step_n(reserr) {
557     struct mcp_mut_string *c = &s->c.string;
558     return c->len;
559 }
560 
mut_step_r(reserr)561 mut_step_r(reserr) {
562     struct mcp_mutator *mut = run->mut;
563     struct mcp_mut_string *c = &s->c.string;
564 
565     const char *str = mut->arena + c->str;
566     int len = c->len;
567 
568     // set error code first
569     memcpy(run->d_pos, str, len);
570     run->d_pos += len;
571     return 0;
572 }
573 
574 // TODO: track which flags we've already set and error on dupes
mut_step_c(flagset)575 mut_step_c(flagset) {
576     _mut_check_flag(L, tidx);
577     size_t len = 0;
578 
579     int vtype = lua_getfield(L, tidx, "val");
580     if (vtype == LUA_TNUMBER || vtype == LUA_TSTRING) {
581         // this converts the arg into a string for us.
582         lua_tolstring(L, -1, &len);
583     } else if (vtype != LUA_TNIL) {
584         proxy_lua_ferror(L, "mutator step %d: unsupported type for 'val'", tidx);
585     }
586     lua_pop(L, 1);
587 
588     return len;
589 }
590 
mut_step_i(flagset)591 mut_step_i(flagset) {
592     struct mcp_mut_step *s = &mut->steps[sc];
593     struct mcp_mut_flagval *c = &s->c.flagval;
594     size_t len = 0;
595 
596     _mut_init_flag(L, tidx, &c->flag);
597     if (lua_getfield(L, tidx, "val") != LUA_TNIL) {
598         const char *str = lua_tolstring(L, -1, &len);
599         c->str.str = mut->aused;
600         c->str.len = len;
601         char *a = mut->arena + mut->aused;
602         memcpy(a, str, len);
603         mut->aused += len;
604     }
605     lua_pop(L, 1);
606 
607     return len;
608 }
609 
mut_step_n(flagset)610 mut_step_n(flagset) {
611     struct mcp_mut_flagval *c = &s->c.flagval;
612     return c->str.len + 1; // room for flag
613 }
614 
615 // TODO: validate we're okay to set flags.
616 // FIXME: triple check that this is actually the same code for req vs res?
617 // seems like it is.
mut_step_r(flagset)618 mut_step_r(flagset) {
619     struct mcp_mutator *mut = run->mut;
620     struct mcp_mut_flagval *c = &s->c.flagval;
621 
622     const char *str = mut->arena + c->str.str;
623     int len = c->str.len;
624 
625     *(run->d_pos) = c->flag.f;
626     run->d_pos++;
627     if (len > 0) {
628         memcpy(run->d_pos, str, len);
629         run->d_pos += len;
630     }
631 
632     return 0;
633 }
634 
mut_step_c(flagcopy)635 mut_step_c(flagcopy) {
636     _mut_check_flag(L, tidx);
637     _mut_check_idx(L, tidx);
638     return 0;
639 }
640 
641 // TODO: maybe: optional default val if copy source missing
mut_step_i(flagcopy)642 mut_step_i(flagcopy) {
643     struct mcp_mut_step *s = &mut->steps[sc];
644     struct mcp_mut_flag *c = &s->c.flag;
645 
646     _mut_init_flag(L, tidx, c);
647 
648     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
649         s->idx = lua_tointeger(L, -1);
650     }
651     lua_pop(L, 1);
652 
653     return 0;
654 }
655 
656 // TODO: any reason for a req to pull from a res or vice versa?
657 // FIXME: handling when source flag doesn't exist might need a special case.
mut_step_n(flagcopy)658 mut_step_n(flagcopy) {
659     struct mcp_mutator *mut = run->mut;
660     struct mcp_mut_flag *c = &s->c.flag;
661 
662     unsigned idx = s->idx;
663     // TODO: validate idx or use cached entry.
664     if (mut->type == MUT_REQ) {
665         mcp_request_t *srq = lua_touserdata(run->L, idx);
666         if (srq->pr.cmd_type != CMD_TYPE_META) {
667             return -1;
668         }
669         if (srq->pr.t.meta.flags & c->bit) {
670             const char *tok = NULL;
671             size_t tlen = 0;
672             mcp_request_find_flag_token(srq, c->f, &tok, &tlen);
673 
674             if (tlen > 0) {
675                 p->src = tok;
676                 p->slen = tlen;
677             } else {
678                 p->slen = 0;
679             }
680         }
681     } else {
682         mcp_resp_t *srs = lua_touserdata(run->L, idx);
683         if (srs->resp.type != MCMC_RESP_META) {
684             // FIXME: error, can't copy flag from non-meta res
685             return -1;
686         }
687         mcmc_tokenize_res(srs->buf, srs->resp.reslen, &srs->tok);
688         if (mcmc_token_has_flag_bit(&srs->tok, c->bit) == MCMC_OK) {
689             // flag exists, so copy that in.
690             // realistically this func is only used if we're also copying a
691             // token, so we look for that too.
692             // could add an option to avoid checking for a token?
693             int len = 0;
694             const char *tok = mcmc_token_get_flag(srs->buf, &srs->tok, c->f, &len);
695 
696             if (len > 0) {
697                 p->src = tok;
698                 p->slen = len;
699             } else {
700                 p->slen = 0;
701             }
702         }
703     }
704 
705     return 0;
706 }
707 
mut_step_r(flagcopy)708 mut_step_r(flagcopy) {
709     struct mcp_mut_flag *c = &s->c.flag;
710     *(run->d_pos) = c->f;
711     run->d_pos++;
712     if (p->slen) {
713         memcpy(run->d_pos, p->src, p->slen);
714         run->d_pos += p->slen;
715     }
716     return 0;
717 }
718 
719 // TODO: check that the value hasn't been set yet.
mut_step_c(valcopy)720 mut_step_c(valcopy) {
721     _mut_check_idx(L, tidx);
722 
723     // TODO: lift to common func
724     if (lua_getfield(L, tidx, "arg") == LUA_TSTRING) {
725         const char *a = lua_tostring(L, -1);
726         if (strcmp(a, "request") != 0 &&
727             strcmp(a, "response") != 0 &&
728             strcmp(a, "string") != 0 &&
729             strcmp(a, "int") != 0) {
730             proxy_lua_ferror(L, "mutator step %d: 'arg' must be request, response, string or int", tidx);
731         }
732     } else {
733         proxy_lua_ferror(L, "mutator step %d: missing 'arg' for input type", tidx);
734     }
735     lua_pop(L, 1);
736     return 0;
737 }
738 
mut_step_i(valcopy)739 mut_step_i(valcopy) {
740     struct mcp_mut_step *s = &mut->steps[sc];
741 
742     if (lua_getfield(L, tidx, "idx") != LUA_TNIL) {
743         s->idx = lua_tointeger(L, -1);
744     }
745     lua_pop(L, 1);
746 
747     // TODO: lift to common func
748     if (lua_getfield(L, tidx, "arg") == LUA_TSTRING) {
749         const char *a = lua_tostring(L, -1);
750         if (strcmp(a, "request") == 0) {
751             s->arg = mcp_mut_step_arg_request;
752         } else if (strcmp(a, "response") == 0) {
753             s->arg = mcp_mut_step_arg_response;
754         } else if (strcmp(a, "string") == 0) {
755             s->arg = mcp_mut_step_arg_string;
756         } else if (strcmp(a, "int") == 0) {
757             s->arg = mcp_mut_step_arg_int;
758         } else {
759             proxy_lua_ferror(L, "mutator step %d: 'arg' must be request, response, string or int", tidx);
760         }
761     }
762     lua_pop(L, 1);
763 
764     return 0;
765 }
766 
mut_step_n(valcopy)767 mut_step_n(valcopy) {
768     lua_State *L = run->L;
769     unsigned idx = s->idx;
770     // extract the string + length we need to copy
771     mcp_request_t *srq;
772     //mcp_resp_t *srs;
773 
774     // TODO: lift to common func?
775     // parts of it? with callback?
776     switch (s->arg) {
777         case mcp_mut_step_arg_none:
778             // can't get here.
779             break;
780         case mcp_mut_step_arg_request:
781             lua_getmetatable(L, idx);
782             lua_getiuservalue(L, 1, MUT_REQ);
783             if (lua_rawequal(L, -1, -2) == 0) {
784                 // FIXME: error propagation
785                 return -1;
786             }
787             lua_pop(L, 2);
788             srq = lua_touserdata(L, idx);
789             if (srq->pr.vbuf) {
790                 run->vbuf = srq->pr.vbuf;
791                 run->vlen = srq->pr.vlen;
792             }
793             break;
794         case mcp_mut_step_arg_response:
795             lua_getmetatable(L, idx);
796             lua_getiuservalue(L, 1, MUT_RES);
797             if (lua_rawequal(L, -1, -2) == 0) {
798                 // FIXME: error propagation
799                 return -1;
800             }
801             lua_pop(L, 2);
802             assert(1 == 0);
803             //srs = lua_touserdata(L, idx);
804             // TODO: need to locally parse the result to get the actual val
805             // offsets until later refactoring takes place.
806             break;
807         case mcp_mut_step_arg_string:
808             if (lua_isstring(L, idx)) {
809                 // TODO: do we require the user supplies "\r\n"?
810                 // detect it here and add a flag or adjust or etc?
811                 run->vbuf = lua_tolstring(L, idx, &run->vlen);
812             }
813             break;
814         case mcp_mut_step_arg_int:
815             // TODO: just do number instead of int? meh.
816             // we want to not auto-convert this to a string.
817             lua_isnumber(L, idx);
818             assert(1 == 0); // TODO: unimplemented.
819             break;
820     }
821 
822     // count the number of digits in vlen to reserve space.
823     //
824     // oddly algorithms to count digits and write digits are similar (outside
825     // of hyper optimization via bit math), so just reuse the same code here.
826     // if I can ever get arena allocations to work and remove the pre-calc
827     // steps this is moot anyway.
828     char temp[22];
829     const char *e = itoa_u64(run->vlen, temp);
830 
831     return e - temp;
832 }
833 
834 // print the vlen into the buffer
835 // we remove the \r\n from the protocol length
mut_step_r(valcopy)836 mut_step_r(valcopy) {
837     run->d_pos = itoa_u64(run->vlen-2, run->d_pos);
838     return 0;
839 }
840 
841 // END STEPS
842 
843 static const struct mcp_mut_entry mcp_mut_entries[] = {
844     [mcp_mut_step_none] = {NULL, NULL, NULL, NULL, NULL, 0, 0},
845     [mcp_mut_step_cmdset] = {"cmdset", mcp_mutator_cmdset_c, mcp_mutator_cmdset_i, mcp_mutator_cmdset_n, mcp_mutator_cmdset_r, MUT_REQ, 0},
846     [mcp_mut_step_cmdcopy] = {"cmdcopy", mcp_mutator_cmdcopy_c, mcp_mutator_cmdcopy_i, mcp_mutator_cmdcopy_n, mcp_mutator_cmdcopy_r, MUT_REQ, 0},
847     [mcp_mut_step_keycopy] = {"keycopy", mcp_mutator_keycopy_c, mcp_mutator_keycopy_i, mcp_mutator_keycopy_n, mcp_mutator_keycopy_r, MUT_REQ, 0},
848     [mcp_mut_step_keyset] = {"keyset", mcp_mutator_keyset_c, mcp_mutator_keyset_i, mcp_mutator_keyset_n, mcp_mutator_keyset_r, MUT_REQ, 0},
849     [mcp_mut_step_rescodeset] = {"rescodeset", mcp_mutator_rescodeset_c, mcp_mutator_rescodeset_i, mcp_mutator_rescodeset_n, mcp_mutator_rescodeset_r, MUT_RES, 0},
850     [mcp_mut_step_rescodecopy] = {"rescodecopy", mcp_mutator_rescodecopy_c, mcp_mutator_rescodecopy_i, mcp_mutator_rescodecopy_n, mcp_mutator_rescodecopy_r, MUT_RES, 0},
851     [mcp_mut_step_reserr] = {"reserr", mcp_mutator_reserr_c, mcp_mutator_reserr_i, mcp_mutator_reserr_n, mcp_mutator_reserr_r, MUT_RES, 0},
852     [mcp_mut_step_flagset] = {"flagset", mcp_mutator_flagset_c, mcp_mutator_flagset_i, mcp_mutator_flagset_n, mcp_mutator_flagset_r, MUT_REQ|MUT_RES, 0},
853     [mcp_mut_step_flagcopy] = {"flagcopy", mcp_mutator_flagcopy_c, mcp_mutator_flagcopy_i, mcp_mutator_flagcopy_n, mcp_mutator_flagcopy_r, MUT_REQ|MUT_RES, 0},
854     [mcp_mut_step_valcopy] = {"valcopy", mcp_mutator_valcopy_c, mcp_mutator_valcopy_i, mcp_mutator_valcopy_n, mcp_mutator_valcopy_r, MUT_REQ|MUT_RES, 0},
855     [mcp_mut_step_final] = {NULL, NULL, NULL, NULL, NULL, 0, 0},
856 };
857 
858 // call with type string on top
mcp_mutator_steptype(lua_State * L)859 static enum mcp_mut_steptype mcp_mutator_steptype(lua_State *L) {
860     const char *type = luaL_checkstring(L, -1);
861     for (int x = 0; x < mcp_mut_step_final; x++) {
862         const struct mcp_mut_entry *e = &mcp_mut_entries[x];
863         if (e->s && strcmp(type, e->s) == 0) {
864             return x;
865         }
866     }
867     return mcp_mut_step_none;
868 }
869 
mcp_mutator_new(lua_State * L,enum mcp_mut_type type)870 static int mcp_mutator_new(lua_State *L, enum mcp_mut_type type) {
871     int argc = lua_gettop(L);
872     size_t size = 0;
873     int scount = 0;
874 
875     // loop argument tables once for validation and pre-calculations.
876     for (int x = 1; x <= argc; x++) {
877         luaL_checktype(L, x, LUA_TTABLE);
878         if (lua_getfield(L, x, "t") != LUA_TNIL) {
879             enum mcp_mut_steptype st = mcp_mutator_steptype(L);
880             const struct mcp_mut_entry *e = &mcp_mut_entries[st];
881             if (!(e->t & type)) {
882                 proxy_lua_ferror(L, "mutator step %d: step incompatible with mutator type", x);
883             }
884             if ((st == mcp_mut_step_none) || e->c == NULL) {
885                 proxy_lua_ferror(L, "mutator step %d: unknown step type", x);
886             }
887             size += e->c(L, x);
888         }
889         lua_pop(L, 1); // drop 't' or nil
890         scount++;
891     }
892 
893     // we now know the size and number of steps. allocate some flat memory.
894 
895     size_t extsize = sizeof(struct mcp_mut_step) * scount;
896     struct mcp_mutator *mut = lua_newuserdatauv(L, sizeof(*mut) + extsize, 2);
897     memset(mut, 0, sizeof(*mut));
898 
899     mut->arena = malloc(size);
900     if (mut->arena == NULL) {
901         proxy_lua_error(L, "mutator_new: failed to allocate memory");
902     }
903     luaL_setmetatable(L, "mcp.mutator");
904     mut->type = type;
905 
906     // Cache both request and result metatables for arg validation.
907     // Since a req mutator can take a res argument and vice versa
908     luaL_getmetatable(L, "mcp.request");
909     lua_setiuservalue(L, -2, MUT_REQ);
910     luaL_getmetatable(L, "mcp.response");
911     lua_setiuservalue(L, -2, MUT_RES);
912 
913     // loop the arg tables again to fill in the steps
914     // skip checks since we did that during the first loop.
915     scount = 0;
916     for (int x = 1; x <= argc; x++) {
917         if (lua_getfield(L, x, "t") != LUA_TNIL) {
918             enum mcp_mut_steptype st = mcp_mutator_steptype(L);
919             mut->steps[scount].type = st;
920             mcp_mut_entries[st].i(L, x, scount, mut);
921             mut->rcount += mcp_mut_entries[st].rc;
922 
923             // copy function pointers into the step so we don't have to skip
924             // around the much larger mcp_mut_entries at runtime.
925             mut->steps[scount].n = mcp_mut_entries[st].n;
926             mut->steps[scount].r = mcp_mut_entries[st].r;
927             mut->steps[scount].idx++; // actual args are "self, etc, etc"
928         }
929         lua_pop(L, 1); // drop t or nil
930         scount++;
931     }
932 
933     if (size != mut->aused) {
934         proxy_lua_error(L, "mutator failed to properly initialize, memory not filled correctly");
935     }
936     mut->scount = scount;
937 
938     return 1;
939 }
940 
_mcp_mut_run_total(struct mcp_mut_run * run,struct mcp_mut_part * parts)941 static inline int _mcp_mut_run_total(struct mcp_mut_run *run, struct mcp_mut_part *parts) {
942     int total = 0;
943     struct mcp_mutator *mut = run->mut;
944     for (int x = 0; x < mut->scount; x++) {
945         struct mcp_mut_step *s = &mut->steps[x];
946         assert(s->type != mcp_mut_step_none);
947         int len = s->n(run, s, &parts[x]);
948         if (len < 0) {
949             assert(1 == 0);
950             break;
951         } else {
952             total += len;
953         }
954     }
955     // account for spaces between "steps" and \r\n
956     // note that steps that themselves can make multiple tokens _must_ account
957     // for this on their own.
958     total += mut->scount + MIN_BUF_SPACE;
959 
960     return total;
961 }
962 
_mcp_mut_run_assemble(struct mcp_mut_run * run,struct mcp_mut_part * parts)963 static inline int _mcp_mut_run_assemble(struct mcp_mut_run *run, struct mcp_mut_part *parts) {
964     struct mcp_mutator *mut = run->mut;
965     // assemble final req/res
966     for (int x = 0; x < mut->scount; x++) {
967         struct mcp_mut_step *s = &mut->steps[x];
968         assert(s->type != mcp_mut_step_none);
969         // TODO: handle -1 errors, halt.
970         // TODO: can we structure this so we don't have to check for errors at
971         // this stage, only the first one? would be nice to cut the branch out
972         if (s->r(run, s, &parts[x]) < 0) {
973             assert(1 == 0);
974         }
975 
976         *(run->d_pos) = ' ';
977         run->d_pos++;
978     }
979 
980     // TODO: any cases where we need to check if the final char is a space or
981     // not?
982     // add the \r\n after all steps
983     *(run->d_pos-1) = '\r';
984     *(run->d_pos) = '\n';
985     run->d_pos++;
986 
987     return 0;
988 }
989 
mcp_mut_run(struct mcp_mut_run * run)990 static int mcp_mut_run(struct mcp_mut_run *run) {
991     struct mcp_mutator *mut = run->mut;
992     LIBEVENT_THREAD *t = PROXY_GET_THR(run->L);
993     int ret = 0;
994     struct mcp_mut_part parts[mut->scount];
995 
996     // first accumulate the length tally
997     int total = _mcp_mut_run_total(run, parts);
998     // FIXME: error handling from total call
999 
1000     // ensure space and/or allocate memory then seed our destination pointer.
1001     if (mut->type == MUT_REQ) {
1002         mcp_request_t *rq = run->arg;
1003         // FIXME: cleanup should be managed by slot rctx.
1004         mcp_request_cleanup(t, rq);
1005         // future.. should be able to dynamically assign request buffer.
1006         if (total > MCP_REQUEST_MAXLEN) {
1007             // FIXME: proper error.
1008             assert(1 == 0);
1009         }
1010         run->d_pos = rq->request;
1011 
1012         _mcp_mut_run_assemble(run, parts);
1013 
1014         // TODO: process_request()
1015         // if run->vbuf, malloc/copy vbuf.
1016         if (process_request(&rq->pr, rq->request, run->d_pos - rq->request) != 0) {
1017             // TODO: throw error or return false?
1018             assert(1 == 0);
1019         }
1020 
1021         if (run->vbuf) {
1022             rq->pr.vbuf = malloc(run->vlen);
1023             if (rq->pr.vbuf == NULL) {
1024                 assert(1 == 0);
1025             }
1026             pthread_mutex_lock(&t->proxy_limit_lock);
1027             t->proxy_buffer_memory_used += rq->pr.vlen;
1028             pthread_mutex_unlock(&t->proxy_limit_lock);
1029 
1030             rq->pr.vlen = run->vlen;
1031             memcpy(rq->pr.vbuf, run->vbuf, run->vlen);
1032         }
1033     } else {
1034         mcp_resp_t *rs = run->arg;
1035         // FIXME: cleanup should be managed by slot rctx.
1036         mcp_response_cleanup(t, rs);
1037 
1038         // TODO: alloc big enough result buffer.
1039         rs->buf = malloc(total);
1040         if (rs->buf == NULL) {
1041             // FIXME: proper error.
1042             assert(1 == 0);
1043         }
1044         run->d_pos = rs->buf;
1045 
1046         _mcp_mut_run_assemble(run, parts);
1047 
1048         rs->tok.ntokens = 0; // TODO: handler from mcmc?
1049         if (mcmc_parse_buf(rs->buf, run->d_pos - rs->buf, &rs->resp) != MCMC_OK) {
1050             // TODO: throw error or return false?
1051             assert(1 == 0);
1052         }
1053 
1054         // results are sequential buffers, copy the value in.
1055         if (run->vbuf) {
1056             memcpy(run->d_pos, run->vbuf, run->vlen);
1057             run->d_pos += run->vlen;
1058         }
1059 
1060         rs->blen = run->d_pos - rs->buf;
1061         // NOTE: We increment but don't check the memory limits here. Any
1062         // incoming request or incoming response will alos check the memory
1063         // limits, and just doing an increment here removes some potential
1064         // error handling. Requests that are already started should be allowed
1065         // to complete to minimize impact of hitting memory limits.
1066         pthread_mutex_lock(&t->proxy_limit_lock);
1067         t->proxy_buffer_memory_used += rs->blen;
1068         pthread_mutex_unlock(&t->proxy_limit_lock);
1069     }
1070 
1071     return ret;
1072 }
1073 
1074 // PUBLIC INTERFACE
1075 
mcplib_req_mutator_new(lua_State * L)1076 int mcplib_req_mutator_new(lua_State *L) {
1077     return mcp_mutator_new(L, MUT_REQ);
1078 }
1079 
mcplib_res_mutator_new(lua_State * L)1080 int mcplib_res_mutator_new(lua_State *L) {
1081     return mcp_mutator_new(L, MUT_RES);
1082 }
1083 
1084 // walk each step and free references/memory/etc
mcplib_mutator_gc(lua_State * L)1085 int mcplib_mutator_gc(lua_State *L) {
1086     struct mcp_mutator *mut = lua_touserdata(L, 1);
1087 
1088     if (mut->arena) {
1089         free(mut->arena);
1090         mut->arena = NULL;
1091     }
1092 
1093     // NOTE: leaving commented until I run into something that actually has
1094     // something extra to GC
1095     /*for (int x = 0; x < mut->scount; x++) {
1096         struct mcp_mut_step *s = &mut->steps[x];
1097         switch (s->type) {
1098             case mcp_mut_step_none:
1099             case mcp_mut_step_cmdset:
1100             case mcp_mut_step_cmdcopy:
1101             case mcp_mut_step_keycopy:
1102             case mcp_mut_step_keyset:
1103             case mcp_mut_step_rescodeset:
1104             case mcp_mut_step_rescodecopy:
1105             case mcp_mut_step_reserr:
1106             case mcp_mut_step_flagset:
1107             case mcp_mut_step_flagcopy:
1108             case mcp_mut_step_valcopy:
1109             case mcp_mut_step_final:
1110                 break;
1111         }
1112     }*/
1113 
1114     return 0;
1115 }
1116 
mcplib_mutator_call(lua_State * L)1117 int mcplib_mutator_call(lua_State *L) {
1118     // since we're here from a __call, assume the type is correct.
1119     struct mcp_mutator *mut = lua_touserdata(L, 1);
1120     luaL_checktype(L, 2, LUA_TUSERDATA);
1121     if (lua_checkstack(L, mut->rcount + 3) == 0) {
1122         proxy_lua_error(L, "mutator ran out of stack space for results");
1123     }
1124 
1125     lua_getmetatable(L, 2); // put dest obj arg metatable on stack
1126     lua_getiuservalue(L, 1, mut->type); // put stashed metatable on stack
1127     luaL_argcheck(L, lua_rawequal(L, -1, -2), 2,
1128             "invalid argument to mutator object");
1129     lua_pop(L, 2); // toss both metatables
1130 
1131 
1132     // we're valid now.
1133     void *arg = lua_touserdata(L, 2);
1134     // stack scratch space so we can avoid modifying the mut struct
1135     struct mcp_mut_run run = {L, mut, arg, NULL, NULL, 0};
1136     // TODO: numbuf space
1137     int ret = mcp_mut_run(&run);
1138 
1139     return ret;
1140 }
1141