]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Flock: converted HCS to the parser framework
authorMaria Matejka <mq@ucw.cz>
Thu, 3 Oct 2024 21:02:58 +0000 (23:02 +0200)
committerMaria Matejka <mq@ucw.cz>
Sun, 23 Feb 2025 18:07:35 +0000 (19:07 +0100)
flock/ctl.c
flock/flock.h

index a50fda7288639d1fed238d5c68962e1337f1655f..adba6f13c666c3f18a370c7bf745ca2e4a11ba08 100644 (file)
  *   - 4 with array of strings = run the given command inside the hypervisor
  */
 
-struct cbor_parser_context {
-  linpool *lp;
+struct hcs_parser_context {
+  struct cbor_parser_context *ctx;
   sock *sock;
 
-  PACKED enum {
-    CPE_TYPE = 0,
-    CPE_READ_INT,
-    CPE_COMPLETE_INT,
-    CPE_READ_BYTE,
-  } partial_state, partial_next;
-
-  byte type;
-  u64 value;
-  u64 partial_countdown;
-
   u64 bytes_consumed;
-
-  byte *target_buf;
-  uint target_len;
-
   u64 major_state;
 
-  const char *error;
-
-#define LOCAL_STACK_MAX_DEPTH 3
-  u64 stack_countdown[LOCAL_STACK_MAX_DEPTH];
-  uint stack_pos;
-
   /* Specific */
   union flock_machine_config cfg;
 };
 
-#define CBOR_PARSER_ERROR(...) do {            \
-  ctx->error = lp_sprintf(ctx->lp, __VA_ARGS__);\
-  return -(ctx->bytes_consumed + pos + 1);     \
-} while (0)
-
-#define CBOR_PARSER_READ_INT(next)  do {               \
-  ctx->partial_state = CPE_READ_INT;                   \
-  ctx->partial_countdown = (1 << (ctx->value - 24));   \
-  ctx->value = 0;                                      \
-  ctx->partial_next = next;                            \
-} while (0)
-
-struct cbor_parser_context *
+struct hcs_parser_context *
 hcs_parser_init(sock *s)
 {
-  linpool *lp = lp_new(s->pool);
-  struct cbor_parser_context *ctx = lp_allocz(lp, sizeof *ctx);
+  struct cbor_parser_context *ctx = cbor_parser_new(s->pool, 4);
+  struct hcs_parser_context *htx = lp_allocz(ctx->lp, sizeof *htx);
 
-  ctx->lp = lp;
-  ctx->sock = s;
+  htx->ctx = ctx;
+  htx->sock = s;
 
-  ctx->type = 0xff;
-  ctx->stack_countdown[0] = 1;
-
-  return ctx;
+  return htx;
 }
 
+#define CBOR_PARSER_ERROR(...) do {            \
+  ctx->error = lp_sprintf(ctx->lp, __VA_ARGS__);\
+  return -(htx->bytes_consumed + pos + 1);     \
+} while (0)
+
 s64
-hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
+hcs_parse(struct hcs_parser_context *htx, const byte *buf, s64 size)
 {
   ASSERT_DIE(size > 0);
+  struct cbor_parser_context *ctx = htx->ctx;
 
   for (int pos = 0; pos < size; pos++)
   {
-    const byte bp = buf[pos];
-    bool value_is_special = 0;
-    bool exit_stack = false;
-
-    switch (ctx->partial_state)
+    switch (cbor_parse_byte(ctx, buf[pos]))
     {
-      case CPE_TYPE:
-       /* Split the byte to type and value */
-       ctx->type = bp >> 5;
-       ctx->value = bp & 0x1f;
-
-       if (ctx->type == 7)
-       {
-         if (ctx->value < 20)
-           CBOR_PARSER_ERROR("Unknown simple value %u", ctx->value);
-         else if (ctx->value < 24)
-           ; /* false, true, null, undefined */
-         else if (ctx->value < 28)
-         {
-           /* Need more data */
-           CBOR_PARSER_READ_INT(CPE_COMPLETE_INT);
-           break;
-         }
-         else if (ctx->value == 31)
-           ; /* break-stop */
-         else
-           CBOR_PARSER_ERROR("Unknown simple value %u", ctx->value);
-       }
-       else
-       {
-         if (ctx->value < 24)
-           ; /* Immediate value, fall through */
-         else if (ctx->value < 28)
-         {
-           /* Need more data */
-           CBOR_PARSER_READ_INT(CPE_COMPLETE_INT);
-           break;
-         }
-         else if ((ctx->value == 31) && (ctx->type >= 2) && (ctx->type <= 5))
-           /* Indefinite length, fall through */
-           value_is_special = 1;
-         else
-           CBOR_PARSER_ERROR("Garbled additional value %u for type %u", ctx->value, ctx->type);
-       }
-       /* fall through */
-
-      case CPE_READ_INT:
-       if (ctx->partial_state == CPE_READ_INT)
-       {
-         /* Reading a network order integer */
-         ctx->value <<= 8;
-         ctx->value |= bp;
-         if (--ctx->partial_countdown)
-           break;
-       }
-       /* fall through */
+      case CPR_ERROR:
+       /* Parser failure */
+       return -(htx->bytes_consumed + pos + 1);
 
-      case CPE_COMPLETE_INT:
-       /* TODO: exception for 7-31 end of long thing */
+      case CPR_MORE:
+       /* Need more bytes */
+       continue;
 
+      case CPR_MAJOR:
        /* Check type acceptance */
-       switch (ctx->major_state)
+       switch (htx->major_state)
        {
          case 0: /* toplevel */
            if (ctx->type != 5)
@@ -155,7 +76,7 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->value != 1)
              CBOR_PARSER_ERROR("Expected mapping of length 1, got %u", ctx->value);
 
-           ctx->major_state = 1;
+           htx->major_state = 1;
            break;
 
          case 1: /* inside toplevel mapping */
@@ -165,7 +86,7 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->value >= 5)
              CBOR_PARSER_ERROR("Command key too high, got %lu", ctx->value);
 
-           ctx->major_state = ctx->value + 2;
+           htx->major_state = ctx->value + 2;
            break;
 
          case 2: /* shutdown command: expected null */
@@ -175,21 +96,21 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            log(L_INFO "Requested shutdown via CLI");
            ev_send_loop(&main_birdloop, &poweroff_event);
            {
-             struct cbor_writer *cw = cbor_init(ctx->sock->tbuf, ctx->sock->tbsize, ctx->lp);
+             struct cbor_writer *cw = cbor_init(htx->sock->tbuf, htx->sock->tbsize, ctx->lp);
              cbor_open_block_with_length(cw, 1);
              cbor_add_int(cw, -1);
              cbor_add_string(cw, "OK");
-             sk_send(ctx->sock, cw->pt);
+             sk_send(htx->sock, cw->pt);
            }
 
-           ctx->major_state = 1;
+           htx->major_state = 1;
            break;
 
          case 3: /* telnet listener open */
            if ((ctx->type == 7) && (ctx->value == 22))
            {
-             hexp_get_telnet(ctx->sock, NULL);
-             ctx->major_state = 1;
+             hexp_get_telnet(htx->sock, NULL);
+             htx->major_state = 1;
              break;
            }
 
@@ -197,7 +118,7 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
              CBOR_PARSER_ERROR("Expected null or string, got %u-%u", ctx->type, ctx->value);
 
            ASSERT_DIE(!ctx->target_buf);
-           ctx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           htx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
            ctx->target_len = ctx->value;
 
            break;
@@ -207,21 +128,21 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
              CBOR_PARSER_ERROR("Expected null, got %u-%u", ctx->type, ctx->value);
 
            log(L_INFO "Requested telnet close");
-           ctx->major_state = 1;
+           htx->major_state = 1;
            break;
 
          case 5: /* machine creation request */
            if (ctx->type != 5)
              CBOR_PARSER_ERROR("Expected mapping, got %u", ctx->type);
 
-           ctx->major_state = 501;
+           htx->major_state = 501;
            break;
 
          case 6: /* machine shutdown request */
            if (ctx->type != 5)
              CBOR_PARSER_ERROR("Expecting mapping, got %u", ctx->type);
 
-           ctx->major_state = 601;
+           htx->major_state = 601;
            break;
 
          case 7: /* process spawner */
@@ -235,21 +156,21 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->value >= 5)
              CBOR_PARSER_ERROR("Command key too high, got %lu", ctx->value);
 
-           ctx->major_state = ctx->value + 502;
+           htx->major_state = ctx->value + 502;
            break;
 
          case 502: /* machine creation argument 0: name */
            if (ctx->type != 3)
              CBOR_PARSER_ERROR("Expected string, got %u", ctx->type);
 
-           if (value_is_special)
+           if (ctx->tflags & CPT_VARLEN)
              CBOR_PARSER_ERROR("Variable length string not supported yet");
 
-           if (ctx->cfg.cf.name)
+           if (htx->cfg.cf.name)
              CBOR_PARSER_ERROR("Duplicate argument 0 / name");
 
            ASSERT_DIE(!ctx->target_buf);
-           ctx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           htx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
            ctx->target_len = ctx->value;
            break;
 
@@ -257,28 +178,28 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->type != 0)
              CBOR_PARSER_ERROR("Expected integer, got %u", ctx->type);
 
-           if (ctx->cfg.cf.type)
-             CBOR_PARSER_ERROR("Duplicate argument 1 / type, already have %d", ctx->cfg.cf.type);
+           if (htx->cfg.cf.type)
+             CBOR_PARSER_ERROR("Duplicate argument 1 / type, already have %d", htx->cfg.cf.type);
 
            if ((ctx->value < 1) && (ctx->value > 1) )
              CBOR_PARSER_ERROR("Unexpected type, got %lu", ctx->value);
 
-           ctx->cfg.cf.type = ctx->value;
-           ctx->major_state = 501;
+           htx->cfg.cf.type = ctx->value;
+           htx->major_state = 501;
            break;
 
          case 504: /* machine creation argument 2: workdir */
            if (ctx->type != 2)
              CBOR_PARSER_ERROR("Expected bytestring, got %u", ctx->type);
 
-           if (value_is_special)
+           if (ctx->tflags & CPT_VARLEN)
              CBOR_PARSER_ERROR("Variable length string not supported yet");
 
-           if (ctx->cfg.container.workdir)
+           if (htx->cfg.container.workdir)
              CBOR_PARSER_ERROR("Duplicate argument 2 / workdir");
 
            ASSERT_DIE(!ctx->target_buf);
-           ctx->cfg.container.workdir = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           htx->cfg.container.workdir = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
            ctx->target_len = ctx->value;
            break;
 
@@ -286,14 +207,14 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->type != 2)
              CBOR_PARSER_ERROR("Expected bytestring, got %u", ctx->type);
 
-           if (value_is_special)
+           if (ctx->tflags & CPT_VARLEN)
              CBOR_PARSER_ERROR("Variable length string not supported yet");
 
-           if (ctx->cfg.container.basedir)
+           if (htx->cfg.container.basedir)
              CBOR_PARSER_ERROR("Duplicate argument 3 / basedir");
 
            ASSERT_DIE(!ctx->target_buf);
-           ctx->cfg.container.basedir = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           htx->cfg.container.basedir = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
            ctx->target_len = ctx->value;
            break;
 
@@ -304,74 +225,36 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            if (ctx->value >= 1)
              CBOR_PARSER_ERROR("Command key too high, got %lu", ctx->value);
 
-           ctx->major_state = ctx->value + 602;
+           htx->major_state = ctx->value + 602;
            break;
 
          case 602: /* machine creation argument 0: name */
            if (ctx->type != 3)
              CBOR_PARSER_ERROR("Expected string, got %u", ctx->type);
 
-           if (value_is_special)
+           if (ctx->tflags & CPT_VARLEN)
              CBOR_PARSER_ERROR("Variable length string not supported yet");
 
-           if (ctx->cfg.cf.name)
+           if (htx->cfg.cf.name)
              CBOR_PARSER_ERROR("Duplicate argument 0 / name");
 
            ASSERT_DIE(!ctx->target_buf);
-           ctx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           htx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
            ctx->target_len = ctx->value;
            break;
 
          default:
            bug("invalid parser state");
        }
-
-       /* Some types are completely parsed, some not yet */
-       switch (ctx->type)
-       {
-         case 0:
-         case 1:
-         case 7:
-           exit_stack = !--ctx->stack_countdown[ctx->stack_pos];
-           ctx->partial_state = CPE_TYPE;
-           break;
-
-         case 2:
-         case 3:
-           ctx->partial_state = CPE_READ_BYTE;
-           ctx->partial_countdown = ctx->value;
-           ctx->target_buf = ctx->target_buf ?: lp_allocu(
-               ctx->lp, ctx->target_len = (ctx->target_len ?: ctx->value));
-           break;
-
-         case 4:
-         case 5:
-           if (++ctx->stack_pos >= LOCAL_STACK_MAX_DEPTH)
-             CBOR_PARSER_ERROR("Stack too deep");
-
-           /* set array/map size;
-            * once for arrays, twice for maps;
-            * ~0 for indefinite */
-           ctx->stack_countdown[ctx->stack_pos] = value_is_special ? ~0ULL :
-             (ctx->value * (ctx->type - 3));
-           ctx->partial_state = CPE_TYPE;
-           break;
-       }
-
        break;
 
-      case CPE_READ_BYTE:
-       *ctx->target_buf = bp;
-       ctx->target_buf++;
-       if (--ctx->target_len)
-         break;
-
-       /* Read completely! */
-       switch (ctx->major_state)
+      case CPR_STR_END:
+       /* Bytes read completely! */
+       switch (htx->major_state)
        {
          case 3:
-           hexp_get_telnet(ctx->sock, ctx->cfg.cf.name);
-           ctx->major_state = 1;
+           hexp_get_telnet(htx->sock, htx->cfg.cf.name);
+           htx->major_state = 1;
            break;
 
          case 5:
@@ -381,103 +264,95 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
          case 502:
          case 504:
          case 505:
-           ctx->major_state = 501;
+           htx->major_state = 501;
            break;
 
          case 602:
-           ctx->major_state = 601;
+           htx->major_state = 601;
            break;
 
          default:
            bug("Unexpected state to end a (byte)string in");
          /* Code to run at the end of a (byte)string */
        }
-
-       ctx->target_buf = NULL;
-       ctx->partial_state = CPE_TYPE;
-
-       exit_stack = !--ctx->stack_countdown[ctx->stack_pos];
+       break;
     }
 
     /* End of array or map */
-    while (exit_stack)
+    while (cbor_parse_block_end(ctx))
     {
-      switch (ctx->major_state)
+      switch (htx->major_state)
       {
        /* Code to run at the end of the mapping */
        case 0: /* toplevel item ended */
-         ctx->major_state = ~0ULL;
+         htx->major_state = ~0ULL;
          return pos + 1;
 
        case 1:
-         ctx->major_state = 0;
+         htx->major_state = 0;
          break;
 
        case 5:
          /* Finalize the command to exec in hypervisor */
          CBOR_PARSER_ERROR("NOT IMPLEMENTED YET");
-         ctx->major_state = 1;
+         htx->major_state = 1;
          break;
 
        case 501:
-         if (!ctx->cfg.cf.type)
+         if (!htx->cfg.cf.type)
            CBOR_PARSER_ERROR("Machine type not specified");
 
-         if (!ctx->cfg.cf.name)
+         if (!htx->cfg.cf.name)
            CBOR_PARSER_ERROR("Machine name not specified");
 
-         if (!ctx->cfg.container.workdir)
+         if (!htx->cfg.container.workdir)
            CBOR_PARSER_ERROR("Machine workdir not specified");
 
-         if (!ctx->cfg.container.basedir)
+         if (!htx->cfg.container.basedir)
            CBOR_PARSER_ERROR("Machine basedir not specified");
 
          hypervisor_container_request(
-             ctx->sock,
-             ctx->cfg.cf.name,
-             ctx->cfg.container.basedir,
-             ctx->cfg.container.workdir);
+             htx->sock,
+             htx->cfg.cf.name,
+             htx->cfg.container.basedir,
+             htx->cfg.container.workdir);
 
-         ctx->major_state = 1;
+         htx->major_state = 1;
          break;
 
        case 601:
-         if (!ctx->cfg.cf.name)
+         if (!htx->cfg.cf.name)
            CBOR_PARSER_ERROR("Machine name not specified");
 
-         hypervisor_container_shutdown(ctx->sock, ctx->cfg.cf.name);
+         hypervisor_container_shutdown(htx->sock, htx->cfg.cf.name);
 
-         ctx->major_state = 1;
+         htx->major_state = 1;
          break;
 
        default:
          bug("Unexpected state to end a mapping in");
       }
-
-      /* Check exit from the next item */
-      ASSERT_DIE(ctx->stack_pos);
-      exit_stack = !--ctx->stack_countdown[--ctx->stack_pos];
     }
   }
 
-  ctx->bytes_consumed += size;
+  htx->bytes_consumed += size;
   return size;
 }
 
 bool
-hcs_complete(struct cbor_parser_context *ctx)
+hcs_complete(struct hcs_parser_context *htx)
 {
-  return ctx->major_state == ~0ULL;
+  return htx->major_state == ~0ULL;
 }
 
 const char *
-hcs_error(struct cbor_parser_context *ctx)
+hcs_error(struct hcs_parser_context *htx)
 {
-  return ctx->error;
+  return htx->ctx->error;
 }
 
 void
-hcs_parser_cleanup(struct cbor_parser_context *ctx)
+hcs_parser_cleanup(struct hcs_parser_context *htx)
 {
-  rfree(ctx->lp);
+  cbor_parser_free(htx->ctx);
 }
index 1abb6c58cbd7bfd74cfa69b14e327d32172966a1..d2041ccc50a24fb69df6b24d3088a34d31a87bdd 100644 (file)
@@ -22,11 +22,11 @@ struct flock_config {
 
 extern struct flock_config flock_config;
 
-struct cbor_parser_context *hcs_parser_init(sock *s);
-s64 hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size);
-void hcs_parser_cleanup(struct cbor_parser_context *ctx);
-const char *hcs_error(struct cbor_parser_context *ctx);
-bool hcs_complete(struct cbor_parser_context *ctx);
+struct hcs_parser_context *hcs_parser_init(sock *s);
+s64 hcs_parse(struct hcs_parser_context *ctx, const byte *buf, s64 size);
+void hcs_parser_cleanup(struct hcs_parser_context *ctx);
+const char *hcs_error(struct hcs_parser_context *ctx);
+bool hcs_complete(struct hcs_parser_context *ctx);
 
 void hexp_get_telnet(sock *, const char *name);