#include "native.h"
#include <stdio.h>

UnifexState *unifex_alloc_state(UnifexEnv *_env) {
  UNIFEX_UNUSED(_env);
  return (UnifexState *)malloc(sizeof(UnifexState));
}

void unifex_release_state(UnifexEnv *env, UnifexState *state) {
  unifex_cnode_add_to_released_states(env, state);
}

void unifex_cnode_destroy_state(UnifexEnv *env, void *state) {
  handle_destroy_state(env, (UnifexState *)state);
  free(state);
}

UNIFEX_TERM init_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM add_stream_result_ok(UnifexEnv *env, unsigned int stream_id,
                                 UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "ok");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM add_stream_result_error_failed_to_add_stream(UnifexEnv *env,
                                                         UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_add_stream");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM
add_stream_result_error_invalid_stream_or_duplicate_name(UnifexEnv *env,
                                                         UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "invalid_stream_or_duplicate_name");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM add_stream_result_error_failed_to_attach_recv(UnifexEnv *env,
                                                          UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_attach_recv");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM remove_stream_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_relay_info_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_relay_info_result_error_bad_relay_type(UnifexEnv *env,
                                                       UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "bad_relay_type");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_relay_info_result_error_failed_to_set_turn(UnifexEnv *env,
                                                           UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_set_turn");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM forget_relays_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM forget_relays_result_error_component_not_found(UnifexEnv *env,
                                                           UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "component_not_found");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM generate_local_sdp_result_ok(UnifexEnv *env, char const *local_sdp,
                                         UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "ok");
  ei_x_encode_binary(out_buff, local_sdp, strlen(local_sdp));
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM parse_remote_sdp_result_ok(UnifexEnv *env,
                                       unsigned int added_cand_num,
                                       UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "ok");
  ({
    unsigned int tmp_uint = added_cand_num;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM
parse_remote_sdp_result_error_failed_to_parse_sdp(UnifexEnv *env,
                                                  UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_parse_sdp");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM get_local_credentials_result_ok(UnifexEnv *env,
                                            char const *credentials,
                                            UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "ok");
  ei_x_encode_binary(out_buff, credentials, strlen(credentials));
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM get_local_credentials_result_error_failed_to_get_credentials(
    UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_get_credentials");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_remote_credentials_result_ok(UnifexEnv *env,
                                             UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_remote_credentials_result_error_failed_to_set_credentials(
    UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_set_credentials");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM gather_candidates_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM gather_candidates_result_error_invalid_stream_or_allocation(
    UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "invalid_stream_or_allocation");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM peer_candidate_gathering_done_result_ok(UnifexEnv *env,
                                                    UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM peer_candidate_gathering_done_result_error_stream_not_found(
    UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "stream_not_found");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_remote_candidate_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM set_remote_candidate_result_error_failed_to_parse_sdp_string(
    UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_parse_sdp_string");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM
set_remote_candidate_result_error_failed_to_set(UnifexEnv *env,
                                                UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_set");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM restart_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM restart_result_error_failed_to_restart(UnifexEnv *env,
                                                   UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_restart");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM restart_stream_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM restart_stream_result_error_failed_to_restart(UnifexEnv *env,
                                                          UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_restart");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM send_payload_result_ok(UnifexEnv *env, UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_atom(out_buff, "ok");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM send_payload_result_error_failed_to_send(UnifexEnv *env,
                                                     UnifexState *state) {
  UNIFEX_TERM out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  unifex_cnode_prepare_ei_x_buff(env, out_buff, "result");

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "error");
  ei_x_encode_atom(out_buff, "failed_to_send");
  {
    UnifexState *unifex_state = state;
    env->state = unifex_state;
  };

  return out_buff;
}

UNIFEX_TERM init_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  char **stun_servers;
  unsigned int stun_servers_length;
  int controlling_mode;
  unsigned int min_port;
  unsigned int max_port;
  stun_servers = NULL;

  if (({
        int type;
        int size;

        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        stun_servers_length = (unsigned int)size;

        int index = 0;
        UnifexCNodeInBuff unifex_buff;
        UnifexCNodeInBuff *unifex_buff_ptr = &unifex_buff;
        if (type == ERL_STRING_EXT) {
          ei_x_buff buff =
              unifex_cnode_string_to_list(in_buff, stun_servers_length);
          unifex_buff.buff = buff.buff;
          unifex_buff.index = &index;
        } else {
          unifex_buff.buff = in_buff->buff;
          unifex_buff.index = in_buff->index;
        }
        int header_res = ei_decode_list_header(unifex_buff_ptr->buff,
                                               unifex_buff_ptr->index, &size);
        stun_servers_length = (unsigned int)size;
        stun_servers = (char **)malloc(sizeof(char *) * stun_servers_length);

        for (unsigned int i = 0; i < stun_servers_length; i++) {
          stun_servers[i] = NULL;
        }

        for (unsigned int i = 0; i < stun_servers_length; i++) {
          if (({
                int type;
                int size;
                long len;
                ei_get_type(unifex_buff_ptr->buff, unifex_buff_ptr->index,
                            &type, &size);
                size = size + 1; // for NULL byte
                stun_servers[i] = (char *)malloc(sizeof(char) * size);
                memset(stun_servers[i], 0, size);
                ei_decode_binary(unifex_buff_ptr->buff, unifex_buff_ptr->index,
                                 stun_servers[i], &len);
              })) {
            result =
                unifex_raise(env, "Unifex CNode: cannot parse argument "
                                  "'stun_servers' of type '{:list, :string}'");
            goto exit_init_caller;
          }
        }
        if (stun_servers_length) {
          header_res = ei_decode_list_header(unifex_buff_ptr->buff,
                                             unifex_buff_ptr->index, &size);
        }
        header_res;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'stun_servers' of type '{:list, :string}'");
    goto exit_init_caller;
  }

  if (({
        int res = -1;
        char boolean_str[6];
        ei_decode_atom(in_buff->buff, in_buff->index, boolean_str);

        if (strcmp(boolean_str, "true") == 0) {
          controlling_mode = 1;
          res = 0;
        } else if (strcmp(boolean_str, "false") == 0) {
          controlling_mode = 0;
          res = 0;
        }
        res;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'controlling_mode' of type ':bool'");
    goto exit_init_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        min_port = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'min_port' of type ':unsigned'");
    goto exit_init_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        max_port = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'max_port' of type ':unsigned'");
    goto exit_init_caller;
  }

  result = init(env, stun_servers, stun_servers_length, controlling_mode,
                min_port, max_port);
  goto exit_init_caller;
exit_init_caller:
  if (stun_servers != NULL) {
    for (unsigned int i = 0; i < stun_servers_length; i++) {
      unifex_free(stun_servers[i]);
    }
    unifex_free(stun_servers);
  }

  return result;
}

UNIFEX_TERM add_stream_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int n_components;
  char *name;

  name = NULL;
  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_add_stream_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        n_components = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'n_components' of type ':unsigned'");
    goto exit_add_stream_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        name = (char *)malloc(sizeof(char) * size);
        memset(name, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, name, &len);
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'name' of type ':string'");
    goto exit_add_stream_caller;
  }

  result = add_stream(env, state, n_components, name);
  goto exit_add_stream_caller;
exit_add_stream_caller:
  unifex_free(name);
  return result;
}

UNIFEX_TERM remove_stream_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_remove_stream_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_remove_stream_caller;
  }

  result = remove_stream(env, state, stream_id);
  goto exit_remove_stream_caller;
exit_remove_stream_caller:

  return result;
}

UNIFEX_TERM set_relay_info_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;
  unsigned int component_id;
  char *server_ip;
  unsigned int server_port;
  char *username;
  char *password;
  char *relay_type;

  server_ip = NULL;

  username = NULL;
  password = NULL;
  relay_type = NULL;
  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_set_relay_info_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_set_relay_info_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        component_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'component_id' of type ':unsigned'");
    goto exit_set_relay_info_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        server_ip = (char *)malloc(sizeof(char) * size);
        memset(server_ip, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, server_ip, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'server_ip' of type ':string'");
    goto exit_set_relay_info_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        server_port = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'server_port' of type ':unsigned'");
    goto exit_set_relay_info_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        username = (char *)malloc(sizeof(char) * size);
        memset(username, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, username, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'username' of type ':string'");
    goto exit_set_relay_info_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        password = (char *)malloc(sizeof(char) * size);
        memset(password, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, password, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'password' of type ':string'");
    goto exit_set_relay_info_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        relay_type = (char *)malloc(sizeof(char) * size);
        memset(relay_type, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, relay_type, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'relay_type' of type ':string'");
    goto exit_set_relay_info_caller;
  }

  result = set_relay_info(env, state, stream_id, component_id, server_ip,
                          server_port, username, password, relay_type);
  goto exit_set_relay_info_caller;
exit_set_relay_info_caller:
  unifex_free(server_ip);
  unifex_free(username);
  unifex_free(password);
  unifex_free(relay_type);
  return result;
}

UNIFEX_TERM forget_relays_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;
  unsigned int component_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_forget_relays_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_forget_relays_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        component_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'component_id' of type ':unsigned'");
    goto exit_forget_relays_caller;
  }

  result = forget_relays(env, state, stream_id, component_id);
  goto exit_forget_relays_caller;
exit_forget_relays_caller:

  return result;
}

UNIFEX_TERM generate_local_sdp_caller(UnifexEnv *env,
                                      UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_generate_local_sdp_caller;
  }

  result = generate_local_sdp(env, state);
  goto exit_generate_local_sdp_caller;
exit_generate_local_sdp_caller:

  return result;
}

UNIFEX_TERM parse_remote_sdp_caller(UnifexEnv *env,
                                    UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  char *remote_sdp;

  remote_sdp = NULL;
  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_parse_remote_sdp_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        remote_sdp = (char *)malloc(sizeof(char) * size);
        memset(remote_sdp, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, remote_sdp, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'remote_sdp' of type ':string'");
    goto exit_parse_remote_sdp_caller;
  }

  result = parse_remote_sdp(env, state, remote_sdp);
  goto exit_parse_remote_sdp_caller;
exit_parse_remote_sdp_caller:
  unifex_free(remote_sdp);
  return result;
}

UNIFEX_TERM get_local_credentials_caller(UnifexEnv *env,
                                         UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_get_local_credentials_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_get_local_credentials_caller;
  }

  result = get_local_credentials(env, state, stream_id);
  goto exit_get_local_credentials_caller;
exit_get_local_credentials_caller:

  return result;
}

UNIFEX_TERM set_remote_credentials_caller(UnifexEnv *env,
                                          UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  char *credentials;
  unsigned int stream_id;

  credentials = NULL;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_set_remote_credentials_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        credentials = (char *)malloc(sizeof(char) * size);
        memset(credentials, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, credentials, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'credentials' of type ':string'");
    goto exit_set_remote_credentials_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_set_remote_credentials_caller;
  }

  result = set_remote_credentials(env, state, credentials, stream_id);
  goto exit_set_remote_credentials_caller;
exit_set_remote_credentials_caller:
  unifex_free(credentials);
  return result;
}

UNIFEX_TERM gather_candidates_caller(UnifexEnv *env,
                                     UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_gather_candidates_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_gather_candidates_caller;
  }

  result = gather_candidates(env, state, stream_id);
  goto exit_gather_candidates_caller;
exit_gather_candidates_caller:

  return result;
}

UNIFEX_TERM peer_candidate_gathering_done_caller(UnifexEnv *env,
                                                 UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_peer_candidate_gathering_done_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_peer_candidate_gathering_done_caller;
  }

  result = peer_candidate_gathering_done(env, state, stream_id);
  goto exit_peer_candidate_gathering_done_caller;
exit_peer_candidate_gathering_done_caller:

  return result;
}

UNIFEX_TERM set_remote_candidate_caller(UnifexEnv *env,
                                        UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  char *candidate;
  unsigned int stream_id;
  unsigned int component_id;

  candidate = NULL;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_set_remote_candidate_caller;
  }

  if (({
        int type;
        int size;
        long len;
        ei_get_type(in_buff->buff, in_buff->index, &type, &size);
        size = size + 1; // for NULL byte
        candidate = (char *)malloc(sizeof(char) * size);
        memset(candidate, 0, size);
        ei_decode_binary(in_buff->buff, in_buff->index, candidate, &len);
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'candidate' of type ':string'");
    goto exit_set_remote_candidate_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_set_remote_candidate_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        component_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'component_id' of type ':unsigned'");
    goto exit_set_remote_candidate_caller;
  }

  result = set_remote_candidate(env, state, candidate, stream_id, component_id);
  goto exit_set_remote_candidate_caller;
exit_set_remote_candidate_caller:
  unifex_free(candidate);
  return result;
}

UNIFEX_TERM restart_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_restart_caller;
  }

  result = restart(env, state);
  goto exit_restart_caller;
exit_restart_caller:

  return result;
}

UNIFEX_TERM restart_stream_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;

  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_restart_stream_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_restart_stream_caller;
  }

  result = restart_stream(env, state, stream_id);
  goto exit_restart_stream_caller;
exit_restart_stream_caller:

  return result;
}

UNIFEX_TERM send_payload_caller(UnifexEnv *env, UnifexCNodeInBuff *in_buff) {
  UNIFEX_MAYBE_UNUSED(in_buff);
  UNIFEX_TERM result;
  UnifexState *state;
  unsigned int stream_id;
  unsigned int component_id;
  UnifexPayload *data;

  data = NULL;
  if (({
        state = (UnifexState *)env->state;
        0;
      })) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'state' of type ':state'");
    goto exit_send_payload_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        stream_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(
        env,
        "Unifex CNode: cannot parse argument 'stream_id' of type ':unsigned'");
    goto exit_send_payload_caller;
  }

  if (({
        unsigned long long tmp_ulonglong;
        int result =
            ei_decode_ulonglong(in_buff->buff, in_buff->index, &tmp_ulonglong);
        component_id = (unsigned int)tmp_ulonglong;
        result;
      })) {
    result = unifex_raise(env, "Unifex CNode: cannot parse argument "
                               "'component_id' of type ':unsigned'");
    goto exit_send_payload_caller;
  }

  if (unifex_payload_decode(env, in_buff, &data)) {
    result = unifex_raise(
        env, "Unifex CNode: cannot parse argument 'data' of type ':payload'");
    goto exit_send_payload_caller;
  }

  result = send_payload(env, state, stream_id, component_id, data);
  goto exit_send_payload_caller;
exit_send_payload_caller:
  if (data && !data->owned) {
    unifex_payload_release(data);
  }

  return result;
}

int send_new_candidate_full(UnifexEnv *env, UnifexPid pid, int flags,
                            char const *candidate) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "new_candidate_full");
  ei_x_encode_binary(out_buff, candidate, strlen(candidate));

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_new_remote_candidate_full(UnifexEnv *env, UnifexPid pid, int flags,
                                   char const *candidate) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "new_remote_candidate_full");
  ei_x_encode_binary(out_buff, candidate, strlen(candidate));

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_candidate_gathering_done(UnifexEnv *env, UnifexPid pid, int flags,
                                  unsigned int stream_id) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 2);
  ei_x_encode_atom(out_buff, "candidate_gathering_done");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_new_selected_pair(UnifexEnv *env, UnifexPid pid, int flags,
                           unsigned int stream_id, unsigned int component_id,
                           char const *lfoundation, char const *rfoundation) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 5);
  ei_x_encode_atom(out_buff, "new_selected_pair");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  ({
    unsigned int tmp_uint = component_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  ei_x_encode_binary(out_buff, lfoundation, strlen(lfoundation));
  ei_x_encode_binary(out_buff, rfoundation, strlen(rfoundation));

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_component_state_failed(UnifexEnv *env, UnifexPid pid, int flags,
                                unsigned int stream_id,
                                unsigned int component_id) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 3);
  ei_x_encode_atom(out_buff, "component_state_failed");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  ({
    unsigned int tmp_uint = component_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_component_state_ready(UnifexEnv *env, UnifexPid pid, int flags,
                               unsigned int stream_id,
                               unsigned int component_id) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 3);
  ei_x_encode_atom(out_buff, "component_state_ready");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  ({
    unsigned int tmp_uint = component_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

int send_ice_payload(UnifexEnv *env, UnifexPid pid, int flags,
                     unsigned int stream_id, unsigned int component_id,
                     UnifexPayload *payload) {
  UNIFEX_UNUSED(flags);
  ei_x_buff *out_buff = (ei_x_buff *)malloc(sizeof(ei_x_buff));
  ei_x_new_with_version(out_buff);

  ei_x_encode_tuple_header(out_buff, 4);
  ei_x_encode_atom(out_buff, "ice_payload");
  ({
    unsigned int tmp_uint = stream_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  ({
    unsigned int tmp_uint = component_id;
    ei_x_encode_ulonglong(out_buff, (unsigned long long)tmp_uint);
  });

  unifex_payload_encode(env, out_buff, payload);

  unifex_cnode_send_and_free(env, &pid, out_buff);
  return 1;
}

UNIFEX_TERM unifex_cnode_handle_message(UnifexEnv *env, char *fun_name,
                                        UnifexCNodeInBuff *in_buff) {
  if (strcmp(fun_name, "init") == 0) {
    return init_caller(env, in_buff);
  } else if (strcmp(fun_name, "add_stream") == 0) {
    return add_stream_caller(env, in_buff);
  } else if (strcmp(fun_name, "remove_stream") == 0) {
    return remove_stream_caller(env, in_buff);
  } else if (strcmp(fun_name, "set_relay_info") == 0) {
    return set_relay_info_caller(env, in_buff);
  } else if (strcmp(fun_name, "forget_relays") == 0) {
    return forget_relays_caller(env, in_buff);
  } else if (strcmp(fun_name, "generate_local_sdp") == 0) {
    return generate_local_sdp_caller(env, in_buff);
  } else if (strcmp(fun_name, "parse_remote_sdp") == 0) {
    return parse_remote_sdp_caller(env, in_buff);
  } else if (strcmp(fun_name, "get_local_credentials") == 0) {
    return get_local_credentials_caller(env, in_buff);
  } else if (strcmp(fun_name, "set_remote_credentials") == 0) {
    return set_remote_credentials_caller(env, in_buff);
  } else if (strcmp(fun_name, "gather_candidates") == 0) {
    return gather_candidates_caller(env, in_buff);
  } else if (strcmp(fun_name, "peer_candidate_gathering_done") == 0) {
    return peer_candidate_gathering_done_caller(env, in_buff);
  } else if (strcmp(fun_name, "set_remote_candidate") == 0) {
    return set_remote_candidate_caller(env, in_buff);
  } else if (strcmp(fun_name, "restart") == 0) {
    return restart_caller(env, in_buff);
  } else if (strcmp(fun_name, "restart_stream") == 0) {
    return restart_stream_caller(env, in_buff);
  } else if (strcmp(fun_name, "send_payload") == 0) {
    return send_payload_caller(env, in_buff);
  } else {
    return unifex_cnode_undefined_function_error(env, fun_name);
  }
}

int main(int argc, char **argv) {
  return unifex_cnode_main_function(argc, argv);
}
