size_t stun_usage_bind_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len) { stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); return stun_agent_finish_message (agent, msg, NULL, 0); }
size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *previous_response, int32_t lifetime, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, StunUsageTurnCompatibility compatibility) { if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { return stun_usage_turn_create (agent, msg, buffer, buffer_len, previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime, username, username_len, password, password_len, compatibility); } stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_REFRESH); if (lifetime >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (previous_response) { uint8_t *realm; uint8_t *nonce; uint16_t len; realm = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_REALM, &len); if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } nonce = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_NONCE, &len); if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } if (username != NULL && username_len > 0) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
static void check_af (const char *name, int family, socklen_t addrlen) { struct sockaddr_storage addr; uint8_t buf[100]; StunAgent agent; StunMessage msg; uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, STUN_ATTRIBUTE_ERROR_CODE, 0}; stun_agent_init (&agent, known_attributes, STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); assert (addrlen <= sizeof (addr)); memset (&addr, 0, sizeof (addr)); stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr *) &addr, addrlen) != STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS) fatal ("Unknown address family test failed"); if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr, addrlen) != STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS) fatal ("Unknown address family xor test failed"); addr.ss_family = family; if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr *) &addr, addrlen - 1) != STUN_MESSAGE_RETURN_INVALID) fatal ("Too small %s sockaddr test failed", name); if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr, addrlen - 1) != STUN_MESSAGE_RETURN_INVALID) fatal ("Too small %s sockaddr xor test failed", name); if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr *) &addr, addrlen) != STUN_MESSAGE_RETURN_SUCCESS) fatal ("%s sockaddr test failed", name); if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr, addrlen) != STUN_MESSAGE_RETURN_SUCCESS) fatal ("%s sockaddr xor test failed", name); }
size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, uint8_t *realm, size_t realm_len, uint8_t *nonce, size_t nonce_len, struct sockaddr *peer, StunUsageTurnCompatibility compatibility) { if (!peer) return 0; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_CREATEPERMISSION); /* PEER address */ if (stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer, sizeof(*peer)) != STUN_MESSAGE_RETURN_SUCCESS) { return 0; } /* nonce */ if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, nonce_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } /* realm */ if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, realm_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } /* username */ if (username != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
size_t stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, const uint8_t *username, const size_t username_len, const uint8_t *password, const size_t password_len, bool cand_use, bool controlling, uint32_t priority, uint64_t tie, StunUsageIceCompatibility compatibility) { StunMessageReturn val; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245) { if (cand_use) { val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (controlling) val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie); else val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (username && username_len > 0) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
int main (void) { uint8_t buf[100]; size_t len; union { struct sockaddr_storage storage; struct sockaddr addr; } addr; StunAgent agent; StunMessage msg; uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, STUN_ATTRIBUTE_ERROR_CODE, 0}; stun_agent_init (&agent, known_attributes, STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); /* Request formatting test */ stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); finish_check (&agent, &msg); if (memcmp (buf, "\x00\x01", 2)) fatal ("Request formatting test failed"); /* Response formatting test */ stun_agent_init_response (&agent, &msg, buf, sizeof (buf), &msg); finish_check (&agent, &msg); if (memcmp (buf, "\x01\x01", 2)) fatal ("Response formatting test failed"); /* Error formatting test */ stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); finish_check (&agent, &msg); if (!stun_agent_init_error (&agent, &msg, buf, sizeof (buf), &msg, 400)) fatal ("Error initialization test failed"); finish_check (&agent, &msg); if (memcmp (buf, "\x01\x11", 2)) fatal ("Error formatting test failed"); /* Unknown error formatting test */ stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); finish_check (&agent, &msg); if (!stun_agent_init_error (&agent, &msg, buf, sizeof (buf), &msg, 666)) fatal ("Unknown error initialization test failed"); finish_check (&agent, &msg); if (memcmp (buf, "\x01\x11", 2)) fatal ("Unknown error formatting test failed"); /* Overflow tests */ stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); for (len = 0; stun_message_append_flag (&msg, 0xffff) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; len += 4) { if (len > 0xffff) fatal ("Overflow protection test failed"); } if (stun_message_append32 (&msg, 0xffff, 0x12345678) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) fatal ("Double-word overflow test failed"); if (stun_message_append64 (&msg, 0xffff, 0x123456789abcdef0) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) fatal ("Quad-word overflow test failed"); if (stun_message_append_string (&msg, 0xffff, "foobar") != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) fatal ("String overflow test failed"); memset (&addr, 0, sizeof (addr)); addr.addr.sa_family = AF_INET; #ifdef HAVE_SS_LEN addr.addr.ss_len = sizeof (addr); #endif if (stun_message_append_xor_addr (&msg, 0xffff, &addr.storage, sizeof (addr)) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) fatal ("Address overflow test failed"); len = sizeof (msg); if (stun_agent_finish_message (&agent, &msg, NULL, 0) != 0) fatal ("Fingerprint overflow test failed"); if (stun_agent_finish_message (&agent, &msg, pwd, strlen ((char *) pwd)) != 0) fatal ("Message integrity overflow test failed"); /* Address attributes tests */ check_af ("IPv4", AF_INET, sizeof (struct sockaddr_in)); #ifdef AF_INET6 check_af ("IPv6", AF_INET6, sizeof (struct sockaddr_in6)); #endif return 0; }
int main (void) { union { struct sockaddr sa; struct sockaddr_storage storage; struct sockaddr_in ip4; } addr; uint8_t req_buf[STUN_MAX_MESSAGE_SIZE]; uint8_t resp_buf[STUN_MAX_MESSAGE_SIZE]; const const uint64_t tie = 0x8000000000000000LL; StunMessageReturn val; StunUsageIceReturn val2; size_t len; size_t rlen; static char username[] = "L:R"; static uint8_t ufrag[] = "L", pass[] = "secret"; size_t ufrag_len = strlen ((char*) ufrag); size_t pass_len = strlen ((char*) pass); int code; bool control = false; StunAgent agent; StunMessage req; StunMessage resp; StunDefaultValidaterData validater_data[] = { {ufrag, ufrag_len, pass, pass_len}, {(uint8_t *) username, strlen (username), pass, pass_len}, {NULL, 0, NULL, 0}}; StunValidationStatus valid; stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT | STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); memset (&addr, 0, sizeof (addr)); addr.ip4.sin_family = AF_INET; #ifdef HAVE_SA_LEN addr.ip4.sin_len = sizeof (addr); #endif addr.ip4.sin_port = htons (12345); addr.ip4.sin_addr.s_addr = htonl (0x7f000001); /* Incorrect message class */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); assert (stun_agent_init_response (&agent, &req, req_buf, sizeof (req_buf), &req)); rlen = stun_agent_finish_message (&agent, &req, NULL, 0); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_REQUEST); assert (len == 0); /* Incorrect message method */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), 0x666)); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_METHOD); assert (len > 0); /* Unknown attribute */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append_string (&req, 0x666, "The evil unknown attribute!"); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE); /* Unauthenticated message */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); rlen = stun_agent_finish_message (&agent, &req, NULL, 0); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); /* No username */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); assert (stun_usage_ice_conncheck_priority (&req) == 0); assert (stun_usage_ice_conncheck_use_candidate (&req) == false); /* Good message */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append32 (&req, STUN_ATTRIBUTE_PRIORITY, 0x12345678); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_flag (&req, STUN_ATTRIBUTE_USE_CANDIDATE); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char*) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS); assert (len > 0); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_RESPONSE); assert (stun_usage_ice_conncheck_priority (&req) == 0x12345678); assert (stun_usage_ice_conncheck_use_candidate (&req) == true); /* Invalid socket address */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); addr.ip4.sin_family = AF_UNSPEC; len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_ADDRESS); assert (len == 0); addr.ip4.sin_family = AF_INET; /* Lost role conflict */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie + 1); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); control = true; val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); assert (len > 0); assert (control == false); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_RESPONSE); /* Won role conflict */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie - 1); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); control = false; val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS); assert (len > 0); assert (control == false); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_ERROR); stun_message_find_error (&resp, &code); assert (code == STUN_ERROR_ROLE_CONFLICT); return 0; }
size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *previous_response, StunUsageTurnRequestPorts request_props, int32_t bandwidth, int32_t lifetime, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, StunUsageTurnCompatibility compatibility) { stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE); if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (bandwidth >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } else { if (stun_message_append32 (msg, STUN_ATTRIBUTE_MAGIC_COOKIE, TURN_MAGIC_COOKIE) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (lifetime >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) { uint32_t req = 0; if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE) { req |= REQUESTED_PROPS_R; req |= REQUESTED_PROPS_E; } else if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN) { req |= REQUESTED_PROPS_E; } if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, req) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (previous_response) { uint8_t *realm; uint8_t *nonce; uint64_t reservation; uint16_t len; realm = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_REALM, &len); if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } nonce = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_NONCE, &len); if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (stun_message_find64 (previous_response, STUN_ATTRIBUTE_RESERVATION_TOKEN, &reservation) == STUN_MESSAGE_RETURN_SUCCESS) { if (stun_message_append64 (msg, STUN_ATTRIBUTE_RESERVATION_TOKEN, reservation) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } if (username != NULL && username_len > 0) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
size_t stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, const uint8_t *username, const size_t username_len, const uint8_t *password, const size_t password_len, bool cand_use, bool controlling, uint32_t priority, uint64_t tie, const char *candidate_identifier, StunUsageIceCompatibility compatibility) { StunMessageReturn val; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 || compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { if (cand_use) { val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (controlling) val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie); else val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (username && username_len > 0) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2 && candidate_identifier) { size_t identifier_len = strlen(candidate_identifier); size_t attribute_len = identifier_len; int modulo4 = identifier_len % 4; uint8_t* buf; if (modulo4) attribute_len += 4 - modulo4; // Avoid a coverify false positive assert (attribute_len >= identifier_len); buf = malloc(attribute_len); memset(buf, 0, attribute_len); memcpy(buf, candidate_identifier, identifier_len); val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER, buf, attribute_len); free(buf); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; val = stun_message_append32 (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }