diff --git a/src/address.c b/src/address.c index c26741c..f63a727 100644 --- a/src/address.c +++ b/src/address.c @@ -1,5 +1,11 @@ #include #include +#include +#include +#include +#include +#include + #include "address.h" int addr_ipv4_validate(const char *ipv4, size_t len, Address *addr) { @@ -21,6 +27,49 @@ int addr_ipv4_validate(const char *ipv4, size_t len, Address *addr) { return 0; } } + addr->family = AF_INET; + return 1; +} + +int addr_ipv6_validate(const char *ipv6, size_t len, Address *addr) { + int ret; + struct sockaddr_in6 sa6; + char astring[INET6_ADDRSTRLEN]; + ret = inet_pton(AF_INET6, ipv6, &(sa6.sin6_addr)); + inet_ntop(AF_INET6, &(sa6.sin6_addr), astring, INET6_ADDRSTRLEN); + memcpy(addr->ipv6, sa6.sin6_addr.s6_addr, 16); + return ret; +} + +int addr_to_text(const Address *addr, char *buf, size_t len) { + + switch (addr->family) { + case AF_INET: + return inet_ntop(AF_INET, addr->ipv4, buf, len) != NULL; + break; + case AF_INET6: + return inet_ntop(AF_INET6, addr->ipv6, buf, len) != NULL; + break; + } + return 0; +} + +int addr_equal(const Address *a, const Address *b) { + if (a->family != b->family) { + return 0; + } + + switch (a->family) { + case AF_INET: + for (int i = 0; i < 4; i++) { + if (a->ipv4[i] != b->ipv4[i]) { + return 0; + } + } + break; + case AF_INET6: + break; + } return 1; } diff --git a/src/address.h b/src/address.h index 524f720..52e2eb1 100644 --- a/src/address.h +++ b/src/address.h @@ -10,10 +10,16 @@ struct Address { uint8_t family; uint16_t port; uint8_t ipv4[4]; - uint8_t ipv6[16]; + uint16_t ipv6[8]; -}__attribute__((packed)); +}; + +int addr_ipv6_validate(const char *ipv6, size_t len, Address *addr); int addr_ipv4_validate(const char *ipv4, size_t len, Address *addr); +int addr_to_text(const Address *addr, char *buf, size_t len); + +int addr_equal(const Address *a, const Address *b); + #endif // ADDRESS_H_ diff --git a/src/agent.c b/src/agent.c index e7ed198..9c1aa1d 100644 --- a/src/agent.c +++ b/src/agent.c @@ -15,55 +15,100 @@ #include "agent.h" #include "ports.h" +#define AGENT_POLL_TIMEOUT 1 +#define AGENT_CONNCHECK_MAX 300 +#define AGENT_CONNCHECK_PERIOD 100 static int agent_create_sockets(Agent *agent) { - int ret = -1; - UdpSocket *udp_socket = &agent->udp_sockets[0]; - ret = udp_socket_create(udp_socket, AF_INET); - return ret; + int ret; + if (ret = udp_socket_create(&agent->udp_sockets[0], AF_INET) < 0) { + LOGE("Failed to create UDP socket."); + return ret; + } + LOGI("create IPv4 UDP socket: %d", agent->udp_sockets[0].fd); + +#if CONFIG_IPV6 + if (ret = udp_socket_create(&agent->udp_sockets[1], AF_INET6) < 0) { + LOGE("Failed to create IPv6 UDP socket."); + return ret; + } + LOGI("create IPv6 UDP socket: %d", agent->udp_sockets[1].fd); +#endif + return 0; } -static int agent_socket_recv(Agent *agent, uint8_t *buf, int len) { +static int agent_socket_recv(Agent *agent, Address *addr, uint8_t *buf, int len) { +#if CONFIG_IPV6 + int nfds = 2; +#else int nfds = 1; +#endif int ret = -1; - struct pollfd fds[2]; + int i; + struct pollfd fds[nfds]; - fds[0].fd = agent->udp_sockets[0].fd; - fds[0].events = POLLIN; - ret = poll(fds, nfds, 1); + for (i = 0; i < nfds; i++) { + fds[i].fd = agent->udp_sockets[i].fd; + fds[i].events = POLLIN; + } + ret = poll(fds, nfds, AGENT_POLL_TIMEOUT); if (ret < 0) { LOGE("poll error"); } else if (ret == 0) { // timeout - } else if (fds[0].revents & POLLIN) { - ret = udp_socket_recvfrom(&agent->udp_sockets[0], NULL, buf, len); + } else { + + for (i = 0; i < nfds; i++) { + if (fds[i].revents & POLLIN) { + ret = udp_socket_recvfrom(&agent->udp_sockets[i], addr, buf, len); + break; + } + } } return ret; } static int agent_socket_send(Agent *agent, Address *addr, const uint8_t *buf, int len) { - return udp_socket_sendto(&agent->udp_sockets[0], addr, buf, len); + switch (addr->family) { + case AF_INET6: + return udp_socket_sendto(&agent->udp_sockets[1], addr, buf, len); + case AF_INET: + default: + return udp_socket_sendto(&agent->udp_sockets[0], addr, buf, len); + } + return -1; } static int agent_create_host_addr(Agent *agent) { - UdpSocket *udp_socket = &agent->udp_sockets[0]; + UdpSocket *udp_socket; + udp_socket = &agent->udp_sockets[0]; if (ports_get_host_addr(&udp_socket->bind_addr)) { + LOGD("addr: %d.%d.%d.%d", udp_socket->bind_addr.ipv4[0], udp_socket->bind_addr.ipv4[1], udp_socket->bind_addr.ipv4[2], udp_socket->bind_addr.ipv4[3]); IceCandidate *ice_candidate = agent->local_candidates + agent->local_candidates_count++; ice_candidate_create(ice_candidate, agent->local_candidates_count, ICE_CANDIDATE_TYPE_HOST, &udp_socket->bind_addr); } - return -1; +#if CONFIG_IPV6 + udp_socket = &agent->udp_sockets[1]; + if (ports_get_host_addr(&udp_socket->bind_addr)) { + LOGD("addr: %x:%x:%x:%x:%x:%x:%x:%x", udp_socket->bind_addr.ipv6[0], udp_socket->bind_addr.ipv6[1], udp_socket->bind_addr.ipv6[2], udp_socket->bind_addr.ipv6[3], udp_socket->bind_addr.ipv6[4], udp_socket->bind_addr.ipv6[5], udp_socket->bind_addr.ipv6[6], udp_socket->bind_addr.ipv6[7]); + IceCandidate *ice_candidate = agent->local_candidates + agent->local_candidates_count++; + ice_candidate_create(ice_candidate, agent->local_candidates_count, ICE_CANDIDATE_TYPE_HOST, &udp_socket->bind_addr); + } +#endif + return 0; } static int agent_create_bind_addr(Agent *agent, Address *serv_addr) { int ret = -1; + int retry = 0; Address bind_addr; StunMessage send_msg; StunMessage recv_msg; @@ -79,7 +124,14 @@ static int agent_create_bind_addr(Agent *agent, Address *serv_addr) { return ret; } - ret = agent_socket_recv(agent, recv_msg.buf, sizeof(recv_msg.buf)); + // blocking 1 second + while (retry < 1000) { + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); + if (ret > 0) { + break; + } + } + if (ret <= 0) { LOGD("Failed to receive STUN Binding Response."); return ret; @@ -87,7 +139,6 @@ static int agent_create_bind_addr(Agent *agent, Address *serv_addr) { stun_parse_msg_buf(&recv_msg); memcpy(&bind_addr, &recv_msg.mapped_addr, sizeof(Address)); - IceCandidate *ice_candidate = agent->local_candidates + agent->local_candidates_count++; ice_candidate_create(ice_candidate, agent->local_candidates_count, ICE_CANDIDATE_TYPE_SRFLX, &bind_addr); return ret; @@ -97,6 +148,7 @@ static int agent_create_turn_addr(Agent *agent, Address *serv_addr, const char * int ret = -1; uint32_t attr = ntohl(0x11000000); + int retry = 0; Address turn_addr; StunMessage send_msg; StunMessage recv_msg; @@ -112,9 +164,16 @@ static int agent_create_turn_addr(Agent *agent, Address *serv_addr, const char * return -1; } - ret = agent_socket_recv(agent, recv_msg.buf, sizeof(recv_msg.buf)); + // blocking 1 second + while (retry < 1000) { + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); + if (ret > 0) { + break; + } + } + if (ret <= 0) { - LOGD("Failed to receive TURN Binding Response."); + LOGD("Failed to receive STUN Binding Response."); return ret; } @@ -141,7 +200,7 @@ static int agent_create_turn_addr(Agent *agent, Address *serv_addr, const char * } memset(&recv_msg, 0, sizeof(recv_msg)); - ret = agent_socket_recv(agent, recv_msg.buf, sizeof(recv_msg.buf)); + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); if (ret <= 0) { LOGD("Failed to receive TURN Binding Response."); return ret; @@ -174,45 +233,46 @@ void agent_gather_candidate(Agent *agent, const char *urls, const char *username char *port = NULL; char hostname[64]; + int i; + int addr_type[1] = {AF_INET}; // ipv6 no need stun Address resolved_addr; memset(hostname, 0, sizeof(hostname)); memset(agent, 0, sizeof(Agent)); agent_create_sockets(agent); + agent_create_host_addr(agent); + do { if ((port = strstr(urls + 5, ":")) == NULL) { break; } - snprintf(hostname, port - urls - 5 + 1, "%s", urls + 5); - - if (!addr_ipv4_validate(hostname, strlen(hostname), &resolved_addr)) { - - ports_resolve_addr(hostname, &resolved_addr); - } - resolved_addr.port = atoi(port + 1); - - LOGI("resolved_addr.ipv4: %d.%d.%d.%d", - resolved_addr.ipv4[0], resolved_addr.ipv4[1], resolved_addr.ipv4[2], resolved_addr.ipv4[3]); - LOGI("resolved_addr.port: %d", resolved_addr.port); - - agent_create_host_addr(agent); - if (resolved_addr.port <= 0) { break; } + LOGI("resolved_addr.port: %d", resolved_addr.port); - if (strncmp(urls, "stun:", 5) == 0) { - - agent_create_bind_addr(agent, &resolved_addr); + snprintf(hostname, port - urls - 5 + 1, "%s", urls + 5); - } else if (strncmp(urls, "turn:", 5) == 0) { + for (i = 0; i < sizeof(addr_type) / sizeof(addr_type[0]); i++) { + resolved_addr.family = addr_type[i]; + if (ports_resolve_addr(hostname, &resolved_addr) == 0) { + LOGI("resolved_addr.ipv4: %d.%d.%d.%d", + resolved_addr.ipv4[0], resolved_addr.ipv4[1], resolved_addr.ipv4[2], resolved_addr.ipv4[3]); + } - agent_create_turn_addr(agent, &resolved_addr, username, credential); + if (strncmp(urls, "stun:", 5) == 0) { + LOGD("create stun addr"); + agent_create_bind_addr(agent, &resolved_addr); + } else if (strncmp(urls, "turn:", 5) == 0) { + LOGD("create turn addr"); + agent_create_turn_addr(agent, &resolved_addr, username, credential); + } } + } while (0); } @@ -237,7 +297,7 @@ void agent_get_local_description(Agent *agent, char *description, int length) { // remove last \n description[strlen(description)] = '\0'; - + LOGD("local description:\n%s", description); } int agent_send(Agent *agent, const uint8_t *buf, int len) { @@ -245,34 +305,48 @@ int agent_send(Agent *agent, const uint8_t *buf, int len) { return agent_socket_send(agent, &agent->nominated_pair->remote->addr, buf, len); } -void agent_process_stun_request(Agent *agent, StunMessage *stun_msg) { +static void agent_create_binding_response(Agent *agent, StunMessage *msg, Address *addr) { + + char username[584]; + char mapped_address[8]; + StunHeader *header; + stun_msg_create(msg, STUN_CLASS_RESPONSE | STUN_METHOD_BINDING); + header = (StunHeader *)msg->buf; + memcpy(header->transaction_id, agent->transaction_id, sizeof(header->transaction_id)); + snprintf(username, sizeof(username), "%s:%s", agent->local_ufrag, agent->remote_ufrag); + // TODO: XOR-MAPPED-ADDRESS + stun_set_mapped_address(mapped_address, NULL, addr); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_MAPPED_ADDRESS, 8, mapped_address); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_USERNAME, strlen(username), username); + stun_msg_finish(msg, STUN_CREDENTIAL_SHORT_TERM, agent->local_upwd, strlen(agent->local_upwd)); +} + +static void agent_create_binding_request(Agent *agent, StunMessage *msg) { + + uint64_t tie_breaker = 0; // always be controlled + // send binding request + stun_msg_create(msg, STUN_CLASS_REQUEST | STUN_METHOD_BINDING); + char username[584]; + memset(username, 0, sizeof(username)); + snprintf(username, sizeof(username), "%s:%s", agent->remote_ufrag, agent->local_ufrag); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_USERNAME, strlen(username), username); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_PRIORITY, 4, (char *)&agent->nominated_pair->priority); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_USE_CANDIDATE, 0, NULL); + stun_msg_write_attr(msg, STUN_ATTR_TYPE_ICE_CONTROLLED, 8, (char *)&tie_breaker); + stun_msg_finish(msg, STUN_CREDENTIAL_SHORT_TERM, agent->remote_upwd, strlen(agent->remote_upwd)); +} - switch (stun_msg->stunmethod) { +void agent_process_stun_request(Agent *agent, StunMessage *stun_msg, Address *addr) { + StunMessage msg; + StunHeader *header; + switch (stun_msg->stunmethod) { case STUN_METHOD_BINDING: if (stun_msg_is_valid(stun_msg->buf, stun_msg->size, agent->local_upwd) == 0) { - - StunHeader *header = (StunHeader *)stun_msg->buf; + header = (StunHeader *)stun_msg->buf; memcpy(agent->transaction_id, header->transaction_id, sizeof(header->transaction_id)); - //LOGD("recv STUN_MSG_TYPE_BINDING_REQUEST is valid"); - - StunMessage msg; - stun_msg_create(&msg, STUN_CLASS_RESPONSE | STUN_METHOD_BINDING); - - header = (StunHeader *)msg.buf; - memcpy(header->transaction_id, agent->transaction_id, sizeof(header->transaction_id)); - - char username[584]; - snprintf(username, sizeof(username), "%s:%s", agent->local_ufrag, agent->remote_ufrag); - - // TODO: XOR-MAPPED-ADDRESS - char mapped_address[8]; - stun_set_mapped_address(mapped_address, NULL, &agent->nominated_pair->remote->addr); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_MAPPED_ADDRESS, 8, mapped_address); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_USERNAME, strlen(username), username); - stun_msg_finish(&msg, STUN_CREDENTIAL_SHORT_TERM, agent->local_upwd, strlen(agent->local_upwd)); - agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size); - agent->binding_request_time = utils_get_timestamp(); + agent_create_binding_response(agent, &msg, addr); + agent_socket_send(agent, addr, msg.buf, msg.size); } break; default: @@ -283,17 +357,10 @@ void agent_process_stun_request(Agent *agent, StunMessage *stun_msg) { void agent_process_stun_response(Agent *agent, StunMessage *stun_msg) { switch (stun_msg->stunmethod) { - case STUN_METHOD_BINDING: - LOGD("recv STUN_MSG_TYPE_BINDING_RESPONSE"); - if (stun_msg_is_valid(stun_msg->buf, stun_msg->size, agent->remote_upwd) == 0) { - - LOGD("recv STUN_MSG_TYPE_BINDING_RESPONSE is valid"); - agent->nominated_pair->state = ICE_CANDIDATE_STATE_SUCCEEDED; } - break; default: break; @@ -305,20 +372,20 @@ int agent_recv(Agent *agent, uint8_t *buf, int len) { int ret = -1; StunMessage stun_msg; - if ((ret = agent_socket_recv(agent, buf, len)) > 0 && stun_probe(buf, len) == 0) { + Address addr; + if ((ret = agent_socket_recv(agent, &addr, buf, len)) > 0 && stun_probe(buf, len) == 0) { memcpy(stun_msg.buf, buf, ret); stun_msg.size = ret; stun_parse_msg_buf(&stun_msg); switch (stun_msg.stunclass) { case STUN_CLASS_REQUEST: - agent_process_stun_request(agent, &stun_msg); + agent_process_stun_request(agent, &stun_msg, &addr); break; case STUN_CLASS_RESPONSE: agent_process_stun_response(agent, &stun_msg); break; case STUN_CLASS_ERROR: - agent->nominated_pair->state = ICE_CANDIDATE_STATE_WAITING; break; default: break; @@ -367,87 +434,80 @@ a=candidate:1 1 UDP 1 36.231.28.50 38143 typ srflx // Please set gather candidates before set remote description for (i = 0; i < agent->local_candidates_count; i++) { - for (j = 0; j < agent->remote_candidates_count; j++) { - - agent->candidate_pairs[agent->candidate_pairs_num].local = &agent->local_candidates[i]; - agent->candidate_pairs[agent->candidate_pairs_num].remote = &agent->remote_candidates[j]; - agent->candidate_pairs[agent->candidate_pairs_num].priority = agent->local_candidates[i].priority + agent->remote_candidates[j].priority; - agent->candidate_pairs[agent->candidate_pairs_num].state = ICE_CANDIDATE_STATE_FROZEN; - agent->candidate_pairs_num++; + if (agent->local_candidates[i].addr.family == agent->remote_candidates[j].addr.family) { + agent->candidate_pairs[agent->candidate_pairs_num].local = &agent->local_candidates[i]; + agent->candidate_pairs[agent->candidate_pairs_num].remote = &agent->remote_candidates[j]; + agent->candidate_pairs[agent->candidate_pairs_num].priority = agent->local_candidates[i].priority + agent->remote_candidates[j].priority; + agent->candidate_pairs[agent->candidate_pairs_num].state = ICE_CANDIDATE_STATE_FROZEN; + agent->candidate_pairs_num++; + } } } + LOGD("candidate pairs num: %d", agent->candidate_pairs_num); } + int agent_connectivity_check(Agent *agent) { uint8_t buf[1400]; - StunMessage msg; - memset(&msg, 0, sizeof(msg)); - if (agent->nominated_pair->state == ICE_CANDIDATE_STATE_WAITING) { - agent_recv(agent, buf, sizeof(buf)); + if (agent->nominated_pair->state != ICE_CANDIDATE_STATE_INPROGRESS) { + LOGI("nominated pair is not in progress"); + return -1; + } - stun_msg_create(&msg, STUN_CLASS_REQUEST | STUN_METHOD_BINDING); - char username[584]; - memset(username, 0, sizeof(username)); - snprintf(username, sizeof(username), "%s:%s", agent->remote_ufrag, agent->local_ufrag); + memset(&msg, 0, sizeof(msg)); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_USERNAME, strlen(username), username); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_PRIORITY, 4, (char *)&agent->nominated_pair->priority); - uint64_t tie_breaker = utils_get_timestamp(); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_USE_CANDIDATE, 0, NULL); - stun_msg_write_attr(&msg, STUN_ATTR_TYPE_ICE_CONTROLLED, 8, (char *)&tie_breaker); - stun_msg_finish(&msg, STUN_CREDENTIAL_SHORT_TERM, agent->remote_upwd, strlen(agent->remote_upwd)); + if (agent->nominated_pair->conncheck % AGENT_CONNCHECK_PERIOD == 0) { - LOGD("send binding request to remote ip: %d.%d.%d.%d, port: %d", agent->nominated_pair->remote->addr.ipv4[0], agent->nominated_pair->remote->addr.ipv4[1], agent->nominated_pair->remote->addr.ipv4[2], agent->nominated_pair->remote->addr.ipv4[3], agent->nominated_pair->remote->addr.port); + if (agent->nominated_pair->remote->addr.family == AF_INET) { + LOGD("send binding request to remote ip: %d.%d.%d.%d, port: %d", agent->nominated_pair->remote->addr.ipv4[0], agent->nominated_pair->remote->addr.ipv4[1], agent->nominated_pair->remote->addr.ipv4[2], agent->nominated_pair->remote->addr.ipv4[3], agent->nominated_pair->remote->addr.port); + } else { + char astring[INET6_ADDRSTRLEN]; + addr_to_text(&(agent->nominated_pair->remote->addr), astring, INET6_ADDRSTRLEN); + LOGD("send binding request to remote ip: %s, port: %d", astring, agent->nominated_pair->remote->addr.port); + } + agent_create_binding_request(agent, &msg); agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size); + } - agent->nominated_pair->state = ICE_CANDIDATE_STATE_INPROGRESS; - - } else if (agent->nominated_pair->state == ICE_CANDIDATE_STATE_INPROGRESS) { + agent_recv(agent, buf, sizeof(buf)); - agent_recv(agent, buf, sizeof(buf)); + // XXX: FULL ICE + if (agent->nominated_pair->state == ICE_CANDIDATE_STATE_SUCCEEDED) { + agent->selected_pair = agent->nominated_pair; + return 0; } - return agent->nominated_pair->state == ICE_CANDIDATE_STATE_SUCCEEDED; + return -1; } -void agent_select_candidate_pair(Agent *agent) { +int agent_select_candidate_pair(Agent *agent) { int i; - - time_t t2 = time(NULL); - - //LOGD("Mode: %d", agent->mode); - for (i = 0; i < agent->candidate_pairs_num; i++) { if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_FROZEN) { - // nominate this pair agent->nominated_pair = &agent->candidate_pairs[i]; - agent->nominated_pair->state = ICE_CANDIDATE_STATE_WAITING; - agent->candidate_pairs[i].nominated_time = time(NULL); - break; - - } else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_INPROGRESS - && (t2 - agent->candidate_pairs[i].nominated_time) > 2) { - - LOGD("timeout for nominate (pair %d)", i); - agent->nominated_pair->state = ICE_CANDIDATE_STATE_FAILED; - + agent->candidate_pairs[i].conncheck = 0; + agent->candidate_pairs[i].state = ICE_CANDIDATE_STATE_INPROGRESS; + return 0; + } else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_INPROGRESS) { + agent->candidate_pairs[i].conncheck++; + if (agent->candidate_pairs[i].conncheck < AGENT_CONNCHECK_MAX) { + return 0; + } + agent->candidate_pairs[i].state = ICE_CANDIDATE_STATE_FAILED; } else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_FAILED) { - } else if (agent->candidate_pairs[i].state <= ICE_CANDIDATE_STATE_SUCCEEDED) { - // still in progress. wait for it - agent->nominated_pair = &agent->candidate_pairs[i]; - break; + } else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_SUCCEEDED) { + agent->selected_pair = &agent->candidate_pairs[i]; + return 0; } - } - - //LOGD("nominated_pair: %p", agent->nominated_pair); + // all candidate pairs are failed + return -1; } - diff --git a/src/agent.h b/src/agent.h index 92a4281..58567fc 100644 --- a/src/agent.h +++ b/src/agent.h @@ -46,11 +46,9 @@ struct Agent { char local_upwd[ICE_UPWD_LENGTH + 1]; IceCandidate local_candidates[AGENT_MAX_CANDIDATES]; - IceCandidate remote_candidates[AGENT_MAX_CANDIDATES]; int local_candidates_count; - int remote_candidates_count; UdpSocket udp_socket; @@ -89,7 +87,7 @@ void agent_set_remote_description(Agent *agent, char *description); void *agent_thread(void *arg); -void agent_select_candidate_pair(Agent *agent); +int agent_select_candidate_pair(Agent *agent); void agent_attach_recv_cb(Agent *agent, void (*data_recv_cb)(char *buf, int len, void *user_data)); diff --git a/src/config.h b/src/config.h index 8ec275b..627e46a 100644 --- a/src/config.h +++ b/src/config.h @@ -36,7 +36,7 @@ #define WHIP_PORT 443 #define KEEPALIVE_CONNCHECK 0 - +#define CONFIG_IPV6 0 // default use wifi interface #define IFR_NAME "w" diff --git a/src/ice.c b/src/ice.c index b58c610..b5a0d3f 100644 --- a/src/ice.c +++ b/src/ice.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "ports.h" #include "udp.h" @@ -77,18 +78,31 @@ void ice_candidate_to_description(IceCandidate *candidate, char *description, in default: break; } - - snprintf(description, length, "a=candidate:%d %d %s %" PRIu32 " %d.%d.%d.%d %d typ %s\n", - candidate->foundation, - candidate->component, - candidate->transport, - candidate->priority, - candidate->addr.ipv4[0], - candidate->addr.ipv4[1], - candidate->addr.ipv4[2], - candidate->addr.ipv4[3], - candidate->addr.port, - typ_raddr); + LOGI("candidate->addr.family: %d", candidate->addr.family); + if (candidate->addr.family == AF_INET6) { + char ipv6str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, candidate->addr.ipv6, ipv6str, INET6_ADDRSTRLEN); + snprintf(description, length, "a=candidate:%d %d %s %" PRIu32 " %s %d typ %s\n", + candidate->foundation, + candidate->component, + candidate->transport, + candidate->priority, + ipv6str, + candidate->addr.port, + typ_raddr); + } else { + snprintf(description, length, "a=candidate:%d %d %s %" PRIu32 " %d.%d.%d.%d %d typ %s\n", + candidate->foundation, + candidate->component, + candidate->transport, + candidate->priority, + candidate->addr.ipv4[0], + candidate->addr.ipv4[1], + candidate->addr.ipv4[2], + candidate->addr.ipv4[3], + candidate->addr.port, + typ_raddr); + } } int ice_candidate_from_description(IceCandidate *candidate, char *description, char *end) { @@ -127,10 +141,14 @@ int ice_candidate_from_description(IceCandidate *candidate, char *description, c return -1; } LOGD("mDNS host: %s, ip: %d.%d.%d.%d", buf, candidate->addr.ipv4[0], candidate->addr.ipv4[1], candidate->addr.ipv4[2], candidate->addr.ipv4[3]); - } else if (!addr_ipv4_validate(buf, strlen(buf), &candidate->addr)) { - LOGW("Unknow address"); + } else if (addr_ipv4_validate(buf, strlen(buf), &candidate->addr)) { + candidate->addr.family = AF_INET; + } else if (addr_ipv6_validate(buf, strlen(buf), &candidate->addr)) { + candidate->addr.family = AF_INET6; + } else { return -1; - } + } + break; case 5: candidate->addr.port = atoi(buf); diff --git a/src/ice.h b/src/ice.h index dbe37ba..add35ab 100644 --- a/src/ice.h +++ b/src/ice.h @@ -56,13 +56,9 @@ typedef struct IceCandidatePair IceCandidatePair; struct IceCandidatePair { IceCandidateState state; - IceCandidate *local; - IceCandidate *remote; - - time_t nominated_time; - + int conncheck; uint64_t priority; }; diff --git a/src/peer_connection.c b/src/peer_connection.c index 5feeeeb..a9e05ef 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -362,19 +362,11 @@ int peer_connection_loop(PeerConnection *pc) { case PEER_CONNECTION_CHECKING: - agent_select_candidate_pair(&pc->agent); - - if (!pc->agent.nominated_pair) { + if (agent_select_candidate_pair(&pc->agent) < 0) { STATE_CHANGED(pc, PEER_CONNECTION_FAILED); - - } else if (agent_connectivity_check(&pc->agent)) { - - LOGD("Connectivity check success. pair: %p", pc->agent.nominated_pair); - + } else if (agent_connectivity_check(&pc->agent) == 0) { STATE_CHANGED(pc, PEER_CONNECTION_CONNECTED); - pc->agent.selected_pair = pc->agent.nominated_pair; } - break; case PEER_CONNECTION_CONNECTED: diff --git a/src/ports.c b/src/ports.c index 9b73be7..0494499 100644 --- a/src/ports.c +++ b/src/ports.c @@ -50,6 +50,7 @@ int ports_get_host_addr(Address *addr) { ret = 1; break; case AF_INET6: + LOGI("this is ipv6"); memcpy(addr->ipv6, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr.s6_addr, 16); ret = 1; break; @@ -117,9 +118,9 @@ LOGI("get_host_address inside while loop"); } int ports_resolve_addr(const char *host, Address *addr) { - int ret = -1; struct addrinfo hints, *res, *p; + int family; int status; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -131,12 +132,25 @@ int ports_resolve_addr(const char *host, Address *addr) { return ret; } - for (p = res; p != NULL; p = p->ai_next) { + if (addr->family == AF_INET6) { + family = AF_INET6; + } else { + family = AF_INET; + } - if (p->ai_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + for (p = res; p != NULL; p = p->ai_next) { + if (p->ai_family == family) { + switch (p->ai_family) { + case AF_INET6: + memcpy(addr->ipv6, &((struct sockaddr_in6 *)p->ai_addr)->sin6_addr.s6_addr, 16); + break; + case AF_INET: + LOGI("AF_INET"); + memcpy(addr->ipv4, &((struct sockaddr_in *)p->ai_addr)->sin_addr.s_addr, 4); + default: + break; + } ret = 0; - memcpy(addr->ipv4, &ipv4->sin_addr.s_addr, 4); } } diff --git a/src/stun.c b/src/stun.c index 62bd546..80e6794 100644 --- a/src/stun.c +++ b/src/stun.c @@ -83,22 +83,27 @@ void stun_set_mapped_address(char *value, uint8_t *mask, Address *addr) { void stun_get_mapped_address(char *value, uint8_t *mask, Address *addr) { + int i; uint32_t *addr32 = (uint32_t *)addr->ipv4; + uint16_t *addr16 = (uint16_t *)addr->ipv6; addr->family = value[1]; + addr->port = ntohs(*(uint16_t *)(value + 2) ^ *(uint16_t*)mask); + LOGD("family: %d, %d", AF_INET, AF_INET6); + LOGD("XOR Mapped Address Family: 0x%02x", addr->family); + LOGD("XOR Mapped Address Port: %d", addr->port); + if (addr->family == 0x02) { + addr->family = AF_INET6; + for (i = 0; i < 8; i++) { + addr16[i] = (*(uint16_t *)(value + 4 + 2*i) ^ *(uint16_t*)(mask + 2*i)); + } + LOGD("XOR Mapped Address Address: %x:%x:%x:%x:%x:%x:%x:%x", addr->ipv6[0], addr->ipv6[1], addr->ipv6[2], addr->ipv6[3], addr->ipv6[4], addr->ipv6[5], addr->ipv6[6], addr->ipv6[7]); - if (addr->family == 0x01) { - - addr->port = ntohs(*(uint16_t *)(value + 2) ^ *(uint16_t*)mask); + } else if (addr->family == 0x01) { + addr->family = AF_INET; *addr32 = (*(uint32_t *)(value + 4) ^ *(uint32_t*)mask); - - } else { - - LOGW("Not support IPv6"); + LOGD("XOR Mapped Address Address: %d.%d.%d.%d", addr->ipv4[0], addr->ipv4[1], addr->ipv4[2], addr->ipv4[3]); } - LOGD("XOR Mapped Address Family: 0x%02x", addr->family); - LOGD("XOR Mapped Address Port: %d", addr->port); - LOGD("XOR Mapped Address Address: %d.%d.%d.%d", addr->ipv4[0], addr->ipv4[1], addr->ipv4[2], addr->ipv4[3]); } void stun_parse_msg_buf(StunMessage *msg) { diff --git a/src/udp.c b/src/udp.c index 3eb99d7..9801c2d 100644 --- a/src/udp.c +++ b/src/udp.c @@ -174,9 +174,10 @@ int udp_get_local_address(UdpSocket *udp_socket, Address *addr) { int udp_socket_sendto(UdpSocket *udp_socket, Address *addr, const uint8_t *buf, int len) { - fd_set write_set; - struct timeval tv; struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr *sa; + socklen_t sin_len; int ret = -1; if (udp_socket->fd < 0) { @@ -185,22 +186,25 @@ int udp_socket_sendto(UdpSocket *udp_socket, Address *addr, const uint8_t *buf, return -1; } - FD_ZERO(&write_set); - FD_SET(udp_socket->fd, &write_set); - - tv.tv_sec = udp_socket->timeout_sec; - tv.tv_usec = udp_socket->timeout_usec; - sin.sin_family = AF_INET; - - memcpy(&sin.sin_addr.s_addr, addr->ipv4, 4); - - //LOGD("s_addr: %d", sin.sin_addr.s_addr); - - sin.sin_port = htons(addr->port); - - //LOGD("sendto addr %d.%d.%d.%d (%d)", addr->ipv4[0], addr->ipv4[1], addr->ipv4[2], addr->ipv4[3], addr->port); + switch (addr->family) { + case AF_INET6: + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(addr->port); + memcpy(&sin6.sin6_addr, addr->ipv6, 16); + sa = (struct sockaddr *)&sin6; + sin_len = sizeof(sin6); + break; + case AF_INET: + default: + sin.sin_family = AF_INET; + sin.sin_port = htons(addr->port); + memcpy(&sin.sin_addr.s_addr, addr->ipv4, 4); + sa = (struct sockaddr *)&sin; + sin_len = sizeof(sin); + break; + } - ret = sendto(udp_socket->fd, buf, len, 0, (struct sockaddr *)&sin, sizeof(sin)); + ret = sendto(udp_socket->fd, buf, len, 0, sa, sin_len); if (ret < 0) { @@ -243,6 +247,22 @@ int udp_socket_recvfrom(UdpSocket *udp_socket, Address *addr, uint8_t *buf, int return -1; } + if (addr) { + switch (udp_socket->bind_addr.family) { + case AF_INET6: + addr->family = AF_INET6; + addr->port = ntohs(sin6.sin6_port); + memcpy(addr->ipv6, &sin6.sin6_addr, 16); + break; + case AF_INET: + default: + addr->family = AF_INET; + addr->port = ntohs(sin.sin_port); + memcpy(addr->ipv4, &sin.sin_addr.s_addr, 4); + break; + } + } + return ret; }