Files
UltraGrid/gui/QT/util/random_port.cpp
Martin Piatka 415be28119 GUI: Get random control socket port by binding to 0
This lowers the chance of getting an already used port. This is still
not perfect as the port could still be taken before ug starts, but
should be good enough until we invert the client-server relationship
between gui and ug for control-port.
2022-08-22 15:30:07 +02:00

81 lines
1.7 KiB
C++

#include <QtGlobal>
#include <cerrno>
#ifndef Q_OS_WIN
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define CLOSESOCKET close
#define WIN_WSA_CLEAN()
#define INVALID_SOCKET -1
typedef int fd_t;
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#define CLOSESOCKET closesocket
#define WIN_WSA_CLEAN WSACleanup
typedef SOCKET fd_t;
#endif
#include "random_port.hpp"
int getRandomFreePort(){
#ifdef Q_OS_WIN
WSAData wsadata;
WSAStartup(MAKEWORD(2,2), &wsadata);
#endif
bool ipv4fallback = false;
fd_t socket_fd = socket(AF_INET6, SOCK_STREAM, 0);
if(socket_fd == INVALID_SOCKET && errno == EAFNOSUPPORT){
ipv4fallback = true;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
}
if(socket_fd == INVALID_SOCKET){
WIN_WSA_CLEAN();
return -1;
}
struct sockaddr_storage ss{};
socklen_t s_len = 0;
if(!ipv4fallback){
auto *s_in6 = reinterpret_cast<struct sockaddr_in6 *>(&ss);
s_in6->sin6_family = AF_INET6;
s_in6->sin6_addr = in6addr_any;
s_in6->sin6_port = 0;
s_len = sizeof(*s_in6);
} else {
auto *s_in = reinterpret_cast<struct sockaddr_in *>(&ss);
s_in->sin_family = AF_INET;
s_in->sin_addr.s_addr = htonl(INADDR_ANY);
s_in->sin_port = 0;
s_len = sizeof(*s_in);
}
int rc = ::bind(socket_fd, reinterpret_cast<const struct sockaddr *>(&ss), s_len);
if(rc != 0){
CLOSESOCKET(socket_fd);
WIN_WSA_CLEAN();
return -1;
}
rc = getsockname(socket_fd, reinterpret_cast<struct sockaddr *>(&ss), &s_len);
CLOSESOCKET(socket_fd);
WIN_WSA_CLEAN();
if(rc != 0)
return -1;
if(ipv4fallback){
auto *s_in = reinterpret_cast<struct sockaddr_in *>(&ss);
return ntohs(s_in->sin_port);
}
auto *s_in6 = reinterpret_cast<struct sockaddr_in6 *>(&ss);
return ntohs(s_in6->sin6_port);
}