📄 stun.c
字号:
req->sr_request_mask = bits; /* compose header */ msg->stun_hdr.msg_type = BINDING_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); } /* optional attributes: * - Response Address * - Change Request X * - Username * - Message-Integrity */ msg->stun_attr = NULL; /* CHANGE_REQUEST */ p = &(msg->stun_attr); if (chg_ip || chg_port) { stun_attr_changerequest_t *attr_cr; tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t)); tmp->attr_type = CHANGE_REQUEST; attr_cr = (stun_attr_changerequest_t *) malloc(sizeof(stun_attr_changerequest_t)); attr_cr->value = (chg_ip ? STUN_CR_CHANGE_IP : 0) | (chg_port ? STUN_CR_CHANGE_PORT : 0); tmp->pattr = attr_cr; tmp->next = NULL; *p = tmp; p = &(tmp->next); } /* USERNAME */ if (sh->sh_use_msgint && sh->sh_username.data && sh->sh_passwd.data) { tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t)); tmp->attr_type = USERNAME; tmp->pattr = &sh->sh_username; tmp->next = NULL; *p = tmp; p = &(tmp->next); /* dummy MESSAGE_INTEGRITY attribute, computed later */ tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t)); tmp->attr_type = MESSAGE_INTEGRITY; tmp->pattr = NULL; tmp->next = NULL; *p = tmp; p = &(tmp->next); } /* no buffer assigned yet */ msg->enc_buf.data = NULL; msg->enc_buf.size = 0; return 0;}int stun_process_response(stun_msg_t *msg){ enter; /* parse msg first */ if (stun_parse_message(msg) < 0) { SU_DEBUG_3(("%s: Error parsing response.\n", __func__)); return -1; } /* check message digest if exists */ switch (msg->stun_hdr.msg_type) { case BINDING_RESPONSE: if (stun_process_binding_response(msg) < 0) return -1; break; case BINDING_ERROR_RESPONSE: if (stun_process_error_response(msg) < 0) return -1; break; default: return -1; } return 0;}/** process binding response */int stun_process_binding_response(stun_msg_t *msg) { /* currently not needed. */ return 0;}/** process binding error response * Report error and return */int stun_process_error_response(stun_msg_t *msg){ stun_attr_t *attr; stun_attr_errorcode_t *ec; enter; attr = stun_get_attr(msg->stun_attr, ERROR_CODE); if (attr == NULL) { perror("stun_process_error_response"); return -1; } ec = (stun_attr_errorcode_t *)attr->pattr; SU_DEBUG_5(("%s: Received Binding Error Response:\n", __func__)); SU_DEBUG_5(("%s: Error: %d %s\n", __func__, ec->code, ec->phrase)); return 0;}int stun_handle_set_uname_pwd(stun_handle_t *sh, const char *uname, int len_uname, const char *pwd, int len_pwd){ enter; sh->sh_username.data = (unsigned char *) malloc(len_uname); memcpy(sh->sh_username.data, uname, len_uname); sh->sh_username.size = len_uname; sh->sh_passwd.data = (unsigned char *) malloc(len_pwd); memcpy(sh->sh_passwd.data, pwd, len_pwd); sh->sh_passwd.size = len_pwd; sh->sh_use_msgint = 1; /* turn on message integrity ussage */ return 0;} /* convert character address format to sockaddr_in */int stun_atoaddr(int ai_family, su_addrinfo_t *info, char const *in){ su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }}; char const *host; char *port = NULL, tmp[SU_ADDRSIZE]; int err; su_sockaddr_t *addr; assert(info && in); enter; addr = (su_sockaddr_t *) info->ai_addr; /* note: works only for IPv4 */ hints->ai_family = ai_family; port = strstr(in, ":"); if (port == NULL) { host = in; } else { assert(port - in < strlen(in) + 1); memcpy(tmp, in, port - in); tmp[port - in] = 0; host = tmp; ++port; } if ((err = su_getaddrinfo(host, NULL, hints, &res)) != 0) { STUN_ERROR(err, su_getaddrinfo); return -1; } for (ai = res; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET) continue; info->ai_flags = ai->ai_flags; info->ai_family = ai->ai_family; info->ai_socktype = ai->ai_socktype; info->ai_protocol = ai->ai_protocol; info->ai_addrlen = ai->ai_addrlen; memcpy(&addr->su_sa, res->ai_addr, sizeof(struct sockaddr)); break; } if (port) addr->su_port = htons(atoi(port)); else addr->su_port = htons(STUN_DEFAULT_PORT); if (res) su_freeaddrinfo(res); return err;}int stun_handle_get_lifetime(stun_handle_t *sh, tag_type_t tag, tag_value_t value, ...){ stun_request_t *req = NULL; stun_discovery_t *sd = NULL; ta_list ta; int s = -1, err, index = 0; char ipaddr[SU_ADDRSIZE + 2] = { 0 }; char const *server = NULL; su_socket_t sockfdy; socklen_t y_len; su_sockaddr_t y_addr; su_sockaddr_t *destination; assert(sh); enter; ta_start(ta, tag, value); tl_gets(ta_args(ta), STUNTAG_SOCKET_REF(s), STUNTAG_SERVER_REF(server), TAG_END()); sd = stun_discovery_create(sh, stun_action_get_lifetime); 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); /* ci = &req->sr_localinfo; */ /* get local ip address */ /* get_localinfo(ci); */ /* initialize socket y */ sockfdy = socket(AF_INET, SOCK_DGRAM, 0); /* set socket asynchronous */ if (su_setblocking(sockfdy, 0) < 0) { STUN_ERROR(errno, su_setblocking); su_close(sockfdy); return errno = EFAULT, -1; } sd->sd_socket2 = sockfdy; memset(&y_addr, 0, sizeof(y_addr)); memcpy(&y_addr, sd->sd_bind_addr, sizeof(y_addr)); y_addr.su_port = 0; y_len = sizeof(y_addr); if (bind(sockfdy, (struct sockaddr *) &y_addr, y_len) < 0) { return -1; } if (getsockname(sockfdy, (struct sockaddr *) &y_addr, &y_len) < 0) { STUN_ERROR(errno, getsockname); return -1; } SU_DEBUG_3(("%s: socket y bound to %s:%u\n", __func__, inet_ntop(y_addr.su_family, SU_ADDR(&y_addr), ipaddr, sizeof(ipaddr)), (unsigned) ntohs(y_addr.su_port))); req->sr_from_y = -1; SU_DEBUG_1(("%s: determining binding life time, this may take a while.\n", __func__)); if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0) return -1; err = stun_send_binding_request(req, destination); if (err < 0) { stun_free_message(req->sr_msg); return -1; } ta_end(ta); return 0;}int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr){ stun_attr_sockaddr_t *addr; stun_attr_t *tmp; enter; tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t)); tmp->attr_type = RESPONSE_ADDRESS; addr = malloc(sizeof(stun_attr_sockaddr_t)); memcpy(addr, mapped_addr, sizeof(stun_attr_sockaddr_t)); tmp->pattr = addr; if (req->stun_attr == NULL) { tmp->next = NULL; } else { tmp->next = req->stun_attr; } req->stun_attr = tmp; return 0;}/** Determine if the message is STUN message (0 if not). */int stun_msg_is_keepalive(uint16_t data){ uint16_t msg_type; /* parse header */ msg_type = ntohs(data); if (msg_type == BINDING_REQUEST || msg_type == BINDING_RESPONSE || msg_type == BINDING_ERROR_RESPONSE) { return 0; } return -1;}/** Determine length of STUN message (0 if not stun). */int stun_message_length(void *data, int len, int end_of_message){ unsigned char *p; uint16_t tmp16, msg_type; /* parse header first */ p = data; memcpy(&tmp16, p, 2); msg_type = ntohs(tmp16); if (msg_type == BINDING_REQUEST || msg_type == BINDING_RESPONSE || msg_type == BINDING_ERROR_RESPONSE) { p+=2; memcpy(&tmp16, p, 2); /* return message length */ return ntohs(tmp16); } else return -1;}/** Process incoming message */int stun_handle_process_message(stun_handle_t *sh, su_socket_t s, su_sockaddr_t *sa, socklen_t salen, void *data, int len){ int retval = -1, err = -1, dgram_len; char ipaddr[SU_ADDRSIZE + 2]; stun_msg_t msg; unsigned char dgram[20] = { 0 }; su_sockaddr_t recv; socklen_t recv_len; enter; /* Message received. */ msg.enc_buf.data = data; msg.enc_buf.size = len; debug_print(&msg.enc_buf); /* Parse here the incoming message. */ if (stun_parse_message(&msg) < 0) { stun_free_message(&msg); SU_DEBUG_5(("%s: Error parsing response.\n", __func__)); return retval; } if (msg.stun_hdr.msg_type == BINDING_REQUEST) { return stun_process_request(s, &msg, 0, sa, salen); } else if (msg.stun_hdr.msg_type == BINDING_RESPONSE) { /* Based on the decoded payload, find the corresponding request * (based on TID). */ return do_action(sh, &msg); } return -1;}/** Unregister socket from STUN handle event loop */int stun_handle_release(stun_handle_t *sh, su_socket_t s){ stun_discovery_t *sd; assert (sh); enter; if (s < 0) return errno = EFAULT, -1; /* 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; sd = sd->sd_next) { if (sd->sd_socket != s) continue; su_root_deregister(sh->sh_root, sd->sd_index); sd->sd_index = -1; /* mark index as deregistered */ SU_DEBUG_3(("%s: socket deregistered from STUN \n", __func__)); return 0; } /* Oops, user passed wrong socket */ SU_DEBUG_3(("%s: socket given is not associated with STUN \n", __func__)); return -1;}/** stun_keepalive won't do su_root_register() */int stun_keepalive(stun_handle_t *sh, su_sockaddr_t *sa, tag_type_t tag, tag_value_t value, ...){ int s = -1; unsigned int timeout = 0; ta_list ta; stun_discovery_t *sd; stun_request_t *req; stun_action_t action = stun_action_keepalive; char ipaddr[SU_ADDRSIZE + 2] = { 0 }; enter; ta_start(ta, tag, value); tl_gets(ta_args(ta), STUNTAG_SOCKET_REF(s), STUNTAG_TIMEOUT_REF(timeout), TAG_END()); if (s < 1 || !sa || timeout == 0) return errno = EFAULT, -1; /* If there already is keepalive associated with the given socket, * destroy it. */ stun_keepalive_destroy(sh, s); /*Ok, here we go */ sd = stun_discovery_create(sh, action); sd->sd_socket = s; sd->sd_timeout = timeout; memcpy(sd->sd_pri_addr, sa, sizeof(*sa)); req = stun_request_create(sd); SU_DEBUG_3(("%s: Starting to send STUN keepalives to %s:%u\n", __func__, inet_ntop(sa->su_family, SU_ADDR(sa), ipaddr, sizeof(ipaddr)), (unsigned) ntohs(sa->su_port))); if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 || stun_send_binding_request(req, sa) < 0) { stun_request_destroy(req); stun_discovery_destroy(sd); return -1; } sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout); su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd); ta_end(ta); return 0;}/** Send SIP keepalives */void stun_keepalive_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; int timeout = sd->sd_timeout; su_sockaddr_t *destination = sd->sd_pri_addr; stun_request_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -