Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added IPv6 support for client #107

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from
Draft

Conversation

Gibus21250
Copy link

Hello, I worked on the client side to fully support IPv6 (and still IPv4 of course)
And I changed some mechanisms that don't break everything:

The DNS resolver can now return IPv4 or IPv6, and prefer IPv6 (as OS like Windows do)

I think I have tested everything:

  • joining a server by hostname who is listening on IPv6 (direct join)
  • joining a server by IPv6 (direct join)
  • Tested with vanilla and modded server, the download socket has been adapted

I have also added vcpkg, as beamng-server has, it is simpler for me to "clone and go" this project.

The server side has needed some modification, which I let you check it on the server repo! (ill add the PR link after)

I hope everything is good to go!

@Gibus21250
Copy link
Author

Re, the PR in link for IPv6 support, on the server side:
BeamMP/BeamMP-Server#359
Thanks!

Copy link
Member

@lionkor lionkor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally great job, please see if you can address the comments I made.

Could you also explain to my what the rationale is behind adding so many comments and doing so many unrelated changes? I'm just curious.

Terminate = true;
return;

const std::regex ipv4v6Pattern(R"(((^\h*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\h*(|/([0-9]|[1-2][0-9]|3[0-2]))$)|(^\h*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\h*(|/([0-9]|[0-9][0-9]|1[0-1][0-9]|12[0-8]))$)))");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not just let the connect() / bind() syscalls handle the validation check of ipv6's? :)

@@ -87,6 +98,7 @@ void Parse(std::string Data, SOCKET CSocket) {
Data = Code + HTTP::Get("https://backend.beammp.com/servers-info");
break;
case 'C':
//TODO StartSync Here
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please either do or remove the todo, or create an issue

Comment on lines 308 to 326
info("Game Connected!");
info("Game Connected to LUA interface!");
GameHandler(CSocket);
warn("Game Reconnecting...");
warn("Game reconnecting to LUA interface...");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was fine, why the change?

LSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (LSocket == -1) {
debug("(Core) socket failed with error: " + std::to_string(WSAGetLastError()));
freeaddrinfo(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we don't need freeaddrinfo anymore?

Comment on lines 57 to 72
//Loop all and return it by prefeence ipv6
for (struct addrinfo* ptr = addresses; ptr != nullptr; ptr = ptr->ai_next) {
char ipstr[INET6_ADDRSTRLEN] = { 0 };

if (ptr->ai_family == AF_INET6) {
struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)ptr->ai_addr;
inet_ntop(AF_INET6, &(ipv6->sin6_addr), ipstr, sizeof(ipstr));
resolved = ipstr;
break; //Break if IPv6 finded
}
else if (ptr->ai_family == AF_INET) {
struct sockaddr_in* ipv4 = (struct sockaddr_in*)ptr->ai_addr;
inet_ntop(AF_INET, &(ipv4->sin_addr), ipstr, sizeof(ipstr));
resolved = ipstr;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually you just loop over resolved addresses, attempt to connect, and take the first one that connects. Is there a good reason why we don't just do that here?

Comment on lines 90 to 108
if (AF == AF_INET) {
// IPv4
struct sockaddr_in serverAddrV4;
memset(&serverAddrV4, 0, sizeof(sockaddr_in));
serverAddrV4.sin_family = AF_INET;
serverAddrV4.sin_port = htons(Port);
inet_pton(AF_INET, IP.c_str(), &serverAddrV4.sin_addr);
memcpy(ToServer, &serverAddrV4, sizeof(sockaddr_in));
addrLen = sizeof(sockaddr_in);
} else {
// IPv6
struct sockaddr_in6 serverAddrV6;
memset(&serverAddrV6, 0, sizeof(sockaddr_in6));
serverAddrV6.sin6_family = AF_INET6;
serverAddrV6.sin6_port = htons(Port);
inet_pton(AF_INET6, IP.c_str(), &serverAddrV6.sin6_addr);
memcpy(ToServer, &serverAddrV6, sizeof(sockaddr_in6));
addrLen = sizeof(sockaddr_in6);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is almost duplicated down in VehicleEvent, could we pull this out into a function maybe?

Based on Windows's documentation, the entire app need at least one WSAStarup call, other gonna juste increment a counter, for wich the app need the same number of WSACleanup.
https://learn.microsoft.com/fr-fr/windows/win32/api/winsock/nf-winsock-wsastartup
To simplify, and to increase a lot the visibility, the app will call one WSAStartup, and one WSACleanup at all. This is done on CoreNetwork function.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants