📄 stun.c
字号:
if ((sd->sd_index = su_root_register(sh->sh_root, wait, stun_tls_callback, (su_wakeup_arg_t *) sd, 0)) == -1) { STUN_ERROR(errno, su_root_register); return -1; } sd->sd_state = stun_tls_connecting; /* Create and start timer for connect() timeout */ SU_DEBUG_3(("%s: creating timeout timer for connect()\n", __func__)); connect_timer = su_timer_create(su_root_task(sh->sh_root), STUN_TLS_CONNECT_TIMEOUT); /* sd->sd_connect_timer = connect_timer; */ su_timer_set(connect_timer, stun_tls_connect_timer_cb, (su_wakeup_arg_t *) sd); return 0;}#elseint stun_handle_request_shared_secret(stun_handle_t *sh){ return 0;}#endif /* HAVE_OPENSSL */stun_request_t *stun_request_create(stun_discovery_t *sd){ stun_handle_t *sh = sd->sd_handle; stun_request_t *req = NULL; enter; req = calloc(sizeof(stun_request_t), 1); if (!req) return NULL; req->sr_handle = sh; req->sr_discovery = sd; /* This is the default */ req->sr_socket = sd->sd_socket; req->sr_localinfo.li_addrlen = sizeof(su_sockaddr_t); req->sr_localinfo.li_addr = req->sr_local_addr; /* default timeout for next sendto() */ req->sr_timeout = STUN_SENDTO_TIMEOUT; req->sr_retry_count = 0; /* req->sr_action = action; */ req->sr_request_mask = 0; req->sr_msg = calloc(sizeof(stun_msg_t), 1); req->sr_state = stun_discovery_init; memcpy(req->sr_local_addr, sd->sd_bind_addr, sizeof(su_sockaddr_t)); /* Insert this request to the request queue */ if (sh->sh_requests) x_insert(sh->sh_requests, req, sr); else sh->sh_requests = req; return req;}void stun_request_destroy(stun_request_t *req){ stun_handle_t *sh; assert(req); enter; sh = req->sr_handle; if (x_is_inserted(req, sr)) x_remove(req, sr); if (!x_is_inserted(req, sr) && !req->sr_next) sh->sh_requests = NULL; req->sr_handle = NULL; req->sr_discovery = NULL; /* memset(req->sr_destination, 0, sizeof(su_sockaddr_t)); */ if (req->sr_msg) stun_free_message(req->sr_msg); free(req); SU_DEBUG_9(("%s: request destroyed.\n", __func__)); return;}/** Destroy a STUN client */ void stun_handle_destroy(stun_handle_t *sh){ stun_discovery_t *sd = NULL, *kill = NULL; enter; /* There can be several discoveries using the same socket. It is still enough to deregister the socket in first of them */ for (sd = sh->sh_discoveries; sd; ) { kill = sd; sd = sd->sd_next; /* Index has same value as sockfd, right? ... or not? */ if (kill->sd_index != -1) su_root_deregister(sh->sh_root, kill->sd_index); if (kill->sd_action == stun_action_tls_query) su_close(kill->sd_socket); stun_discovery_destroy(kill); } su_home_zap(sh->sh_home);}/** Create wait object and register it to the handle callback */int assign_socket(stun_discovery_t *sd, su_socket_t s) { stun_handle_t *sh = sd->sd_handle; int events; stun_discovery_t *tmp; /* su_localinfo_t clientinfo[1]; */ su_sockaddr_t bind_addr; socklen_t bind_len; char ipaddr[SU_ADDRSIZE + 2] = { 0 }; su_sockaddr_t *sa; int err; su_wait_t wait[1] = { SU_WAIT_INIT }; enter; if (s == -1) { SU_DEBUG_3(("%s: invalid socket.\n", __func__)); return errno = EINVAL, -1; } for (tmp = sh->sh_discoveries; tmp; tmp = tmp->sd_next) { if (tmp->sd_socket == s) { sd->sd_socket = s; sd->sd_index = tmp->sd_index; memcpy(sd->sd_bind_addr, tmp->sd_bind_addr, sizeof(su_sockaddr_t)); return 0; } } sd->sd_socket = s; /* set socket asynchronous */ if (su_setblocking(s, 0) < 0) { STUN_ERROR(errno, su_setblocking); su_close(s); return -1; } /* xxx -- check if socket is already assigned to this root */ events = SU_WAIT_IN | SU_WAIT_ERR; if (su_wait_create(wait, s, events) == -1) { STUN_ERROR(su_errno(), su_wait_create); return -1; } /* Register receiving function with events specified above */ if ((sd->sd_index = su_root_register(sh->sh_root, wait, stun_bind_callback, (su_wakeup_arg_t *) sd, 0)) < 0) { STUN_ERROR(errno, su_root_register); return -1; } SU_DEBUG_7(("%s: socket registered.\n", __func__)); bind_len = sizeof bind_addr; sa = (void *) &bind_addr; bind_len = sizeof bind_addr; memset(sa, 0, sizeof(bind_addr)); /* if bound check the error */ err = getsockname(s, (struct sockaddr *) sa, &bind_len); if (err < 0 && errno == SOCKET_ERROR) { STUN_ERROR(errno, getsockname); return -1; } /* Not bound - bind it */ if (sa->su_port == 0) {#if defined (__CYGWIN__) get_localinfo(clientinfo);#endif if ((err = bind(s, (struct sockaddr *) sa, bind_len)) < 0) { STUN_ERROR(errno, bind); SU_DEBUG_3(("%s: Error binding to %s:%u\n", __func__, inet_ntop(sa->su_family, SU_ADDR(sa), ipaddr, sizeof(ipaddr)), (unsigned) ntohs(sa->su_port))); return -1; } /* bind_len = clientinfo->li_addrlen; */ /* clientinfo->li_addrlen = bind_len; */ sa->su_len = bind_len; /* ? */ } memcpy(&sd->sd_bind_addr, &bind_addr, sizeof bind_addr); if (getsockname(s, (struct sockaddr *) &bind_addr, &bind_len) != 0) { STUN_ERROR(errno, getsockname); return -1; } SU_DEBUG_3(("%s: local socket is bound to %s:%u\n", __func__, inet_ntop(bind_addr.su_family, SU_ADDR(&bind_addr), ipaddr, sizeof(ipaddr)), (unsigned) ntohs(bind_addr.su_port))); return 0;}/** * Helper function needed by Cygwin builds. */#if defined (__CYGWIN__)static int get_localinfo(su_localinfo_t *clientinfo){ su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL; su_sockaddr_t *sa; int i, error, found = 0; char ipaddr[SU_ADDRSIZE + 2] = { 0 }; hints->li_family = AF_INET; if ((error = su_getlocalinfo(hints, &res)) == 0) { /* try to bind to the first available address */ for (i = 0, li = res; li; li = li->li_next) { if (li->li_family != AF_INET) continue; clientinfo->li_family = li->li_family; clientinfo->li_addrlen = li->li_addrlen; sa = clientinfo->li_addr; memcpy(sa, li->li_addr, sizeof(su_sockaddr_t)); SU_DEBUG_3(("%s: local address found to be %s.\n", __func__, inet_ntop(clientinfo->li_family, SU_ADDR(sa), ipaddr, sizeof(ipaddr)))); found = 1; break; } if (!found) { STUN_ERROR(error, su_getlocalinfo); return -1; } } else { STUN_ERROR(error, su_getlocalinfo); return -1; } if (res) su_freelocalinfo(res); return 0;}#endif/** Bind a socket using STUN client. * * The function stun_bind() obtains a global address for a UDP socket using * a STUN server. * * @param ss dpointer to a STUN client object (IN) * @param my_addr public address for socket (IN/OUT) * @param addrlen length of pub_addr (IN/OUT) * @param lifetime return value pointer to lifetime of * binding, -1 if no STUN not used (OUT) * * @return * On success, zero is returned. Upon error, -1 is returned, and @e errno is * set appropriately. * * @ERRORS * @ERROR EFAULT An invalid address is given as argument * @ERROR EPROTONOSUPPORT Not a UDP socket. * @ERROR EINVAL The socket is already bound to an address. * @ERROR EACCESS The address is protected, and the user is not * the super-user. * @ERROR ENOTSOCK Argument is a descriptor for a file, not a socket. * @ERROR EAGAIN Operation in progress. Application should call * stun_bind() again when there is data available on * the socket. * */int stun_handle_bind(stun_handle_t *sh, tag_type_t tag, tag_value_t value, ...){ su_socket_t s = -1; stun_request_t *req = NULL; stun_discovery_t *sd = NULL; ta_list ta; stun_action_t action = stun_action_binding_request; int index; enter; if (sh == NULL) return errno = EFAULT, -1; ta_start(ta, tag, value); tl_gets(ta_args(ta), STUNTAG_SOCKET_REF(s), TAG_END()); ta_end(ta); sd = stun_discovery_create(sh, action); if ((index = assign_socket(sd, s)) < 0) return -1; req = stun_request_create(sd); if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 || stun_send_binding_request(req, sh->sh_pri_addr) < 0) { stun_discovery_destroy(sd); stun_free_message(req->sr_msg); return -1; } /* note: we always report success if bind() succeeds */ return 0;}/** Return local NATed address * This function returns the local address seen from outside. * Note that the address is not valid until the event stun_clien_done is launched. */su_sockaddr_t *stun_discovery_get_address(stun_discovery_t *sd){ enter; return sd->sd_addr_seen_outside;}stun_discovery_t *stun_discovery_create(stun_handle_t *sh, stun_action_t action){ stun_discovery_t *sd = NULL; enter; sd = calloc(1, sizeof(stun_discovery_t)); sd->sd_action = action; sd->sd_handle = sh; sd->sd_lt_cur = 0; sd->sd_lt = STUN_LIFETIME_EST; sd->sd_lt_max = STUN_LIFETIME_MAX; sd->sd_pri_info.ai_addrlen = 16; sd->sd_pri_info.ai_addr = &sd->sd_pri_addr->su_sa; /* Insert this action to the discovery queue */ if (sh->sh_discoveries) x_insert(sh->sh_discoveries, sd, sd); else sh->sh_discoveries = sd; return sd;}int stun_discovery_destroy(stun_discovery_t *sd){ stun_handle_t *sh; enter; if (!sd) return errno = EFAULT, -1; sh = sd->sd_handle; /* if we are in the queue*/ if (x_is_inserted(sd, sd)) x_remove(sd, sd); /* if we were the only one */ else if (!sd->sd_next) sh->sh_discoveries = NULL; sd->sd_prev = NULL; sd->sd_next = NULL; free(sd); return 0;}int stun_handle_get_nattype(stun_handle_t *sh, tag_type_t tag, tag_value_t value, ...){ int err = 0, index = 0; ta_list ta; char const *server = NULL; stun_request_t *req = NULL; stun_discovery_t *sd = NULL; su_sockaddr_t bind_addr; su_socket_t s = -1; socklen_t bind_len; su_sockaddr_t *destination = NULL; ta_start(ta, tag, value); enter; tl_gets(ta_args(ta), STUNTAG_SOCKET_REF(s), STUNTAG_SERVER_REF(server), TAG_END()); ta_end(ta); bind_len = sizeof bind_addr; if (s < 0) return errno = EFAULT, -1; sd = stun_discovery_create(sh, stun_action_get_nattype); if ((index = assign_socket(sd, s)) < 0) return errno = EFAULT, -1; /* If no server given, use default address from stun_handle_create() */ if (!server) { /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */ memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t)); } else { err = stun_atoaddr(AF_INET, &sd->sd_pri_info, server); memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t)); } destination = (su_sockaddr_t *) sd->sd_pri_addr; req = stun_request_create(sd); if (stun_make_binding_req(sh, req, req->sr_msg, STUNTAG_CHANGE_IP(0), STUNTAG_CHANGE_PORT(0), TAG_END()) < 0) return -1; err = stun_send_binding_request(req, destination); if (err < 0) { stun_free_message(req->sr_msg); return -1; } /* Same Public IP and port, Test III, server ip 0 or 1 should be the same */ req = stun_request_create(sd); if (stun_make_binding_req(sh, req, req->sr_msg, STUNTAG_CHANGE_IP(0), STUNTAG_CHANGE_PORT(1), TAG_END()) < 0) return -1; err = stun_send_binding_request(req, destination); if (err < 0) { stun_free_message(req->sr_msg); return -1; } req = NULL; req = stun_request_create(sd); if (stun_make_binding_req(sh, req, req->sr_msg, STUNTAG_CHANGE_IP(1), STUNTAG_CHANGE_PORT(1), TAG_END()) < 0) return -1; err = stun_send_binding_request(req, destination); if (err < 0) { stun_free_message(req->sr_msg); } return err;}/******************************************************************** * Internal functions *******************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -