Use the posix socket API wrapper of the zig standard library instead of messing with C code.

This commit is contained in:
IntegratedQuantum 2023-01-05 17:18:11 +01:00
parent d9b81b91f8
commit 43da550385
4 changed files with 52 additions and 149 deletions

View File

@ -39,7 +39,7 @@ pub fn build(b: *std.build.Builder) !void {
std.log.err("Unsupported target: {}\n", .{ target.getOsTag() }); std.log.err("Unsupported target: {}\n", .{ target.getOsTag() });
} }
} }
exe.addCSourceFiles(&[_][]const u8{"lib/glad.c", "lib/stb_image.c", "lib/cross_platform_udp_socket.c"}, &[_][]const u8{"-g"}); exe.addCSourceFiles(&[_][]const u8{"lib/glad.c", "lib/stb_image.c"}, &[_][]const u8{"-g"});
exe.addPackage(freetype.pkg); exe.addPackage(freetype.pkg);
exe.addPackage(freetype.harfbuzz_pkg); exe.addPackage(freetype.harfbuzz_pkg);
freetype.link(b, exe, .{ .harfbuzz = .{} }); freetype.link(b, exe, .{ .harfbuzz = .{} });

View File

@ -1,11 +0,0 @@
#include <stdint.h>
void startup();
int init(unsigned short localPort);
int deinit(int socketID);
int sendTo(int socketID, const char* data, uintptr_t size, uint32_t ip, uint16_t port);
intptr_t receiveFrom(int socketID, char* buffer, uintptr_t size, int timeout, uint32_t* resultIP, uint16_t* resultPort);
uint32_t resolveIP(const char* ip);
int getError();

View File

@ -1,110 +0,0 @@
#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <stdio.h>
#include <cross_platform_udp_socket.h>
int checkError(int in) {
// TODO: Print the error here.
return in;
}
void startup() {
#ifdef _WIN32
WSADATA d;
if (WSAStartup(MAKEWORD(2, 2), &d)) {
fprintf(stderr, "Failed to initialize.\n");
}
#endif
}
int init(unsigned short localPort) {
int socketID = checkError(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
if(socketID == -1) return -1;
struct sockaddr_in bindingAddr;
bindingAddr.sin_family = AF_INET;
bindingAddr.sin_port = htons(localPort);
bindingAddr.sin_addr.s_addr = INADDR_ANY;
memset(&bindingAddr.sin_zero, 0, 8);
if(checkError(bind(socketID, (const struct sockaddr*)&bindingAddr, sizeof(bindingAddr))) == -1) {
#ifdef _WIN32
closesocket(socketID);
#else
close(socketID);
#endif
return -1;
};
return socketID;
}
int deinit(int socketID) {
#ifdef _WIN32
return checkError(closesocket(socketID));
#else
return checkError(close(socketID));
#endif
}
int sendTo(int socketID, const char* data, uintptr_t size, uint32_t ip, uint16_t port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = ip;
memset(&addr.sin_zero, 0, 8);
return checkError(sendto(socketID, data, size, 0, (const struct sockaddr*)&addr, sizeof(addr)));
}
intptr_t receiveFrom(int socketID, char* buffer, uintptr_t size, int timeout, uint32_t* resultIP, uint16_t* resultPort) {
struct pollfd pfd = {.fd = socketID, .events = POLLIN};
#ifdef _WIN32
intptr_t result = checkError(WSAPoll(&pfd, 1, timeout));
#else
intptr_t result = checkError(poll(&pfd, 1, timeout));
#endif
if(result <= 0) return result;
struct sockaddr_in address;
uint32_t addrLen = sizeof(address);
result = checkError(recvfrom(socketID, buffer, size, 0, (struct sockaddr *)&address, &addrLen));
*resultIP = address.sin_addr.s_addr;
*resultPort = ntohs(address.sin_port);
return result;
}
uint32_t resolveIP(const char* address) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
struct addrinfo* res;
int result = getaddrinfo(address, NULL, &hints, &res);
if(result != 0) {
errno = result;
return 0xffffffff;
}
uint32_t ip = ((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr;
freeaddrinfo(res);
return ip;
}
int getError() {
return errno;
}

View File

@ -1,3 +1,4 @@
const builtin = @import("builtin");
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -22,46 +23,65 @@ const Vec3f = vec.Vec3f;
//TODO: Might want to use SSL or something similar to encode the message //TODO: Might want to use SSL or something similar to encode the message
const Socket = struct { const Socket = struct {
const c = @cImport({@cInclude("cross_platform_udp_socket.h");}); const os = std.os;
socketID: u31, socketID: os.socket_t,
fn checkError(comptime msg: []const u8, comptime T: type, result: T) !std.meta.Int(.unsigned, @bitSizeOf(T) - 1) { fn startup() void {
if(result == -1) { if(builtin.os.tag == .windows) {
std.log.warn(msg, .{c.getError()}); _ = os.windows.WSAStartup(2, 2) catch |err| { // TODO: Return the error (this triggers a false depency loop error right now).
return error.SocketError; std.log.err("Error trying to startup WSA: {}", .{@errorName(err)});
};
} }
return @intCast(std.meta.Int(.unsigned, @bitSizeOf(T) - 1), result);
} }
fn init(localPort: u16) !Socket { fn init(localPort: u16) !Socket {
return Socket{.socketID = try checkError("Socket creation failed with error: {}", c_int, c.init(localPort))}; var self = Socket {
.socketID = try os.socket(os.AF.INET, os.SOCK.DGRAM, os.IPPROTO.UDP),
};
errdefer self.deinit();
const bindingAddr = os.sockaddr.in {
.port = @byteSwap(localPort),
.addr = 0,
};
try os.bind(self.socketID, @ptrCast(*const os.sockaddr, &bindingAddr), @sizeOf(os.sockaddr.in));
return self;
} }
fn deinit(self: Socket) void { fn deinit(self: Socket) void {
_ = checkError("Error while closing socket: {}", c_int, c.deinit(self.socketID)) catch 0; os.closeSocket(self.socketID);
} }
fn send(self: Socket, data: []const u8, destination: Address) !void { fn send(self: Socket, data: []const u8, destination: Address) !void {
_ = try checkError("Error sending data: {}", isize, c.sendTo(self.socketID, data.ptr, data.len, destination.ip, destination.port)); const addr = os.sockaddr.in {
.port = @byteSwap(destination.port),
.addr = destination.ip,
};
std.debug.assert(data.len == try os.sendto(self.socketID, data, 0, @ptrCast(*const os.sockaddr, &addr), @sizeOf(os.sockaddr.in)));
} }
fn receive(self: Socket, buffer: []u8, timeout: c_int, resultAddress: *Address) ![]u8 { fn receive(self: Socket, buffer: []u8, timeout: i32, resultAddress: *Address) ![]u8 {
var length = try checkError("Receive failed: {}", isize, c.receiveFrom(self.socketID, buffer.ptr, buffer.len, timeout, &resultAddress.ip, &resultAddress.port)); var pfd = [1]os.pollfd {
.{.fd = self.socketID, .events = os.POLL.IN, .revents = undefined},
};
var length = try os.poll(&pfd, timeout);
if(length == 0) return error.Timeout; if(length == 0) return error.Timeout;
var addr: os.sockaddr.in = undefined;
var addrLen: os.socklen_t = @sizeOf(os.sockaddr.in);
length = try os.recvfrom(self.socketID, buffer, 0, @ptrCast(*os.sockaddr, &addr), &addrLen);
resultAddress.ip = addr.addr;
resultAddress.port = @byteSwap(addr.port);
return buffer[0..length]; return buffer[0..length];
} }
fn resolveIP(ip: [:0]const u8) u32 { fn resolveIP(addr: []const u8) !u32 {
const result: u32 = c.resolveIP(ip.ptr); const list = try std.net.getAddressList(main.threadAllocator, addr, settings.defaultPort);
if(result == 0xffffffff) { defer list.deinit();
std.log.warn("Could not resolve address: {s} error: {}", .{ip, c.getError()}); return list.addrs[0].in.sa.addr;
}
return result;
} }
}; };
pub fn init() void { pub fn init() void {
Socket.c.startup(); Socket.startup();
inline for(@typeInfo(@TypeOf(Protocols)).Struct.fields) |field| { inline for(@typeInfo(@TypeOf(Protocols)).Struct.fields) |field| {
if(field.type == type) { if(field.type == type) {
const id = @field(Protocols, field.name).id; const id = @field(Protocols, field.name).id;
@ -239,9 +259,14 @@ const STUN = struct {
random.fill(data[8..]); // Fill the transaction ID. random.fill(data[8..]); // Fill the transaction ID.
var splitter = std.mem.split(u8, server, ":"); var splitter = std.mem.split(u8, server, ":");
var nullTerminatedIP = main.threadAllocator.dupeZ(u8, splitter.first()) catch continue; const ip = splitter.first();
defer main.threadAllocator.free(nullTerminatedIP); var serverAddress = Address {
var serverAddress = Address{.ip=Socket.resolveIP(nullTerminatedIP), .port=std.fmt.parseUnsigned(u16, splitter.rest(), 10) catch 3478}; .ip=Socket.resolveIP(ip) catch |err| {
std.log.err("Cannot resolve stun server address: {s}, error: {s}", .{ip, @errorName(err)});
continue;
},
.port=std.fmt.parseUnsigned(u16, splitter.rest(), 10) catch 3478
};
if(connection.sendRequest(connection.allocator, &data, serverAddress, 500*1000000) catch |err| { if(connection.sendRequest(connection.allocator, &data, serverAddress, 500*1000000) catch |err| {
std.log.warn("Encountered error: {s} while connecting to STUN server: {s}", .{@errorName(err), server}); std.log.warn("Encountered error: {s} while connecting to STUN server: {s}", .{@errorName(err), server});
continue; continue;
@ -270,7 +295,7 @@ const STUN = struct {
std.log.warn("Couldn't reach STUN server: {s}", .{server}); std.log.warn("Couldn't reach STUN server: {s}", .{server});
} }
} }
return Address{.ip=Socket.resolveIP("127.0.0.1"), .port=settings.defaultPort}; // TODO: Return ip address in LAN. return Address{.ip=Socket.resolveIP("127.0.0.1") catch unreachable, .port=settings.defaultPort}; // TODO: Return ip address in LAN.
} }
fn findIPPort(_data: []const u8) !Address { fn findIPPort(_data: []const u8) !Address {
@ -330,7 +355,7 @@ pub const ConnectionManager = struct {
thread: std.Thread = undefined, thread: std.Thread = undefined,
threadId: std.Thread.Id = undefined, threadId: std.Thread.Id = undefined,
externalAddress: Address = undefined, externalAddress: Address = undefined,
online: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true), online: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false),
running: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true), running: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true),
connections: std.ArrayList(*Connection) = undefined, connections: std.ArrayList(*Connection) = undefined,
@ -1248,9 +1273,8 @@ pub const Connection = struct {
std.ArrayList(u32).init(result.allocator), std.ArrayList(u32).init(result.allocator),
}; };
var splitter = std.mem.split(u8, ipPort, ":"); var splitter = std.mem.split(u8, ipPort, ":");
var nullTerminatedIP = try main.threadAllocator.dupeZ(u8, splitter.first()); const ip = splitter.first();
defer main.threadAllocator.free(nullTerminatedIP); result.remoteAddress.ip = try Socket.resolveIP(ip);
result.remoteAddress.ip = Socket.resolveIP(nullTerminatedIP);
var port = splitter.rest(); var port = splitter.rest();
if(port.len != 0 and port[0] == '?') { if(port.len != 0 and port[0] == '?') {
result.remoteAddress.isSymmetricNAT = true; result.remoteAddress.isSymmetricNAT = true;