/* Clear datagram connection */ void v_conn_dgram_clear(struct VDgramConn *dgram_conn) { /* Debug print */ if(is_log_level(VRS_PRINT_DEBUG_MSG)) { v_print_log(VRS_PRINT_DEBUG_MSG, "Free connection "); v_print_log_simple(VRS_PRINT_DEBUG_MSG, "%d ", dgram_conn->host_id); v_print_addr_port(VRS_PRINT_DEBUG_MSG, &dgram_conn->peer_address); v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\n"); } #ifdef WITH_OPENSSL if(dgram_conn->io_ctx.bio != NULL) { BIO_vfree(dgram_conn->io_ctx.bio); dgram_conn->io_ctx.bio = NULL; } #endif close(dgram_conn->io_ctx.sockfd); v_conn_dgram_init(dgram_conn); }
/* Create new UDP connection to the server */ struct VDgramConn *vc_create_client_dgram_conn(struct vContext *C) { struct VSession *vsession = CTX_current_session(C); struct VDgramConn *dgram_conn = NULL; struct addrinfo hints, *result, *rp; int sockfd = -1; int flag, ret; struct VURL url; /* Seed random number generator, */ #ifdef __APPLE__ sranddev(); /* Other BSD based systems probably support this or similar function too. */ #else /* Other systems have to use this evil trick */ struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_sec - tv.tv_usec); #endif if (v_url_parse(vsession->host_url, &url) != 1) { goto end; } else { /* v_print_url(VRS_PRINT_DEBUG_MSG, &url); */ } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Allow datagram protocol */ hints.ai_flags = 0; /* No flags required */ hints.ai_protocol = IPPROTO_UDP; /* Allow UDP protocol only */ if(is_log_level(VRS_PRINT_DEBUG_MSG)) { if(url.ip_ver==IPV6) { v_print_log(VRS_PRINT_DEBUG_MSG, "Try to connect to: [%s]:%s\n", url.node, url.service); } else { v_print_log(VRS_PRINT_DEBUG_MSG, "Try to connect to: %s:%s\n", url.node, url.service); } } if( (ret = getaddrinfo(url.node, url.service, &hints, &result)) !=0 ) { v_print_log(VRS_PRINT_ERROR, "getaddrinfo(): %s\n", gai_strerror(ret)); goto end; } /* Try to use addrinfo from getaddrinfo() */ for(rp=result; rp!=NULL; rp=rp->ai_next) { if( (sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) { v_print_log(VRS_PRINT_ERROR, "socket(): %s\n", strerror(errno)); continue; } else { /* Try to "connect" to this address ... the client will be able to send and * receive packets only from this address. */ if(connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) break; close(sockfd); sockfd = -1; } } if(rp == NULL) { if(is_log_level(VRS_PRINT_ERROR)) { if(url.ip_ver==IPV6) { v_print_log(VRS_PRINT_ERROR, "Could not connect to the [%s]:%s\n", url.node, url.service); } else { v_print_log(VRS_PRINT_ERROR, "Could not connect to the %s:%s\n", url.node, url.service); } } freeaddrinfo(result); goto end; } if( (dgram_conn = (struct VDgramConn*)calloc(1, sizeof(struct VDgramConn))) == NULL) { v_print_log(VRS_PRINT_ERROR, "calloc(): %s\n", strerror(errno)); freeaddrinfo(result); if(sockfd != -1) { close(sockfd); } goto end; } /* Initialize datagram connection */ v_conn_dgram_init(dgram_conn); /* Use first successfully assigned socket */ dgram_conn->io_ctx.sockfd = sockfd; /* Set socket non-blocking */ flag = fcntl(dgram_conn->io_ctx.sockfd, F_GETFL, 0); if( (fcntl(dgram_conn->io_ctx.sockfd, F_SETFL, flag | O_NONBLOCK)) == -1) { v_print_log(VRS_PRINT_ERROR, "fcntl(): %s\n", strerror(errno)); free(dgram_conn); dgram_conn = NULL; if(sockfd != -1) { close(sockfd); } freeaddrinfo(result); goto end; } /* Set socket to reuse address */ flag = 1; if( setsockopt(dgram_conn->io_ctx.sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) { v_print_log(VRS_PRINT_ERROR, "setsockopt(): %s\n", strerror(errno)); free(dgram_conn); if(sockfd != -1) { close(sockfd); } dgram_conn = NULL; goto end; } /* Set address of peer and host */ if(rp->ai_family==AF_INET) { /* Address type of client */ dgram_conn->io_ctx.host_addr.ip_ver = IPV4; dgram_conn->io_ctx.host_addr.protocol = UDP; /* Address of peer */ dgram_conn->io_ctx.peer_addr.ip_ver = IPV4; dgram_conn->io_ctx.peer_addr.protocol = UDP; dgram_conn->io_ctx.peer_addr.port = ntohs(((struct sockaddr_in*)rp->ai_addr)->sin_port); memcpy(&dgram_conn->io_ctx.peer_addr.addr.ipv4, rp->ai_addr, rp->ai_addrlen); /* Address of peer (reference in connection) */ dgram_conn->peer_address.ip_ver = IPV4; dgram_conn->peer_address.protocol = UDP; dgram_conn->peer_address.port = ntohs(((struct sockaddr_in*)rp->ai_addr)->sin_port); memcpy(&dgram_conn->peer_address.addr.ipv4, rp->ai_addr, rp->ai_addrlen); } else if(rp->ai_family==AF_INET6) { /* Address type of client */ dgram_conn->io_ctx.host_addr.ip_ver = IPV6; dgram_conn->io_ctx.host_addr.protocol = UDP; /* Address of peer */ dgram_conn->io_ctx.peer_addr.ip_ver = IPV6; dgram_conn->io_ctx.peer_addr.protocol = UDP; dgram_conn->io_ctx.peer_addr.port = ntohs(((struct sockaddr_in6*)rp->ai_addr)->sin6_port); memcpy(&dgram_conn->io_ctx.peer_addr.addr.ipv6, rp->ai_addr, rp->ai_addrlen); /* Address of peer (reference in connection) */ dgram_conn->peer_address.ip_ver = IPV6; dgram_conn->peer_address.protocol = UDP; dgram_conn->peer_address.port = ntohs(((struct sockaddr_in6*)rp->ai_addr)->sin6_port); memcpy(&dgram_conn->peer_address.addr.ipv6, rp->ai_addr, rp->ai_addrlen); } freeaddrinfo(result); /* When DTLS was negotiated, then set flag */ if(url.security_protocol == VRS_SEC_DATA_TLS) { #if (defined WITH_OPENSSL) && OPENSSL_VERSION_NUMBER>=0x10000000 dgram_conn->io_ctx.flags |= SOCKET_SECURED; #else v_print_log(VRS_PRINT_ERROR, "Server tries to force client to use secured connection, but it is not supported\n"); goto end; #endif } #ifdef WITH_OPENSSL /* Create BIO, connect and set to already connected */ if( (dgram_conn->io_ctx.bio = BIO_new_dgram(dgram_conn->io_ctx.sockfd, BIO_CLOSE)) == NULL) { v_print_log(VRS_PRINT_ERROR, "BIO_new_dgram()\n"); goto end; } /* Try to do PMTU discovery */ if( BIO_ctrl(dgram_conn->io_ctx.bio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL) < 0) { v_print_log(VRS_PRINT_ERROR, "BIO_ctrl()\n"); goto end; } /* Try to get MTU from the bio */ ret = BIO_ctrl(dgram_conn->io_ctx.bio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); if(ret > 0) { dgram_conn->io_ctx.mtu = ret; v_print_log(VRS_PRINT_DEBUG_MSG, "PMTU: %d\n", dgram_conn->io_ctx.mtu); } else { dgram_conn->io_ctx.mtu = DEFAULT_MTU; v_print_log(VRS_PRINT_DEBUG_MSG, "Default MTU: %d\n", dgram_conn->io_ctx.mtu); } #else dgram_conn->io_ctx.mtu = DEFAULT_MTU; #endif /* Set up necessary flag for V_CTX (client will be able to send and receive packets only to/from server) */ dgram_conn->io_ctx.flags |= SOCKET_CONNECTED; dgram_conn->host_id = (unsigned int)rand(); end: v_url_clear(&url); return dgram_conn; }