/**@ingroup thttp_auth_group * Generates digest HA2 value as per RFC 2617 subclause 3.2.2.3. * * * @param [in,out] method The HTTP/SIP method name. * @param [in,out] url The HTTP URL or SIP URI of the request. * @param [in,out] entity_body The entity body. * @param [in,out] qop The Quality Of Protection. * @param [in,out] ha2 A pointer to the response. * * @return Zero if succeed and non-zero error code otherwise. **/ int thttp_auth_digest_HA2(const char* method, const char* url, const tsk_buffer_t* entity_body, const char* qop, tsk_md5string_t* ha2) { int ret; /* RFC 2617 - 3.2.2.3 A2 If the "qop" directive's value is "auth" or is unspecified, then A2 is: A2 = Method ":" digest-url-value If the "qop" value is "auth-int", then A2 is: A2 = Method ":" digest-url-value ":" H(entity-body) */ char *a2 = tsk_null; if (!qop || tsk_strempty(qop) || tsk_striequals(qop, "auth")){ tsk_sprintf(&a2, "%s:%s", method, url); } else if (tsk_striequals(qop, "auth-int")) { if (entity_body && entity_body->data){ tsk_md5string_t hEntity; if ((ret = tsk_md5compute(entity_body->data, entity_body->size, &hEntity))){ goto bail; } tsk_sprintf(&a2, "%s:%s:%s", method, url, hEntity); } else{ tsk_sprintf(&a2, "%s:%s:%s", method, url, TSK_MD5_EMPTY); } } ret = tsk_md5compute(a2, tsk_strlen(a2), ha2); bail: TSK_FREE(a2); return ret; }
//================================================================================================= // SOCKET object definition // static tsk_object_t* tnet_socket_ctor(tsk_object_t * self, va_list * app) { tnet_socket_t *sock = self; if(sock){ int status; tsk_bool_t nonblocking; tsk_bool_t bindsocket; tsk_istr_t port; struct addrinfo *result = 0; struct addrinfo *ptr = 0; struct addrinfo hints; tnet_host_t local_hostname; const char *host = va_arg(*app, const char*); #if defined(__GNUC__) sock->port = (tnet_port_t)va_arg(*app, unsigned); #else sock->port = va_arg(*app, tnet_port_t); #endif tsk_itoa(sock->port, &port); sock->type = va_arg(*app, tnet_socket_type_t); nonblocking = va_arg(*app, tsk_bool_t); bindsocket = va_arg(*app, tsk_bool_t); memset(local_hostname, 0, sizeof(local_hostname)); /* Get the local host name */ if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){ memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host)); } else{ if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){ memcpy(local_hostname, "::", 2); } else{ memcpy(local_hostname, "0.0.0.0", 7); } //if((status = tnet_gethostname(&local_hostname))) //{ // TNET_PRINT_LAST_ERROR("gethostname have failed."); // goto bail; //} } /* hints address info structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET); hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM; hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP; hints.ai_flags = AI_PASSIVE #if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600 | AI_ADDRCONFIG #endif ; /* Performs getaddrinfo */ if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){ TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]", hints.ai_family, local_hostname, port, tnet_gai_strerror(status)); goto bail; } /* Find our address. */ for(ptr = result; ptr; ptr = ptr->ai_next){ sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){ continue; } if(bindsocket){ /* Bind the socket */ if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){ TNET_PRINT_LAST_ERROR("bind have failed."); tnet_socket_close(sock); continue; } /* Get local IP string. */ if(status = tnet_get_ip_n_port(sock->fd , &sock->ip, &sock->port)) /* % */ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST))) { TNET_PRINT_LAST_ERROR("Failed to get local IP and port."); tnet_socket_close(sock); continue; } // else{ //#if TNET_UNDER_WINDOWS // int index; // if((index = tsk_strindexOf(sock->ip, tsk_strlen(sock->ip), "%")) > 0){ // *(sock->ip + index) = '\0'; // } //#endif // } } /* sets the real socket type (if ipv46) */ if(ptr->ai_family == AF_INET6) { TNET_SOCKET_TYPE_SET_IPV6Only(sock->type); } else{ TNET_SOCKET_TYPE_SET_IPV4Only(sock->type); } break; } /* Check socket validity. */ if(!TNET_SOCKET_IS_VALID(sock)) { TNET_PRINT_LAST_ERROR("Invalid socket."); goto bail; } /* To avoid "Address already in use" error */ { #if defined(SOLARIS) char yes = '1'; #else int yes = 1; #endif if(setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int))){ TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR) have failed."); } } /* Sets the socket to nonblocking mode */ if(nonblocking){ if((status = tnet_sockfd_set_nonblocking(sock->fd))){ goto bail; } } bail: /* Free addrinfo */ tnet_freeaddrinfo(result); /* Close socket if failed. */ if(status && TNET_SOCKET_IS_VALID(sock)){ tnet_socket_close(sock); } } return self; }
/**@ingroup tnet_socket_group * Creates a new socket. * To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function. * @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string. * @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port. * @param type The type of the socket. See @ref tnet_socket_type_t. * @param nonblocking Indicates whether to create non-blocking socket. * @param bindsocket Indicates whether to bind the newly created socket or not. * @retval @ref tnet_socket_t object. * @sa @ref tnet_socket_create. */ tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket) { tnet_socket_t *sock; if ((sock = tsk_object_new(tnet_socket_def_t))) { int status; tsk_istr_t port; struct addrinfo *result = tsk_null; struct addrinfo *ptr = tsk_null; struct addrinfo hints; tnet_host_t local_hostname; sock->port = port_; tsk_itoa(sock->port, &port); sock->type = type; memset(local_hostname, 0, sizeof(local_hostname)); /* Get the local host name */ if (host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){ memcpy(local_hostname, host, tsk_strlen(host) > sizeof(local_hostname) - 1 ? sizeof(local_hostname) - 1 : tsk_strlen(host)); } else{ if (TNET_SOCKET_TYPE_IS_IPV6(sock->type)){ memcpy(local_hostname, "::", 2); } else { memcpy(local_hostname, "0.0.0.0", 7); } } /* hints address info structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET); hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM; hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP; hints.ai_flags = AI_PASSIVE #if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600 | AI_ADDRCONFIG #endif ; /* Performs getaddrinfo */ if ((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))) { TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]", hints.ai_family, local_hostname, port, tnet_gai_strerror(status)); goto bail; } /* Find our address. */ for (ptr = result; ptr; ptr = ptr->ai_next){ sock->fd = (tnet_fd_t)tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){ continue; } /* To avoid "Address already in use" error * Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS. */ // if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) { if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) { // do not break...continue } } if (bindsocket){ /* Bind the socket */ if ((status = bind(sock->fd, ptr->ai_addr, (int)ptr->ai_addrlen))){ TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port); tnet_socket_close(sock); continue; } /* Get local IP string. */ if ((status = tnet_get_ip_n_port(sock->fd, tsk_true/*local*/, &sock->ip, &sock->port))) /* % */ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST))) { TNET_PRINT_LAST_ERROR("Failed to get local IP and port."); tnet_socket_close(sock); continue; } } /* sets the real socket type (if ipv46) */ if (ptr->ai_family == AF_INET6) { TNET_SOCKET_TYPE_SET_IPV6Only(sock->type); } else { TNET_SOCKET_TYPE_SET_IPV4Only(sock->type); } break; } /* Check socket validity. */ if (!TNET_SOCKET_IS_VALID(sock)) { TNET_PRINT_LAST_ERROR("Invalid socket."); goto bail; } #if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR /* disable SIGPIPE signal */ { int yes = 1; if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){ TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed."); } } #endif /* TNET_UNDER_IPHONE */ /* Sets the socket to nonblocking mode */ if(nonblocking){ if((status = tnet_sockfd_set_nonblocking(sock->fd))){ goto bail; } } bail: /* Free addrinfo */ tnet_freeaddrinfo(result); /* Close socket if failed. */ if (status){ if (TNET_SOCKET_IS_VALID(sock)){ tnet_socket_close(sock); } return tsk_null; } } return sock; }