Пример #1
0
void sig_notify(int itf,int up)
{
    SIGNALING_ENTITY *sig;

    for (sig = entities; sig; sig = sig->next)
	if (sig->itf == itf) break;
    if (!sig) {
	diag(COMPONENT,DIAG_ERROR,"%s notification for unknown interface %d",
	  up ? "up" : "down",itf);
	return;
    }
    if (sig->pvc.sap_addr.itf == -1) return;
    if (up) {
	struct atm_qos qos;

	sig->call = new_call();
	sig->call->in.pvc = sig->pvc;
	sig->call->out.pvc.sap_addr.itf = sig->itf;
	sig->call->out.pvc.sap_addr.vpi = 0;
	sig->call->out.pvc.sap_addr.vci = 5;
	memset(&qos,0,sizeof(qos));
	qos.txtp.traffic_class = qos.rxtp.traffic_class = ATM_UBR;
	fab_op(sig->call,RM_CLAIM(_RM_ANY),&qos,up_callback,sig);
    }
    else {
	route_sig(sig,&sig->call->out.pvc,0);
	remove_entity(sig);
	fab_op(sig->call,RM_FREE,NULL,down_callback,NULL);
	free_call(sig->call);
    }
}
Пример #2
0
struct call *lac_call (int tid, struct lac *lac, struct lns *lns)
{
    struct tunnel *t = tunnels.head;
    struct call *tmp;
    while (t)
    {
        if (t->ourtid == tid)
        {
            tmp = new_call (t);
            if (!tmp)
            {
                log (LOG_WARN, "%s: unable to create new call\n",
                     __FUNCTION__);
                return NULL;
            }
            tmp->next = t->call_head;
            t->call_head = tmp;
            t->count++;
            tmp->cid = 0;
            tmp->lac = lac;
            tmp->lns = lns;
            if (lac)
                lac->c = tmp;
            log (LOG_NOTICE, "Calling on tunnel %d\n", tid);
            strcpy (tmp->dial_no, dial_no_tmp); /*  jz: copy dialnumber to tmp->dial_no  */
            control_finish (t, tmp);
            return tmp;
        }
        t = t->next;
    };
    log (LOG_DEBUG, "%s: No such tunnel %d to generate call.\n", __FUNCTION__,
         tid);
    return NULL;
}
Пример #3
0
/*
 * This will be with every control message.  It is critical that this
 * procedure check for the validity of sending this kind of a message
 * (assuming sanity check)
 */
int message_type_avp(struct tunnel *t, struct call *c, const struct avp *data,
		     int datalen)
{
	struct call *tmp;
	c->msgtype = ntohs(data->data.us);

	if (datalen != 8)
	{
		l2tp_log(LOG_DEBUG, "%s: wrong size (%d != 8)\n", __func__,
			 datalen);
		wrong_length(c, "Message Type", 8, datalen, 0);
		return -EINVAL;
	}

	/* This is handled in sanity_failed now. May use it. */
	if ((c->msgtype > MAX_MSG) || (!msgtypes[c->msgtype]))
	{
		l2tp_log(LOG_DEBUG, "%s: unknown message type %d\n", __func__,
			 c->msgtype);
		return -EINVAL;
	}

	if (gconfig.debug_avp)
		l2tp_log(LOG_DEBUG, "%s: message type %d (%s)\n", __func__,
			c->msgtype, msgtypes[c->msgtype]);

	if (sanity_enabled(t) && mta_sanity_failed(t, c))
		return -EINVAL;

	if (c->msgtype != ICRQ)
		return 0;

	if (gconfig.debug_avp)
		l2tp_log(LOG_DEBUG, "%s: new incoming call\n", __func__);

	tmp = new_call(t);

	if (!tmp)
	{
		l2tp_log(LOG_WARNING, "%s: unable to create new call\n", __func__);
		return -EINVAL;
	}

	tmp->next = t->call_head;
	t->call_head = tmp;
	t->count++;

	/*
	 * Is this still safe to assume that the head will always
	 * be the most recent call being negotiated?
	 * Probably...  FIXME anyway...
	 */

	return 0;
}
Пример #4
0
void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object)
{
    LOGGER_DEBUG(m->log, "Got msi message");

    MSISession *session = (MSISession *)object;
    MSIMessage msg;

    if (msg_parse_in(m->log, &msg, data, length) == -1) {
        LOGGER_WARNING(m->log, "Error parsing message");
        send_error(m, friend_number, msi_EInvalidMessage);
        return;
    }

    LOGGER_DEBUG(m->log, "Successfully parsed message");

    pthread_mutex_lock(session->mutex);
    MSICall *call = get_call(session, friend_number);

    if (call == NULL) {
        if (msg.request.value != requ_init) {
            send_error(m, friend_number, msi_EStrayMessage);
            pthread_mutex_unlock(session->mutex);
            return;
        }

        call = new_call(session, friend_number);

        if (call == NULL) {
            send_error(m, friend_number, msi_ESystem);
            pthread_mutex_unlock(session->mutex);
            return;
        }
    }

    switch (msg.request.value) {
        case requ_init:
            handle_init(call, &msg);
            break;

        case requ_push:
            handle_push(call, &msg);
            break;

        case requ_pop:
            handle_pop(call, &msg); /* always kills the call */
            break;
    }

    pthread_mutex_unlock(session->mutex);
}
Пример #5
0
struct tunnel *new_tunnel ()
{
    struct tunnel *tmp = calloc (1, sizeof (struct tunnel));
    unsigned char entropy_buf[2] = "\0";
    if (!tmp)
        return NULL;
    tmp->debug = 0;
    tmp->tid = -1;
    memset(&tmp->rt, 0, sizeof(tmp->rt));
#ifndef TESTING
/*      while(get_call((tmp->ourtid = rand() & 0xFFFF),0,0,0)); */
/*        tmp->ourtid = rand () & 0xFFFF; */
        /* get_entropy((char *)&tmp->ourtid, 2); */
        get_entropy(entropy_buf, 2);
        {
            unsigned short *temp;
            temp = (unsigned short *)entropy_buf;
            tmp->ourtid = *temp & 0xFFFF;
#ifdef DEBUG_ENTROPY
            l2tp_log(LOG_DEBUG, "ourtid = %u, entropy_buf = %hx\n", tmp->ourtid, *temp);
#endif
        }

#else
    tmp->ourtid = 0x6227;
#endif
    tmp->peer.sin_family = AF_INET;
    bzero (&(tmp->peer.sin_addr), sizeof (tmp->peer.sin_addr));
#ifdef SANITY
    tmp->sanity = -1;
#endif
    tmp->qtid = -1;
    tmp->ourfc = ASYNC_FRAMING | SYNC_FRAMING;
    tmp->ourtb = (((_u64) rand ()) << 32) | ((_u64) rand ());
    tmp->fc = -1;               /* These really need to be specified by the peer */
    tmp->bc = -1;               /* And we want to know if they forgot */
    if (!(tmp->self = new_call (tmp)))
    {
        free (tmp);
        return NULL;
    };
    tmp->ourrws = DEFAULT_RWS_SIZE;
    tmp->self->ourfbit = FBIT;
    tmp->rxspeed = DEFAULT_RX_BPS;
    tmp->txspeed = DEFAULT_TX_BPS;
    memset (tmp->chal_us.reply, 0, MD_SIG_SIZE);
    memset (tmp->chal_them.reply, 0, MD_SIG_SIZE);
    tmp->chal_them.vector = (unsigned char *) malloc (VECTOR_SIZE);
    return tmp;
}
Пример #6
0
int messages_get_message(void *s, const char *h, unsigned long flags,
				messages_get_message_cb cb, void *user_data)
{
	struct session *session = s;
	struct request *request;
	DBusPendingCall *call;
	int err = 0;
	char *handle = strip_handle(h);
	char *query_handle = g_strdup_printf(MESSAGES_FILTER_BY_HANDLE, handle);
	char *query = path2query("telecom/msg", LIST_MESSAGES_QUERY,
								 query_handle);

	if (query == NULL) {
		err = -ENOENT;

		goto failed;
	}

	if (flags & MESSAGES_FRACTION || flags & MESSAGES_NEXT) {
		err = -EBADR;

		goto failed;
	}

	request = g_new0(struct request, 1);

	request->name = g_strdup(handle);
	request->flags = flags;
	request->cb.message = cb;
	request->generate_response = get_message_resp;
	request->user_data = user_data;

	session->aborted = FALSE;
	session->request = request;

	call = query_tracker(query, session, &err);
	if (err == 0)
		new_call(call);

failed:
	g_free(query_handle);
	g_free(query);
	g_free(handle);

	return err;
}
Пример #7
0
int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities)
{
    if (!session) {
        return -1;
    }

    LOGGER_DEBUG(session->messenger->log, "Session: %p Inviting friend: %u", session, friend_number);

    if (pthread_mutex_trylock(session->mutex) != 0) {
        LOGGER_ERROR(session->messenger->log, "Failed to aquire lock on msi mutex");
        return -1;
    }

    if (get_call(session, friend_number) != NULL) {
        LOGGER_ERROR(session->messenger->log, "Already in a call");
        pthread_mutex_unlock(session->mutex);
        return -1;
    }

    (*call) = new_call(session, friend_number);

    if (*call == NULL) {
        pthread_mutex_unlock(session->mutex);
        return -1;
    }

    (*call)->self_capabilities = capabilities;

    MSIMessage msg;
    msg_init(&msg, requ_init);

    msg.capabilities.exists = true;
    msg.capabilities.value = capabilities;

    send_message((*call)->session->messenger, (*call)->friend_number, &msg);

    (*call)->state = msi_CallRequesting;

    LOGGER_DEBUG(session->messenger->log, "Invite sent");
    pthread_mutex_unlock(session->mutex);
    return 0;
}
Пример #8
0
struct tunnel *new_tunnel ()
{
    struct tunnel *tmp = malloc (sizeof (struct tunnel));
    char entropy_buf[2] = "\0";
    if (!tmp)
        return NULL;
    tmp->control_seq_num = 0;
    tmp->control_rec_seq_num = 0;
    tmp->cLr = 0;
    tmp->call_head = NULL;
    tmp->next = NULL;
    tmp->debug = -1;
    tmp->tid = -1;
    tmp->hello = NULL;
#ifndef TESTING
/*	while(get_call((tmp->ourtid = rand() & 0xFFFF),0,0,0)); */
#ifdef USE_KERNEL
    if (kernel_support)
        tmp->ourtid = ioctl (server_socket, L2TPIOCADDTUNNEL, 0);
    else
#endif
/*        tmp->ourtid = rand () & 0xFFFF; */
        /* get_entropy((char *)&tmp->ourtid, 2); */
        get_entropy(entropy_buf, 2);
        {
            unsigned short *temp;
            temp = (unsigned short *)entropy_buf;
            tmp->ourtid = *temp & 0xFFFF;
#ifdef DEBUG_ENTROPY
            log(LOG_DEBUG, "ourtid = %u, entropy_buf = %hx\n", tmp->ourtid, *temp);
#endif
        }

#else
    tmp->ourtid = 0x6227;
#endif
    tmp->nego = 0;
    tmp->count = 0;
    tmp->state = 0;             /* Nothing */
    tmp->peer.sin_family = AF_INET;
    tmp->peer.sin_port = 0;
    bzero (&(tmp->peer.sin_addr), sizeof (tmp->peer.sin_addr));
    tmp->sanity = -1;
    tmp->qtid = -1;
    tmp->ourfc = ASYNC_FRAMING | SYNC_FRAMING;
    tmp->ourbc = 0;
    tmp->ourtb = (((_u64) rand ()) << 32) | ((_u64) rand ());
    tmp->fc = -1;               /* These really need to be specified by the peer */
    tmp->bc = -1;               /* And we want to know if they forgot */
    tmp->hostname[0] = 0;
    tmp->vendor[0] = 0;
    tmp->secret[0] = 0;
    if (!(tmp->self = new_call (tmp)))
    {
        free (tmp);
        return NULL;
    };
    tmp->ourrws = DEFAULT_RWS_SIZE;
    tmp->self->ourfbit = FBIT;
    tmp->lac = NULL;
    tmp->lns = NULL;
    tmp->chal_us.state = 0;
    tmp->chal_us.secret[0] = 0;
    memset (tmp->chal_us.reply, 0, MD_SIG_SIZE);
    tmp->chal_us.challenge = NULL;
    tmp->chal_us.chal_len = 0;
    tmp->chal_them.state = 0;
    tmp->chal_them.secret[0] = 0;
    memset (tmp->chal_them.reply, 0, MD_SIG_SIZE);
    tmp->chal_them.challenge = NULL;
    tmp->chal_them.chal_len = 0;
    tmp->chal_them.vector = (unsigned char *) malloc (VECTOR_SIZE);
    tmp->chal_us.vector = NULL;
    tmp->hbit = 0;
    return tmp;
}
Пример #9
0
int messages_get_messages_listing(void *s, const char *name,
				uint16_t max, uint16_t offset,
				const struct messages_filter *filter,
				messages_get_messages_listing_cb callback,
				void *user_data)
{
	struct session *session = s;
	struct request *request;
	char *path, *query;
	struct message_folder *folder = NULL;
	DBusPendingCall *call;
	int err = 0;

	if (name == NULL || strlen(name) == 0) {
		path = g_strdup(session->cwd);

		folder = session->folder;
		if (folder == NULL)
			folder = get_folder(path);
	} else {
		if (strchr(name, '/') != NULL)
			return -EBADR;

		path = g_build_filename(session->cwd, name, NULL);
		folder = get_folder(path);
	}

	g_free(path);

	if (folder == NULL)
		return -ENOENT;

	query = folder2query(folder, LIST_MESSAGES_QUERY);
	if (query == NULL)
		return -ENOENT;

	request = g_new0(struct request, 1);

	request->filter = copy_messages_filter(filter);
	request->generate_response = get_messages_listing_resp;
	request->cb.messages_list = callback;
	request->offset = offset;
	request->max = max;
	request->user_data = user_data;

	session->aborted = FALSE;
	session->request = request;

	if (max == 0) {
		request->max = 0xffff;
		request->offset = 0;
		request->count = TRUE;
	}

	call = query_tracker(query, session, &err);
	if (err == 0)
		new_call(call);

	g_free(query);

	return err;
}
Пример #10
0
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  grpc_test_only_set_metadata_hash_seed(0);
  if (squelch) gpr_set_log_function(dont_log);
  input_stream inp = {data, data + size};
  grpc_resolve_address = my_resolve_address;
  grpc_tcp_client_connect_impl = my_tcp_client_connect;
  gpr_now_impl = now_impl;
  grpc_init();

  GPR_ASSERT(g_channel == NULL);
  GPR_ASSERT(g_server == NULL);

  bool server_shutdown = false;
  int pending_server_shutdowns = 0;
  int pending_channel_watches = 0;
  int pending_pings = 0;

  g_active_call = new_call(NULL, ROOT);

  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);

  while (!is_eof(&inp) || g_channel != NULL || g_server != NULL ||
         pending_channel_watches > 0 || pending_pings > 0 ||
         g_active_call->type != ROOT || g_active_call->next != g_active_call) {
    if (is_eof(&inp)) {
      if (g_channel != NULL) {
        grpc_channel_destroy(g_channel);
        g_channel = NULL;
      }
      if (g_server != NULL) {
        if (!server_shutdown) {
          grpc_server_shutdown_and_notify(
              g_server, cq, create_validator(assert_success_and_decrement,
                                             &pending_server_shutdowns));
          server_shutdown = true;
          pending_server_shutdowns++;
        } else if (pending_server_shutdowns == 0) {
          grpc_server_destroy(g_server);
          g_server = NULL;
        }
      }
      call_state *s = g_active_call;
      do {
        if (s->type != PENDING_SERVER && s->call != NULL) {
          s = destroy_call(s);
        } else {
          s = s->next;
        }
      } while (s != g_active_call);

      g_now = gpr_time_add(g_now, gpr_time_from_seconds(1, GPR_TIMESPAN));
    }

    switch (next_byte(&inp)) {
      // terminate on bad bytes
      default:
        end(&inp);
        break;
      // tickle completion queue
      case 0: {
        grpc_event ev = grpc_completion_queue_next(
            cq, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
        switch (ev.type) {
          case GRPC_OP_COMPLETE: {
            validator *v = ev.tag;
            v->validate(v->arg, ev.success);
            gpr_free(v);
            break;
          }
          case GRPC_QUEUE_TIMEOUT:
            break;
          case GRPC_QUEUE_SHUTDOWN:
            abort();
            break;
        }
        break;
      }
      // increment global time
      case 1: {
        g_now = gpr_time_add(
            g_now, gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));
        break;
      }
      // create an insecure channel
      case 2: {
        if (g_channel == NULL) {
          char *target = read_string(&inp);
          char *target_uri;
          gpr_asprintf(&target_uri, "dns:%s", target);
          grpc_channel_args *args = read_args(&inp);
          g_channel = grpc_insecure_channel_create(target_uri, args, NULL);
          GPR_ASSERT(g_channel != NULL);
          grpc_channel_args_destroy(args);
          gpr_free(target_uri);
          gpr_free(target);
        } else {
          end(&inp);
        }
        break;
      }
      // destroy a channel
      case 3: {
        if (g_channel != NULL) {
          grpc_channel_destroy(g_channel);
          g_channel = NULL;
        } else {
          end(&inp);
        }
        break;
      }
      // bring up a server
      case 4: {
        if (g_server == NULL) {
          grpc_channel_args *args = read_args(&inp);
          g_server = grpc_server_create(args, NULL);
          GPR_ASSERT(g_server != NULL);
          grpc_channel_args_destroy(args);
          grpc_server_register_completion_queue(g_server, cq, NULL);
          grpc_server_start(g_server);
          server_shutdown = false;
          GPR_ASSERT(pending_server_shutdowns == 0);
        } else {
          end(&inp);
        }
      }
      // begin server shutdown
      case 5: {
        if (g_server != NULL) {
          grpc_server_shutdown_and_notify(
              g_server, cq, create_validator(assert_success_and_decrement,
                                             &pending_server_shutdowns));
          pending_server_shutdowns++;
          server_shutdown = true;
        } else {
          end(&inp);
        }
        break;
      }
      // cancel all calls if shutdown
      case 6: {
        if (g_server != NULL && server_shutdown) {
          grpc_server_cancel_all_calls(g_server);
        } else {
          end(&inp);
        }
        break;
      }
      // destroy server
      case 7: {
        if (g_server != NULL && server_shutdown &&
            pending_server_shutdowns == 0) {
          grpc_server_destroy(g_server);
          g_server = NULL;
        } else {
          end(&inp);
        }
        break;
      }
      // check connectivity
      case 8: {
        if (g_channel != NULL) {
          uint8_t try_to_connect = next_byte(&inp);
          if (try_to_connect == 0 || try_to_connect == 1) {
            grpc_channel_check_connectivity_state(g_channel, try_to_connect);
          } else {
            end(&inp);
          }
        } else {
          end(&inp);
        }
        break;
      }
      // watch connectivity
      case 9: {
        if (g_channel != NULL) {
          grpc_connectivity_state st =
              grpc_channel_check_connectivity_state(g_channel, 0);
          if (st != GRPC_CHANNEL_FATAL_FAILURE) {
            gpr_timespec deadline = gpr_time_add(
                gpr_now(GPR_CLOCK_REALTIME),
                gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));
            grpc_channel_watch_connectivity_state(
                g_channel, st, deadline, cq,
                create_validator(validate_connectivity_watch,
                                 make_connectivity_watch(
                                     deadline, &pending_channel_watches)));
            pending_channel_watches++;
          }
        } else {
          end(&inp);
        }
        break;
      }
      // create a call
      case 10: {
        bool ok = true;
        if (g_channel == NULL) ok = false;
        grpc_call *parent_call = NULL;
        if (g_active_call->type != ROOT) {
          if (g_active_call->call == NULL || g_active_call->type == CLIENT) {
            end(&inp);
            break;
          }
          parent_call = g_active_call->call;
        }
        uint32_t propagation_mask = read_uint32(&inp);
        char *method = read_string(&inp);
        char *host = read_string(&inp);
        gpr_timespec deadline =
            gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                         gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));

        if (ok) {
          call_state *cs = new_call(g_active_call, CLIENT);
          cs->call =
              grpc_channel_create_call(g_channel, parent_call, propagation_mask,
                                       cq, method, host, deadline, NULL);
        } else {
          end(&inp);
        }
        gpr_free(method);
        gpr_free(host);
        break;
      }
      // switch the 'current' call
      case 11: {
        g_active_call = g_active_call->next;
        break;
      }
      // queue some ops on a call
      case 12: {
        if (g_active_call->type == PENDING_SERVER ||
            g_active_call->type == ROOT || g_active_call->call == NULL) {
          end(&inp);
          break;
        }
        size_t num_ops = next_byte(&inp);
        if (num_ops > 6) {
          end(&inp);
          break;
        }
        grpc_op *ops = gpr_malloc(sizeof(grpc_op) * num_ops);
        bool ok = true;
        size_t i;
        grpc_op *op;
        for (i = 0; i < num_ops; i++) {
          op = &ops[i];
          switch (next_byte(&inp)) {
            default:
              /* invalid value */
              op->op = (grpc_op_type)-1;
              ok = false;
              break;
            case GRPC_OP_SEND_INITIAL_METADATA:
              op->op = GRPC_OP_SEND_INITIAL_METADATA;
              read_metadata(&inp, &op->data.send_initial_metadata.count,
                            &op->data.send_initial_metadata.metadata,
                            g_active_call);
              break;
            case GRPC_OP_SEND_MESSAGE:
              op->op = GRPC_OP_SEND_MESSAGE;
              op->data.send_message = read_message(&inp);
              break;
            case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
              op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
              break;
            case GRPC_OP_SEND_STATUS_FROM_SERVER:
              op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
              read_metadata(
                  &inp,
                  &op->data.send_status_from_server.trailing_metadata_count,
                  &op->data.send_status_from_server.trailing_metadata,
                  g_active_call);
              op->data.send_status_from_server.status = next_byte(&inp);
              op->data.send_status_from_server.status_details =
                  read_string(&inp);
              break;
            case GRPC_OP_RECV_INITIAL_METADATA:
              op->op = GRPC_OP_RECV_INITIAL_METADATA;
              op->data.recv_initial_metadata =
                  &g_active_call->recv_initial_metadata;
              break;
            case GRPC_OP_RECV_MESSAGE:
              op->op = GRPC_OP_RECV_MESSAGE;
              op->data.recv_message = &g_active_call->recv_message;
              break;
            case GRPC_OP_RECV_STATUS_ON_CLIENT:
              op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
              op->data.recv_status_on_client.status = &g_active_call->status;
              op->data.recv_status_on_client.trailing_metadata =
                  &g_active_call->recv_trailing_metadata;
              op->data.recv_status_on_client.status_details =
                  &g_active_call->recv_status_details;
              op->data.recv_status_on_client.status_details_capacity =
                  &g_active_call->recv_status_details_capacity;
              break;
            case GRPC_OP_RECV_CLOSE_ON_SERVER:
              op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
              op->data.recv_close_on_server.cancelled =
                  &g_active_call->cancelled;
              break;
          }
          op->reserved = NULL;
          op->flags = read_uint32(&inp);
        }
        if (ok) {
          validator *v = create_validator(finished_batch, g_active_call);
          g_active_call->pending_ops++;
          grpc_call_error error =
              grpc_call_start_batch(g_active_call->call, ops, num_ops, v, NULL);
          if (error != GRPC_CALL_OK) {
            v->validate(v->arg, false);
            gpr_free(v);
          }
        } else {
          end(&inp);
        }
        for (i = 0; i < num_ops; i++) {
          op = &ops[i];
          switch (op->op) {
            case GRPC_OP_SEND_INITIAL_METADATA:
              break;
            case GRPC_OP_SEND_MESSAGE:
              grpc_byte_buffer_destroy(op->data.send_message);
              break;
            case GRPC_OP_SEND_STATUS_FROM_SERVER:
              gpr_free((void *)op->data.send_status_from_server.status_details);
              break;
            case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
            case GRPC_OP_RECV_INITIAL_METADATA:
            case GRPC_OP_RECV_MESSAGE:
            case GRPC_OP_RECV_STATUS_ON_CLIENT:
            case GRPC_OP_RECV_CLOSE_ON_SERVER:
              break;
          }
        }
        gpr_free(ops);

        break;
      }
      // cancel current call
      case 13: {
        if (g_active_call->type != ROOT && g_active_call->call != NULL) {
          grpc_call_cancel(g_active_call->call, NULL);
        } else {
          end(&inp);
        }
        break;
      }
      // get a calls peer
      case 14: {
        if (g_active_call->type != ROOT && g_active_call->call != NULL) {
          free_non_null(grpc_call_get_peer(g_active_call->call));
        } else {
          end(&inp);
        }
        break;
      }
      // get a channels target
      case 15: {
        if (g_channel != NULL) {
          free_non_null(grpc_channel_get_target(g_channel));
        } else {
          end(&inp);
        }
        break;
      }
      // send a ping on a channel
      case 16: {
        if (g_channel != NULL) {
          pending_pings++;
          grpc_channel_ping(g_channel, cq,
                            create_validator(decrement, &pending_pings), NULL);
        } else {
          end(&inp);
        }
        break;
      }
      // enable a tracer
      case 17: {
        char *tracer = read_string(&inp);
        grpc_tracer_set_enabled(tracer, 1);
        gpr_free(tracer);
        break;
      }
      // disable a tracer
      case 18: {
        char *tracer = read_string(&inp);
        grpc_tracer_set_enabled(tracer, 0);
        gpr_free(tracer);
        break;
      }
      // request a server call
      case 19: {
        if (g_server == NULL) {
          end(&inp);
          break;
        }
        call_state *cs = new_call(g_active_call, PENDING_SERVER);
        cs->pending_ops++;
        validator *v = create_validator(finished_request_call, cs);
        grpc_call_error error =
            grpc_server_request_call(g_server, &cs->call, &cs->call_details,
                                     &cs->recv_initial_metadata, cq, cq, v);
        if (error != GRPC_CALL_OK) {
          v->validate(v->arg, false);
          gpr_free(v);
        }
        break;
      }
      // destroy a call
      case 20: {
        if (g_active_call->type != ROOT &&
            g_active_call->type != PENDING_SERVER &&
            g_active_call->call != NULL) {
          destroy_call(g_active_call);
        } else {
          end(&inp);
        }
        break;
      }
    }
  }

  GPR_ASSERT(g_channel == NULL);
  GPR_ASSERT(g_server == NULL);
  GPR_ASSERT(g_active_call->type == ROOT);
  GPR_ASSERT(g_active_call->next == g_active_call);
  gpr_free(g_active_call);

  grpc_completion_queue_shutdown(cq);
  GPR_ASSERT(
      grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME), NULL)
          .type == GRPC_QUEUE_SHUTDOWN);
  grpc_completion_queue_destroy(cq);

  grpc_shutdown();
  return 0;
}