Пример #1
0
int
rtcdc_parse_candidate_sdp(struct rtcdc_peer_connection *peer, const char *candidates)
{
  if (peer == NULL || peer->transport == NULL)
    return -1;

  return parse_remote_candidate_sdp(peer->transport->ice, candidates);
}
Пример #2
0
int
rtcdc_parse_offer_sdp(struct rtcdc_peer_connection *peer, const char *offer)
{
  if (peer == NULL || offer == NULL)
    return -1;

  if (peer->transport == NULL) {
    if (create_rtcdc_transport(peer, RTCDC_PEER_ROLE_CLIENT) < 0)
      return -1;
  }

  char **lines;
  lines = g_strsplit(offer, "\r\n", 0);

  char buf[BUFFER_SIZE];
  memset(buf, 0, sizeof buf);
  int pos = 0;
  int remote_port = 0;
  for (int i = 0; lines && lines[i]; ++i) {

#ifdef LEGACY_SDP
    if (g_str_has_prefix(lines[i], "m=application")) {
      char **columns = g_strsplit(lines[i], " ", 0);
      remote_port = atoi(columns[3]);
#else
    if (g_str_has_prefix(lines[i], "a=sctp-port:")) {
      char **columns = g_strsplit(lines[i], ":", 0);
      remote_port = atoi(columns[1]);
#endif
      if (remote_port <= 0)
        return -1;
      peer->transport->sctp->remote_port = remote_port;
      g_strfreev(columns);
    } else if (g_str_has_prefix(lines[i], "a=setup:")) {
      char **columns = g_strsplit(lines[i], ":", 0);
      if (strcmp(columns[1], "active") == 0 && peer->role == RTCDC_PEER_ROLE_CLIENT) {
        peer->role = RTCDC_PEER_ROLE_SERVER;
      } else if (strcmp(columns[1], "passive") == 0 && peer->role == RTCDC_PEER_ROLE_SERVER) {
        //peer->role = RTCDC_PEER_ROLE_CLIENT;
        peer->role = RTCDC_PEER_ROLE_SERVER;
      } else { // actpass
        // nothing to do
      }
      g_strfreev(columns);
    }
    pos += sprintf(buf + pos, "%s\n", lines[i]);
  }
  g_strfreev(lines);

  return parse_remote_sdp(peer->transport->ice, buf);
}

int
rtcdc_parse_candidate_sdp(struct rtcdc_peer_connection *peer, const char *candidates)
{
  if (peer == NULL || peer->transport == NULL)
    return -1;

  return parse_remote_candidate_sdp(peer->transport->ice, candidates);
}

struct rtcdc_data_channel *
rtcdc_create_data_channel(struct rtcdc_peer_connection *peer,
                          const char *label, const char *protocol,
                          rtcdc_on_open_cb on_open,
                          rtcdc_on_message_cb on_message,
                          rtcdc_on_close_cb on_close,
                          void *user_data)
{
  if (peer == NULL || peer->transport == NULL)
    return NULL;

  struct rtcdc_transport *transport = peer->transport;
  struct sctp_transport *sctp = transport->sctp;

  int i;
  for (i = 0; i < RTCDC_MAX_CHANNEL_NUM; ++i) {
    if (peer->channels[i])
      continue;
    break;
  }

  if (i == RTCDC_MAX_CHANNEL_NUM)
    return NULL;

  struct rtcdc_data_channel *ch = (struct rtcdc_data_channel *)calloc(1, sizeof *ch);
  if (ch == NULL)
    return NULL;
  ch->on_open = on_open;
  ch->on_message = on_message;
  ch->on_close = on_close;
  ch->user_data = user_data;
  ch->sctp = sctp;

  struct dcep_open_message *req;
  int rlen = sizeof *req + strlen(label) + strlen(protocol);
  req = (struct dcep_open_message *)calloc(1, rlen);
  if (req == NULL)
    goto open_channel_err;

  ch->type = DATA_CHANNEL_RELIABLE;
  ch->state = RTCDC_CHANNEL_STATE_CONNECTING;
  if (label)
    ch->label = strdup(label);
  if (protocol)
    ch->protocol = strdup(protocol);
  ch->sid = sctp->stream_cursor;
  sctp->stream_cursor += 2;

  req->message_type = DATA_CHANNEL_OPEN;
  req->channel_type = ch->type;
  req->priority = htons(0);
  req->reliability_param = htonl(0);
  if (label)
    req->label_length = htons(strlen(label));
  if (protocol)
    req->protocol_length = htons(strlen(protocol));
  memcpy(req->label_and_protocol, label, strlen(label));
  memcpy(req->label_and_protocol + strlen(label), protocol, strlen(protocol));

  int ret = send_sctp_message(sctp, req, rlen, ch->sid, WEBRTC_CONTROL_PPID);
  free(req);
  if (ret < 0)
    goto open_channel_err;

  if (0) {
open_channel_err:
    free(ch);
    ch = NULL;
  }

  peer->channels[i] = ch;
  return ch;
}

void
rtcdc_destroy_data_channel(struct rtcdc_data_channel *channel)
{
  if (channel == NULL)
    return;

  // todo: close channel
  if (channel->label)
    free(channel->label);
  if (channel->protocol)
    free(channel->protocol);
}

int
rtcdc_send_message(struct rtcdc_data_channel *channel, int datatype, void *data, size_t len)
{
  if (channel == NULL)
    return -1;

  int ppid;
  if (datatype == RTCDC_DATATYPE_STRING) {
    if (data == NULL || len == 0)
      ppid = WEBRTC_STRING_EMPTY_PPID;
    else
      ppid = WEBRTC_STRING_PPID;
  } else if (datatype == RTCDC_DATATYPE_BINARY) {
    if (data == NULL || len == 0)
      ppid = WEBRTC_BINARY_EMPTY_PPID;
    else
      ppid = WEBRTC_BINARY_PPID;
  } else
    return -1;

  return send_sctp_message(channel->sctp, data, len, channel->sid, ppid);
}

static gpointer
startup_thread(gpointer user_data)
{
  struct rtcdc_peer_connection *peer = (struct rtcdc_peer_connection *)user_data;
  struct rtcdc_transport *transport = peer->transport;
  struct ice_transport *ice = transport->ice;
  struct dtls_transport *dtls = transport->dtls;
  struct sctp_transport *sctp = transport->sctp;

  while (!peer->exit_thread && !ice->negotiation_done)
    g_usleep(2500);
  if (peer->exit_thread)
    return NULL;

#ifdef DEBUG_SCTP
  fprintf(stderr, "ICE negotiation done\n");
#endif

  if (peer->role == RTCDC_PEER_ROLE_CLIENT)
    SSL_set_connect_state(dtls->ssl);
  else
    SSL_set_accept_state(dtls->ssl);
  SSL_do_handshake(dtls->ssl);

  while (!peer->exit_thread && !dtls->handshake_done)
    g_usleep(2500);
  if (peer->exit_thread)
    return NULL;

#ifdef DEBUG_SCTP
  fprintf(stderr, "DTLS handshake done\n");
#endif

  if (peer->role == RTCDC_PEER_ROLE_CLIENT) {
    sctp->stream_cursor = 0; // use even streams
    struct sockaddr_conn sconn;
    memset(&sconn, 0, sizeof sconn);
    sconn.sconn_family = AF_CONN;
    sconn.sconn_port = htons(sctp->remote_port);
    sconn.sconn_addr = (void *)sctp;
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
    sconn.sconn_len = sizeof *sctp;
#endif
    fprintf(stderr, "usrsctp_connect ... \n");
    if (usrsctp_connect(sctp->sock, (struct sockaddr *)&sconn, sizeof sconn) < 0) {
#ifdef DEBUG_SCTP
      fprintf(stderr, "SCTP connection failed\n");
#endif
    } else {
#ifdef DEBUG_SCTP
      fprintf(stderr, "SCTP connected\n");
#endif
      sctp->handshake_done = TRUE;

      if (peer->on_connect)
        peer->on_connect(peer, peer->user_data);
    }
  } else {
    sctp->stream_cursor = 1; // use odd streams
    struct sockaddr_conn sconn;
    memset(&sconn, 0, sizeof sconn);
    sconn.sconn_family = AF_CONN;
    sconn.sconn_port = htons(sctp->local_port);
    sconn.sconn_addr = (void *)sctp;
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
    sconn.sconn_len = sizeof *sctp;
#endif
    usrsctp_listen(sctp->sock, 1);
    socklen_t len = sizeof sconn;
    fprintf(stderr, "usrsctp_accept ... \n");
    struct socket *s = usrsctp_accept(sctp->sock, (struct sockaddr *)&sconn, &len);
    if (s) {
#ifdef DEBUG_SCTP
      fprintf(stderr, "SCTP accepted\n");
#endif
      sctp->handshake_done = TRUE;
      struct socket *t = sctp->sock;
      sctp->sock = s;
      usrsctp_close(t);

      if (peer->on_connect)
        peer->on_connect(peer, peer->user_data);
    } else {
#ifdef DEBUG_SCTP
      fprintf(stderr, "SCTP acception failed\n");
#endif
    }
  }

  return NULL;
}

void
rtcdc_loop(struct rtcdc_peer_connection *peer)
{
  if (peer == NULL)
    return;

  while (!peer->initialized)
    g_usleep(50000);

  GThread *thread_ice = g_thread_new("ICE thread", &ice_thread, peer);
  GThread *thread_sctp = g_thread_new("SCTP thread", &sctp_thread, peer);
  GThread *thread_startup = g_thread_new("Startup thread", &startup_thread, peer);

  struct ice_transport *ice = peer->transport->ice;
  g_main_loop_run(ice->loop);
  peer->exit_thread = TRUE;

  g_thread_join(thread_ice);
  g_thread_join(thread_sctp);
  g_thread_join(thread_startup);

  g_thread_unref(thread_ice);
  g_thread_unref(thread_sctp);
  g_thread_unref(thread_startup);
}