⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stun.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
#if defined(HAVE_OPENSSL)int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg){  stun_discovery_t *sd = arg;  stun_handle_t *self = sd->sd_handle;  stun_msg_t *msg_req, *resp;  int z, err;  SSL_CTX* ctx;  SSL *ssl;  X509* server_cert;  unsigned char buf[512];  stun_attr_t *password, *username;  int state;  int events = su_wait_events(w, sd->sd_socket), one = 0;  unsigned int onelen;  enter;  SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, self,	      events & SU_WAIT_CONNECT ? " CONNECTED" : "",	      events & SU_WAIT_ERR     ? " ERR"       : "",	      events & SU_WAIT_IN      ? " IN"        : "",	      events & SU_WAIT_OUT     ? " OUT"       : ""));  getsockopt(sd->sd_socket, SOL_SOCKET, SO_ERROR,	     (void *)&one, &onelen);  if (one != 0) {    STUN_ERROR(one, getsockopt);  }  if (one || events & SU_WAIT_ERR) {    su_wait_destroy(w);    su_root_deregister(self->sh_root, sd->sd_index);    sd->sd_index = -1; /* mark index as deregistered */    /* Destroy the timeout timer */    /* su_timer_destroy(sd->sd_connect_timer); */    SU_DEBUG_3(("%s: shared secret not obtained from server. "	\		"Proceed without username/password.\n", __func__));    sd->sd_state = stun_tls_connection_failed;    self->sh_callback(self->sh_context, self, NULL, sd,		      sd->sd_action, sd->sd_state);    return 0;  }  /* Can be NULL, too */  ssl  = self->sh_ssl;  msg_req  = &self->sh_tls_request;  resp = &self->sh_tls_response;  state = sd->sd_state;  switch (state) {  case stun_tls_connecting:    /* compose shared secret request */    if (stun_make_sharedsecret_req(msg_req) != 0) {      STUN_ERROR(errno, stun_make_sharedsecret_req);      stun_free_buffer(&msg_req->enc_buf);      return -1;    }        /* openssl initiation */    SSLeay_add_ssl_algorithms();    SSL_load_error_strings();    ctx = SSL_CTX_new(TLSv1_client_method());    self->sh_ctx = ctx;    if (ctx == NULL) {      STUN_ERROR(errno, SSL_CTX_new);      stun_free_buffer(&msg_req->enc_buf);      return -1;    }        if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") == 0) {      STUN_ERROR(errno, SSL_CTX_set_cipher_list);      stun_free_buffer(&msg_req->enc_buf);      return -1;    }        /* Start TLS negotiation */    ssl = SSL_new(ctx);    self->sh_ssl = ssl;    if (SSL_set_fd(ssl, sd->sd_socket) == 0) {      STUN_ERROR(err, connect);      stun_free_buffer(&msg_req->enc_buf);      return -1;    }    /* No break here! Continue to SSL_connect. If SSL_continue returns     * less than 1 because of nonblocking, have a different state     * (ssl_connecting) for it */  case stun_tls_ssl_connecting:    events = SU_WAIT_ERR | SU_WAIT_IN;    su_root_eventmask(self->sh_root, sd->sd_index,		      sd->sd_socket, events);    z = SSL_connect(ssl);    err = SSL_get_error(ssl, z);    if (z < 1 && (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)) {      sd->sd_state = stun_tls_ssl_connecting;      return 0;    }    else if (z < 1) {      su_wait_destroy(w);      su_root_deregister(self->sh_root, sd->sd_index);      sd->sd_index = -1; /* mark index as deregistered */      stun_free_buffer(&msg_req->enc_buf);      sd->sd_state = stun_tls_connection_failed;      self->sh_callback(self->sh_context, self, NULL, sd,			sd->sd_action, sd->sd_state);      return -1;    }        /* Inform application about the progress  */    sd->sd_state = stun_tls_writing;    /* self->sh_callback(self->sh_context, self, self->sh_state); */    events = SU_WAIT_ERR | SU_WAIT_OUT;    su_root_eventmask(self->sh_root, sd->sd_index,		      sd->sd_socket, events);    break;  case stun_tls_writing:    events = SU_WAIT_ERR | SU_WAIT_IN;    su_root_eventmask(self->sh_root, sd->sd_index,		      sd->sd_socket, events);    SU_DEBUG_3(("TLS connection using %s\n", SSL_get_cipher(ssl)));        server_cert = SSL_get_peer_certificate(ssl);     if(server_cert) {      SU_DEBUG_3(("\t subject: %s\n", X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0)));      SU_DEBUG_3(("\t issuer: %s\n", X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0)));    }    X509_free(server_cert);        z = SSL_write(ssl, msg_req->enc_buf.data, msg_req->enc_buf.size);        if (z < 0) {      err = SSL_get_error(ssl, z);      if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)	return 0;      else {	STUN_ERROR(errno, SSL_write);	stun_free_buffer(&msg_req->enc_buf);	return -1;      }    }    sd->sd_state = stun_tls_reading;    break;  case stun_tls_reading:    events = SU_WAIT_ERR | SU_WAIT_OUT;    su_root_eventmask(self->sh_root, sd->sd_index,		      sd->sd_socket, events);    SU_DEBUG_5(("Shared Secret Request sent to server:\n"));    debug_print(&msg_req->enc_buf);    z = SSL_read(ssl, buf, sizeof(buf));    if (z <= 0) {      err = SSL_get_error(ssl, z);      if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)	return 0;      else {	stun_free_buffer(&msg_req->enc_buf);	return -1;      }    }    /* We end up here after there's something to read from the     * socket */    resp->enc_buf.size = z;    resp->enc_buf.data = malloc(z);    memcpy(resp->enc_buf.data, buf, z);    SU_DEBUG_5(("Shared Secret Response received from server:\n"));    debug_print(&resp->enc_buf);    /* closed TLS connection */    SSL_shutdown(ssl);    sd->sd_state = stun_tls_closing;    break;  case stun_tls_closing:    su_close(sd->sd_socket);    SSL_free(self->sh_ssl), ssl = NULL;    SSL_CTX_free(self->sh_ctx), ctx = NULL;    stun_free_buffer(&msg_req->enc_buf);      /* process response */    if (stun_parse_message(resp) < 0) {      perror("stun_parse_message");      stun_free_buffer(&resp->enc_buf);      return -1;    }    switch(resp->stun_hdr.msg_type) {    case SHARED_SECRET_RESPONSE:      username = stun_get_attr(resp->stun_attr, USERNAME);      password = stun_get_attr(resp->stun_attr, PASSWORD);      if (username != NULL && password != NULL) {	/* move result to se */	stun_copy_buffer(&self->sh_username, username->pattr);	stun_copy_buffer(&self->sh_passwd, password->pattr);      }      break;    case SHARED_SECRET_ERROR_RESPONSE:      if (stun_process_error_response(resp) < 0) {	SU_DEBUG_5(("Error in Shared Secret Error Response.\n"));       }      stun_free_buffer(&resp->enc_buf);      return -1;          break;    default:      break;    }        su_wait_destroy(w);    su_root_deregister(self->sh_root, sd->sd_index);    sd->sd_index = -1; /* mark index as deregistered */    self->sh_use_msgint = 1;    sd->sd_state = stun_tls_done;    self->sh_callback(self->sh_context, self, NULL, sd,		      sd->sd_action, sd->sd_state);        break;  default:    return -1;  }  return 0;}#elseint stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg){  return 0;}#endif /* HAVE_OPENSSL */#if defined(HAVE_OPENSSL)void stun_tls_connect_timer_cb(su_root_magic_t *magic, 			       su_timer_t *t,			       su_timer_arg_t *arg){  stun_discovery_t *sd = arg;  stun_handle_t *sh = sd->sd_handle;  enter;  su_destroy_timer(t);  SU_DEBUG_7(("%s: timer destroyed.\n", __func__));  if (sd->sd_state != stun_tls_connecting)    return;  SU_DEBUG_7(("%s: connect() timeout.\n", __func__));  su_root_deregister(sh->sh_root, sd->sd_index);  sd->sd_index = -1; /* mark index as deregistered */    sd->sd_state = stun_tls_connection_timeout;  sh->sh_callback(sh->sh_context, sh, NULL, sd, sd->sd_action, sd->sd_state);  return;}#elsevoid stun_tls_connect_timer_cb(su_root_magic_t *magic, 			       su_timer_t *t,			       su_timer_arg_t *arg){}#endif /* HAVE_OPENSSL *//** Compose a STUN message of the format defined by stun_msg_t *  result encoded in enc_buf ready for sending as well. */int stun_make_sharedsecret_req(stun_msg_t *msg){  int i, len;   uint16_t tmp;  /* compose header */  msg->stun_hdr.msg_type = SHARED_SECRET_REQUEST;  msg->stun_hdr.msg_len = 0; /* actual len computed by				stun_send_message */  for (i = 0; i < 8; i++) {    msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);  }     /* no buffer assigned yet */  stun_init_buffer(&msg->enc_buf);    msg->enc_buf.data = malloc(20);  msg->enc_buf.size = 20;  tmp = htons(msg->stun_hdr.msg_type);  len = 0;    memcpy(msg->enc_buf.data, &tmp, sizeof(tmp));  len+=sizeof(tmp);  tmp = htons(msg->stun_hdr.msg_len);  memcpy(msg->enc_buf.data+len, &tmp, sizeof(tmp));  len+=sizeof(tmp);  for (i = 0; i < 8; i++) {    tmp = htons(msg->stun_hdr.tran_id[i]);    memcpy(msg->enc_buf.data+len, &tmp, sizeof(tmp));    len+=sizeof(tmp);  }    return 0;}/* Return action of the request. If no request, return default value */static inlinestun_action_t get_action(stun_request_t *req){  stun_discovery_t *sd = NULL;  /* XXX -- if no sr_handle something is leaking... */  if (!req || !req->sr_discovery || !req->sr_handle)    return stun_action_no_action;  sd = req->sr_discovery;  return sd->sd_action;}/* Find request from the request queue, based on TID */static inlinestun_request_t *find_request(stun_handle_t *self, uint16_t *id){  uint16_t *match;  stun_request_t *req = NULL;  int len = sizeof(uint16_t)*8;  for (req = self->sh_requests; req; req = req->sr_next) {    match = req->sr_msg->stun_hdr.tran_id;    if (memcmp(match, id, len) == 0) {      return req;    }  }  return NULL;}/** Process socket event */int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg){  stun_discovery_t *sd = arg;  stun_handle_t *self = sd->sd_handle;  int retval = -1, err = -1, dgram_len;  char ipaddr[SU_ADDRSIZE + 2];  stun_msg_t binding_response;  unsigned char dgram[512] = { 0 };  su_sockaddr_t recv;  socklen_t recv_len;  su_socket_t s = sd->sd_socket;  int events = su_wait_events(w, s);  enter;  SU_DEBUG_7(("%s(%p): events%s%s%s\n", __func__, self,	      events & SU_WAIT_IN ? " IN" : "",	      events & SU_WAIT_OUT ? " OUT" : "",	      events & SU_WAIT_ERR ? " ERR" : ""));  if (!(events & SU_WAIT_IN || events & SU_WAIT_OUT)) {    /* su_wait_destroy(w); */    /* su_root_deregister(self->sh_root, self->ss_root_index); */    /* self->sh_state = stun_bind_error; */    self->sh_callback(self->sh_context, self, NULL, NULL, 		      stun_action_no_action, stun_bind_error);    return 0;  }/*   s = self->sh_bind_socket; */  /* receive response */  recv_len = sizeof(recv);  dgram_len = recvfrom(s, dgram, sizeof(dgram), 0, (struct sockaddr *) &recv,		 &recv_len);  err = errno;  if ((dgram_len < 0) && (err != EAGAIN)) {    /* su_wait_destroy(w); */    /* su_root_deregister(self->sh_root, self->ss_root_index); */    STUN_ERROR(err, recvfrom);    /* stun_free_message(binding_request); */    return err;  }  else if (dgram_len <= 0) {    STUN_ERROR(err, recvfrom);    /* No data available yet, wait for the event. */    return 0;  }  /* Message received. */  binding_response.enc_buf.data = (unsigned char *) malloc(dgram_len);  binding_response.enc_buf.size = dgram_len;  memcpy(binding_response.enc_buf.data, dgram, dgram_len);    SU_DEBUG_5(("%s: response from server %s:%u\n", __func__,	      inet_ntop(recv.su_family, SU_ADDR(&recv), ipaddr, sizeof(ipaddr)),	      ntohs(recv.su_port)));  debug_print(&binding_response.enc_buf);        /* Parse here the incoming message. */  if (stun_parse_message(&binding_response) < 0) {    stun_free_message(&binding_response);    SU_DEBUG_5(("%s: Error parsing response.\n", __func__));    return retval;  }  /* Based on the decoded payload, find the corresponding request   * (based on TID). */  do_action(self, &binding_response);  return 0;}/** Choose the right state machine */int do_action(stun_handle_t *sh, stun_msg_t *msg){  stun_request_t *req = NULL;  stun_action_t action = stun_action_no_action;  uint16_t *id;  enter;  if (!sh)    return errno = EFAULT, -1;  id = msg->stun_hdr.tran_id;  req = find_request(sh, id);  if (!req)    return 0;  action = get_action(req);  /* Based on the action, use different state machines */  switch (action) {  case stun_action_binding_request:    action_bind(req, msg);    break;  case stun_action_get_nattype:    action_determine_nattype(req, msg);    break;  case stun_action_get_lifetime:    process_get_lifetime(req, msg);    break;  case stun_action_keepalive:    SU_DEBUG_3(("%s: Response to keepalive received.\n", __func__));    req->sr_state = stun_dispose_me;    break;  case stun_action_no_action:    SU_DEBUG_3(("%s: Unknown response. No matching request found.\n", __func__));    req->sr_state = stun_request_not_found;    sh->sh_callback(sh->sh_context, sh, req, NULL,		    stun_action_no_action, req->sr_state);    req->sr_state = stun_dispose_me;    break;  default:    SU_DEBUG_3(("%s: bad action.\n", __func__));    req->sr_state = stun_error;    sh->sh_callback(sh->sh_context, sh, req, NULL,		    stun_action_no_action, req->sr_state);    req->sr_state = stun_dispose_me;    break;  }    return 0;}int process_binding_request(stun_request_t *req, stun_msg_t *binding_response){  int retval = -1, clnt_addr_len;  stun_attr_t *mapped_addr, *chg_addr;  stun_handle_t *self = req->sr_handle;  su_localinfo_t *clnt_info = &req->sr_localinfo;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -