/** Receive from stream.
 *
 * @retval -1 error
 * @retval 0  end-of-stream
 * @retval 1  normal receive
 * @retval 2  incomplete recv, recv again
 *
 */
int tport_recv_stream_ws(tport_t *self)
{
  msg_t *msg;
  ssize_t n, N, veclen, i, m;
  int err;
  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
  tport_ws_t *wstp = (tport_ws_t *)self;
  uint8_t *data;
  ws_opcode_t oc;

  if (wstp->ws_initialized < 0) {
	  return -1;
  }

  N = ws_read_frame(&wstp->ws, &oc, &data);

  if (N == -2) {
	  return 2;
  }

  if ((N == -1000) || (N == 0)) {
	  if (self->tp_msg) {
		  msg_recv_commit(self->tp_msg, 0, 1);
	  }
	  return 0;    /* End of stream */
  }
  if (N < 0) {
	  err = errno = EHOSTDOWN;
	  SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, (void *)self,
				  su_strerror(err), err));
	  return 0;
  }

  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
  if (veclen < 0)
    return -1;

  msg = self->tp_msg;

  msg_set_address(msg, self->tp_addr, self->tp_addrlen);

  for (i = 0, n = 0; i < veclen; i++) {
    m = iovec[i].mv_len; assert(N >= n + m);
    memcpy(iovec[i].mv_base, data + n, m);
    n += m;
  }

  assert(N == n);

  /* Write the received data to the message dump file */
  if (self->tp_master->mr_dump_file)
	  tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");

  /* Mark buffer as used */
  msg_recv_commit(msg, N, 0);

  return 1;
}
Exemple #2
0
abyss_bool websocket_hook(TSession *r)
{
	wsh_t *wsh;
	int ret;
	int i;
	ws_opcode_t opcode;
	uint8_t *data;
	switch_event_node_t *nodes[MAX_EVENT_BIND_SLOTS];
	int node_count = 0;
	char *p;
	char *key = NULL;
	char *version = NULL;
	char *proto = NULL;
	char *upgrade = NULL;

	for (i = 0; i < r->requestHeaderFields.size; i++) {
		TTableItem * const item = &r->requestHeaderFields.item[i];

		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "headers %s: %s\n", item->name, item->value);
	}

	key = RequestHeaderValue(r, "sec-websocket-key");
	version = RequestHeaderValue(r, "sec-websocket-version");
	proto = RequestHeaderValue(r, "sec-websocket-protocol");
	upgrade = RequestHeaderValue(r, "upgrade");

	if (!key || !version || !proto || !upgrade) return FALSE;
	if (strncasecmp(upgrade, "websocket", 9) || strncasecmp(proto, "websocket", 9)) return FALSE;

	wsh = ws_init(r);
	if (!wsh) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "websocket error %d\n", ret);
		return FALSE;
	}

	ret = ws_handshake_kvp(wsh, key, version, proto);
	if (ret < 0) wsh->down = 1;

	if (ret != 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "handshake error %d\n", ret);
		return FALSE;
	}

	if (switch_event_bind_removable("websocket", SWITCH_EVENT_CUSTOM, "websocket::stophook", stop_hook_event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n");
		node_count--;
	}

	while (!wsh->down) {
		int bytes = ws_read_frame(wsh, &opcode, &data);

		if (bytes < 0) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d %s\n", opcode, (char *)data);
			switch_yield(100000);
			continue;
		}

		switch (opcode) {
			case WSOC_CLOSE:
				ws_close(wsh, 1000);
				break;
			case WSOC_CONTINUATION:
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "continue\n");
				continue;
			case WSOC_TEXT:
				p = data;
				if (!p) continue;
				if (!strncasecmp(data, "event ", 6)) {
					switch_event_types_t type;
					char *subclass;

					if (node_count == MAX_EVENT_BIND_SLOTS - 1) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot subscribe more than %d events\n", node_count);
						continue;
					}
					p += 6;
					if (p = strchr(p, ' ')) p++;
					if (!strncasecmp(p, "json ", 5)) {
						p += 5;
					} else if (!strncasecmp(p, "xml ", 4)) {
						p += 4;
					} else if (!strncasecmp(p, "plain ", 6)) {
						p += 6;
					}
					if (!*p) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "missing event type in [%s]\n", data);
						break;
					} else {
					}
					if (subclass = strchr(p, ' ')) {
						*subclass++ = '\0';
						if (!*subclass) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing subclass\n");
							continue;
						}
					} else {
						subclass = SWITCH_EVENT_SUBCLASS_ANY;
					}

					if (switch_name_event(p, &type) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown event %s\n", p);
						continue;
					}

					if (switch_event_bind_removable("websocket", type, subclass, event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n");
						node_count--;
						continue;
					} else {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bind %s\n", data);
					}

				}
				break;
			default:
				break;
		}
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "wsh->down = %d, node_count = %d\n", wsh->down, node_count);

	switch_yield(2000);
	while (--node_count >= 0) switch_event_unbind(&nodes[node_count]);

	switch_safe_free(wsh);

	return FALSE;
}