From 303019296e474ffde03dde15aecefacb3119f71f Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 28 Mar 2022 14:49:24 -0500 Subject: [PATCH] working connection --- doc.md | 6 + src/host.onyx | 439 +++++++++++++++++++++++++++++++++++++++++++++- src/module.onyx | 12 +- src/packet.onyx | 67 +++++++ src/peer.onyx | 189 +++++++++++++++++++- src/protocol.onyx | 74 ++++++++ udp_client.onyx | 35 +++- udp_server.onyx | 31 ++++ 8 files changed, 845 insertions(+), 8 deletions(-) diff --git a/doc.md b/doc.md index ee9fd13..b576046 100644 --- a/doc.md +++ b/doc.md @@ -20,3 +20,9 @@ transferred in a different way, or chunked up by the application layer. +Each packet is at most 1400 bytes in size. + +0 2 4 6 8 ... +| peerID | sentTime | checksum | channelID | commandID | data + OPTIONAL OPTIONAL + diff --git a/src/host.onyx b/src/host.onyx index dfce83b..85ec307 100644 --- a/src/host.onyx +++ b/src/host.onyx @@ -1,11 +1,448 @@ package onyx_net +@CLEANUP +use package core + Host :: struct { socket : net.Socket; addr : net.Socket_Address; peers : [] Peer; - maximum_peers: u32; + connected_peers: u32; + + mtu: u32; + current_time: u32; + + // Transient data used during processing of an message. + packet_data: [2] [Host_Default_MTU] u8; + event: Event; + produced_event: bool; + + received_data: [] u8; + received_addr: net.Socket_Address; + + pulse :: host_pulse; + get_events :: host_get_events; +} + +#local Host_Creation_Error :: enum { + None; + Socket_Creation_Failed; + Socket_Binding_Failed; +} + +host_create :: (addr: ^net.Socket_Address, peer_count: u32) -> (^Host, Host_Creation_Error) { + errored := false; + host := new(Host); + defer if errored do cfree(host); + + memory.alloc_slice(^host.peers, peer_count); + defer if errored do memory.free_slice(^host.peers); + host.connected_peers = 0; + + if socket, err := net.socket_create(.Inet, .Dgram); err != .None { + errored = true; + return null, .Socket_Creation_Failed; + + } else { + host.socket = socket; + } + defer if errored do net.socket_close(^host.socket); + + if addr != null { + if !host.socket->bind(addr.port) { + errored = true; + return null, .Socket_Binding_Failed; + } + } + + host.socket->setting(.NonBlocking, 1); + host.socket->setting(.Broadcast, 1); + + host.addr = *addr; + host.mtu = Host_Default_MTU; + + for^ peer: host.peers { + peer.host = host; + peer.state = .Disconnected; + peer.channels = .{ null, 0 }; + peer.incoming_id = ~~((cast(u32) peer - cast(u32) host.peers.data) / sizeof Peer); + peer.outgoing_id = ~~((cast(u32) peer - cast(u32) host.peers.data) / sizeof Peer); + peer.mtu = host.mtu; + } + + return host, .None; +} + +host_connect :: (host: ^Host, addr: ^net.Socket_Address, channel_count: u32) -> ^Peer { + peer: ^Peer; + + // Find first peer that is in the disconnected state. + for^ host.peers do if it.state == .Disconnected { + peer = it; + break; + } + + if peer == null do return null; + + memory.alloc_slice(^peer.channels, channel_count); + peer.host = host; + peer.state = .Connecting; + peer.addr = *addr; + peer.connect_id = random.int(); + peer.mtu = Host_Default_MTU; + + for^ channel: peer.channels { + channel.id = ~~((cast(u32) channel - cast(u32) peer.channels.data) / 4); + channel.seq_number = 0; + channel.max_reliable_windows = 16; + memory.alloc_slice(^channel.reliable_windows, channel.max_reliable_windows); + } + + command := new(Protocol_Connect); + command.command = .Connect; + command.command |= .Flag_Acknowledge; + command.channel = 255; + command.outgoing_peer_id = net.host_to_network(peer.outgoing_id); + command.mtu = net.host_to_network(peer.mtu); + command.window_size = 0; + command.channel_count = net.host_to_network(channel_count); + command.connect_id = net.host_to_network(peer.connect_id); + + peer_queue_outgoing_command(peer, command); + return peer; +} + +host_free :: (host: ^Host) { + net.socket_close(^host.socket); + memory.free_slice(^host.peers); + cfree(host); +} + +host_broadcast :: (host: ^Host, channel: Channel_ID, packet: ^Packet) { + for ^peer: host.peers { + if peer.state != .Connected do continue; + + peer_send(peer, channel, packet); + } +} + +host_pulse :: (host: ^Host, timeout: u32 = 0) -> bool { + host.current_time = ~~ os.time(); + + sent_command := host_send_commands(host); + received_command := host_receive_commands(host, timeout); + + return host.produced_event; +} + +host_send_commands :: (host: ^Host) -> bool { + for ^peer: host.peers { + // + // Skip over peers that are dead or disconnected. + if peer.state == .Disconnected || peer.state == .Zombie { + continue; + } + + // + // Have peers send their acknowledgements for messages they received. + // Currently, this will issue its own send() call. A better way is to + // pool the messages together using something like sendmsg(), but Onyx + // does not currently support that. + if peer.acknowledgements.count > 0 { + peer_send_acknowledgements(peer); + } + + // TODO + // Peer pinging + // Packet loss calcuations + // Dropped packet detection + + peer_flush_outgoing_commands(peer); + } +} + +host_receive_commands :: (host: ^Host, timeout: u32 = 0) -> bool { + if timeout > 0 { + check_sockets := (^net.Socket).[ ^host.socket ]; + changed_buffer := alloc.array_from_stack(i32, 1); + changed := net.socket_poll_all(check_sockets, timeout, changed_buffer); + + if changed.count == 0 do return false; + } + + buffer: [] u8 = host.packet_data[0]; + recv_addr, recv_bytes := host.socket ->recvfrom(buffer); + + host.received_addr = recv_addr; + host.received_data = buffer[0 .. recv_bytes]; + + return host_handle_incoming_commands(host); +} + +host_handle_incoming_commands :: (host: ^Host) -> bool { + header: ^Protocol_Header = ~~ host.received_data.data; + current_data := host.received_data; + + peer_id := cast(u32) net.network_to_host(header.peer_id); + peer: ^Peer; + + if peer_id == 0xffff --- // a Peer Id of 0xffff is used for a newly connecting peer. + elseif peer_id >= host.peers.count || peer_id >= host.peers.count { + return false; + + } else { + peer = ^host.peers[peer_id]; + } + + if peer != null { + peer.addr = host.received_addr; + } + + string.advance(^current_data, sizeof typeof *header); + + return_block :: macro () { + printf("DISCARDING: {}\n", peer_id); + return host.event.type != .None; + } + + while current_data.count > sizeof Protocol_Command_Header { + if host.produced_event do break; + + command := cast(^Protocol_Command_Header) current_data.data; + command_id := command_get_effective(command.command); + printf("Received command: {} {*p}\n", command_sizes[command_id], cast(Command) command_id, command); + string.advance(^current_data, command_sizes[command_id]); + + switch command_id { + case .Acknowledge { + if peer == null do return_block(); + host_handle_acknowledge_command(host, peer, ~~ command); + } + + case .Connect { + if peer != null do return_block(); + peer = host_handle_connect_command(host, ~~ command); + if peer == null do return_block(); + } + + case .Verify_Connect { + if peer == null do return_block(); + host_handle_verify_connect_command(host, peer, ~~ command); + } + + case .Disconnect { + } + + case .Ping { + } + + case .Send_Reliable { + if peer == null do return_block(); + host_handle_send_reliable_command(host, peer, ~~ command, ^current_data); + } + + case .Send_Unreliable { + } + + case .Send_Unsequenced { + } + } + + if peer != null && (command.command & .Flag_Acknowledge) != 0 { + sent_time := net.network_to_host(header.sent_time); + + switch peer.state { + case .Acknowledging_Disconnect { + if command_id == .Disconnect { + peer_queue_acknowledgement(peer, command, sent_time); + } + } + + case #default { + peer_queue_acknowledgement(peer, command, sent_time); + } + } + } + } + + host.event.peer = peer; + return host.produced_event; +} + +host_get_events :: (host: ^Host, timeout: u32 = 0) -> Iterator(^Event) { + Context :: struct { + host: ^Host; + timeout: u32 = 0; + } + + next :: (use ctx: ^Context) -> (^Event, bool) { + if host_pulse(host, timeout) { + host.produced_event = false; + return ^host.event, true; + } + + return null, false; + } + + ctx := new(Context); + ctx.host = host; + ctx.timeout = timeout; + return .{ ctx, next, null_proc }; +} + +#local host_notify_connect :: (host: ^Host, peer: ^Peer) { + host.event.type = .Connection; + host.event.peer = peer; + host.event.channel_id = 255; // Magic constant + host.event.data = .[]; + + host.produced_event = true; +} + +#local host_notify_disconnect :: (host: ^Host, peer: ^Peer) { + host.event.type = .Disconnection; + host.event.peer = peer; + host.event.channel_id = 255; // Magic constant + host.event.data = .[]; + + host.produced_event = true; +} + +#local host_notify_message :: (host: ^Host, peer: ^Peer, channel_id: u8, data: [] u8) { + host.event.type = .Message; + host.event.peer = peer; + host.event.channel_id = channel_id; + host.event.data = data; + + host.produced_event = true; +} + +#local host_handle_acknowledge_command :: (host: ^Host, peer: ^Peer, command: ^Protocol_Acknowledge) { + if peer.state == .Disconnected || peer.state == .Zombie do return; + + recv_sent_time := cast(u32) net.network_to_host(command.recv_sent_time); + recv_sent_time |= host.current_time & 0xFFFF0000; + if (recv_sent_time & 0x8000) > (host.current_time & 0x8000) { + recv_sent_time -= 0x10000; + } + + // + // If the acknowledgement is for a message in the future, ignore it. + if host.current_time < recv_sent_time { + return; + } + + recv_seq_number := net.network_to_host(command.recv_seq_number); + removed_command_id := peer_remove_sent_reliable_command(peer, recv_seq_number, command.channel); + printf("Received acknowledgement for {}.\n", removed_command_id); + + switch peer.state { + case .Acknowledging_Connection { + if removed_command_id == .Verify_Connect { + peer.state = .Connected; + host_notify_connect(host, peer); + } + } + + case .Disconnecting { + if removed_command_id == .Disconnect { + host_notify_disconnect(host, peer); + } + } + + case .Disconnect_Later { + if peer.outgoing_commands.count == 0 { + peer_disconnect(peer); + } + } + } +} + +#local host_handle_connect_command :: (host: ^Host, command: ^Protocol_Connect) -> ^Peer { + peer: ^Peer; + + for^ host.peers { + if it.state == .Disconnected { + peer = it; + break; + + } elseif it.state == .Connecting && it.addr.addr == host.received_addr.addr { + if it.addr.port == host.received_addr.port && it.connect_id == command.connect_id do return null; + } + } + + if peer == null do return null; + + channel_count := net.network_to_host(command.channel_count); + memory.alloc_slice(^peer.channels, channel_count); + memory.set(peer.channels.data, 0, channel_count * sizeof Channel); + + peer.state = .Acknowledging_Connection; + peer.connect_id = net.network_to_host(command.connect_id); + peer.addr = host.received_addr; + peer.outgoing_id = net.network_to_host(command.outgoing_peer_id); + peer.mtu = net.network_to_host(command.mtu); + + verify := new(Protocol_Verify_Connect); + verify.command = .Verify_Connect; + verify.command |= .Flag_Acknowledge; + verify.channel = 255; + verify.channel_count = net.host_to_network(peer.channels.count); + verify.outgoing_peer_id = net.host_to_network(peer.incoming_id); + verify.mtu = net.host_to_network(peer.mtu); + verify.window_size = command.window_size; + verify.connect_id = net.host_to_network(peer.connect_id); + + peer_queue_outgoing_command(peer, verify); + + return peer; } +#local host_handle_verify_connect_command :: (host: ^Host, peer: ^Peer, command: ^Protocol_Verify_Connect) { + if net.network_to_host(command.connect_id) != peer.connect_id do return; + channel_count := net.network_to_host(command.channel_count); + + // + // These magic constants refer to the fact that the connection + // packet will have sequence number 1, and channel id 255. + peer_remove_sent_reliable_command(peer, 1, 255); + + peer.channels.count = math.min(peer.channels.count, channel_count); + peer.outgoing_id = net.network_to_host(command.outgoing_peer_id); + + peer.mtu = math.min(peer.mtu, net.network_to_host(command.mtu)); + peer.window_size = math.min(peer.window_size, net.network_to_host(command.window_size)); + + peer.state = .Connected; + host_notify_connect(host, peer); + return; +} + +// +// This is slightly misnamed, as it is actually handling a received reliable message. +#local host_handle_send_reliable_command :: (host: ^Host, peer: ^Peer, command: ^Protocol_Send, data: ^[] u8) { + host_notify_message(host, peer, command.channel, *data); + string.advance(data, ~~ command.data_length); +} + + +@Relocate +Event :: struct { + Type :: enum { + None; + Connection; + Disconnection; + Message; + } + + type: Type; + peer: ^Peer; + channel_id: Channel_ID; + data: [] u8; +} + +#local { + Host_Default_MTU :: 1400 +} diff --git a/src/module.onyx b/src/module.onyx index c07d176..6db6c8a 100644 --- a/src/module.onyx +++ b/src/module.onyx @@ -1,10 +1,14 @@ package onyx_net #package { - array :: package core.array - net :: package core.net - list :: package core.list - alloc :: package core.alloc + array :: package core.array + net :: package core.net + list :: package core.list + alloc :: package core.alloc + memory :: package core.memory + string :: package core.string + random :: package core.random + os :: package core.os } #load_all "./." diff --git a/src/packet.onyx b/src/packet.onyx index e69de29..77175c7 100644 --- a/src/packet.onyx +++ b/src/packet.onyx @@ -0,0 +1,67 @@ +package onyx_net + +Outgoing_Command :: struct { + command: ^Protocol_Command_Header; + packet : ^Packet; + reliable_seq_number : u16; + unreliable_seq_number : u16; + sent_time : u16; + send_attempts : u16; + + pack_into_buffer :: outgoing_command_pack_into_buffer; +} + +Incoming_Command :: struct { + command: ^Protocol_Command_Header; + packet : ^Packet; + reliable_seq_number : u16; + unreliable_seq_number : u16; +} + +Packet :: struct { + Flags :: enum #flags { + Reliable; + Unsequenced; + } + + flags: Flags; + data: [] u8; +} + +Acknowledgement :: struct { + sent_time: u16; + command: ^Protocol_Command_Header; +} + + +outgoing_command_pack_into_buffer :: (out: ^Outgoing_Command, peer: ^Peer, buf: [] u8) -> ([] u8, bool) { + write_offset := 0; + write :: macro (data: [] u8) { + if write_offset + data.count > buf.count do return .[], false; + memory.copy(buf.data + write_offset, data.data, data.count); + write_offset += data.count; + } + + peer_id := net.host_to_network(peer.outgoing_id); + sent_time := net.host_to_network(cast(u16)(peer.host.current_time & 0xFFFF)); + + // + // Connect packets expect to have a peer id of FFFF. + // However, the outgoing_id needs to remain its original value. + if command_get_effective(out.command.command) == .Connect { + peer_id = 65535; + } + + @HACK @HACK + write((cast(^u8) ^peer_id)[0 .. 2]); + write((cast(^u8) ^sent_time)[0 .. 2]); + + command_size := command_sizes[~~ command_get_effective(out.command.command)]; + write((cast(^u8) out.command)[0 .. command_size]); + + if out.packet != null { + write(out.packet.data); + } + + return buf[0 .. write_offset], true; +} diff --git a/src/peer.onyx b/src/peer.onyx index 483e941..1bebba7 100644 --- a/src/peer.onyx +++ b/src/peer.onyx @@ -6,7 +6,7 @@ Peer_State :: enum { Acknowledging_Connection; Connection_Pending; Connection_Successed; - Connection; + Connected; Disconnect_Later; Disconnecting; Acknowledging_Disconnect; @@ -19,11 +19,196 @@ Peer :: struct { state: Peer_State; channels: [] Channel; + + incoming_id: u16; + outgoing_id: u16; + connect_id: u32; + mtu: u32; + window_size: u32; + last_send_time: u32; + + outgoing_reliable_seq_number: u16; + incoming_reliable_seq_number: u16; + outgoing_unsequenced_group: u32; + + outgoing_commands: [..] ^Outgoing_Command; + incoming_commands: [..] ^Incoming_Command; + acknowledgements: [..] Acknowledgement; + sent_reliable_commands: [..] ^Outgoing_Command; +} + +peer_destroy :: (peer: ^Peer) { + memory.free_slice(^peer.channels); + array.free(^peer.outgoing_commands); + array.free(^peer.incoming_commands); +} + +peer_disconnect :: (peer: ^Peer) { + if peer.state == .Disconnected do return; + + peer.state = .Disconnected; + + peer_destroy(peer); +} + +peer_queue_outgoing_command :: #match { + (peer: ^Peer, command: ^Protocol_Command_Header, packet: ^Packet = null) -> ^Outgoing_Command { + out := new(Outgoing_Command); + out.command = command; + out.packet = packet; + + peer_setup_outgoing_command(peer, out); + return out; + } +} + +peer_setup_outgoing_command :: (peer: ^Peer, command: ^Outgoing_Command) { + if command.command.channel == 255 { + peer.outgoing_reliable_seq_number += 1; + command.reliable_seq_number = peer.outgoing_reliable_seq_number; + command.unreliable_seq_number = 0; + + } else { + channel := ^peer.channels[command.command.channel]; + + // Oof... That's a long chain of command. + if (command.command.command & .Flag_Acknowledge) != 0 { + channel.outgoing_reliable_seq_number += 1; + command.reliable_seq_number = channel.outgoing_reliable_seq_number; + command.unreliable_seq_number = 0; + + } elseif (command.command.command & .Flag_Unsequenced) != 0 { + peer.outgoing_unsequenced_group += 1; + command.reliable_seq_number = 0; + command.unreliable_seq_number = 0; + + } else { + channel.outgoing_unreliable_seq_number += 1; + + command.reliable_seq_number = channel.outgoing_reliable_seq_number; + command.unreliable_seq_number = channel.outgoing_unreliable_seq_number; + } + } + + command.send_attempts = 0; + command.sent_time = 0; + command.command.seq_number = net.host_to_network(command.reliable_seq_number); + + peer.outgoing_commands << command; +} + +peer_send :: (peer: ^Peer, channel_id: Channel_ID, packet: ^Packet) -> bool { + if peer.state != .Connected || ~~channel_id > peer.channels.count do return false; + + channel := ^peer.channels[channel_id]; + + @TODO // Fragmented sending + if packet.data.count > peer.mtu - sizeof Protocol_Header - sizeof Protocol_Send do return false; + + command := new(Protocol_Send); + command.channel = channel_id; + command.data_length = net.host_to_network(cast(u16) packet.data.count); + + if packet.flags & .Reliable { + command.command = .Send_Reliable; + command.command |= .Flag_Acknowledge; + } elseif packet.flags & .Unsequenced { + command.command = .Send_Unsequenced; + command.command |= .Flag_Unsequenced; + } else { + command.command = .Send_Unreliable; + } + + return peer_queue_outgoing_command(peer, command, packet) != null; +} + +peer_queue_acknowledgement :: (peer: ^Peer, command: ^Protocol_Command_Header, sent_time: u16) { + peer.acknowledgements << .{ sent_time, command }; +} + +peer_flush_outgoing_commands :: (peer: ^Peer) -> i32 { + peer.last_send_time = peer.host.current_time; + + send_buffer: [65535] u8; + + total_sent := 0; + for peer.outgoing_commands { + to_send, success := it->pack_into_buffer(peer, send_buffer); + if !success do continue; + + sent_bytes := peer.host.socket->sendto(to_send, ^peer.addr); + if sent_bytes < 0 { + return -1; + } + + total_sent += sent_bytes; + peer.sent_reliable_commands << it; + } + + array.clear(^peer.outgoing_commands); + return total_sent; +} + +peer_send_acknowledgements :: (peer: ^Peer) { + send_buffer: [65535] u8; + + for ^ack: peer.acknowledgements { + command: Protocol_Acknowledge; + command.command = .Acknowledge; + command.channel = ack.command.channel; + command.seq_number = 0; + command.recv_seq_number = ack.command.seq_number; + command.recv_sent_time = ack.sent_time; + + out: Outgoing_Command; + out.command = ^command; + + to_send, success := out->pack_into_buffer(peer, send_buffer); + if !success do continue; + + sent_bytes := peer.host.socket->sendto(to_send, ^peer.addr); + if sent_bytes < 0 do return; + } + + array.clear(^peer.acknowledgements); } +peer_remove_sent_reliable_command :: (peer: ^Peer, seq_num: u16, channel: Channel_ID) -> Command { + command: ^Outgoing_Command; + index := 0; + for peer.sent_reliable_commands { + if it.reliable_seq_number == seq_num && it.command.channel == channel { + command = it; + break; + } + + index += 1; + } + + if command == null do return .None; + + defer { + cfree(command.command); + cfree(command); + array.fast_delete(^peer.sent_reliable_commands, index); + } + return command_get_effective(command.command.command); +} +Channel_ID :: u8; + Channel :: struct { + id: Channel_ID; seq_number: u16; - + + reliable_windows: [] u16; + max_reliable_windows: u32; + + outgoing_unreliable_seq_number: u16; + outgoing_reliable_seq_number: u16; + incoming_reliable_seq_number: u16; + } + + diff --git a/src/protocol.onyx b/src/protocol.onyx index e69de29..76fa352 100644 --- a/src/protocol.onyx +++ b/src/protocol.onyx @@ -0,0 +1,74 @@ +package onyx_net + +Command :: enum (u8) { + None :: 0; + Acknowledge :: 1; + Connect :: 2; + Verify_Connect :: 3; + Disconnect :: 4; + Ping :: 5; + Send_Reliable :: 6; + Send_Unreliable :: 7; + Send_Unsequenced :: 8; + + Flag_Acknowledge :: 1 << 6; + Flag_Unsequenced :: 1 << 7; +} + +command_get_effective :: (n: Command) -> Command { + return ~~(n & 63); +} + +Protocol_Header :: struct #pack { + peer_id: u16; + sent_time: u16; +} + +Protocol_Command_Header :: struct #pack { + command: Command; + channel: Channel_ID; + seq_number: u16; +} + +Protocol_Acknowledge :: struct #pack { + use header: Protocol_Command_Header; + recv_seq_number: u16; + recv_sent_time: u16; +} + +Protocol_Connect :: struct #pack { + use header: Protocol_Command_Header; + outgoing_peer_id : u16; + mtu : u32; + window_size : u32; + channel_count : u32; + connect_id : u32; +} + +Protocol_Verify_Connect :: struct #pack { + use header: Protocol_Command_Header; + outgoing_peer_id : u16; + mtu : u32; + window_size : u32; + channel_count : u32; + connect_id : u32; +} + +Protocol_Send :: struct #pack { + use header: Protocol_Command_Header; + data_length: u16; +} + +Protocol_Disconnect :: Protocol_Command_Header; + +command_sizes := u32.[ + /* None */ 0, + /* Acknowledge */ sizeof Protocol_Acknowledge, + /* Connect */ sizeof Protocol_Connect, + /* Verify_Connect */ sizeof Protocol_Verify_Connect, + /* Disconnect */ sizeof Protocol_Disconnect, + /* Ping */ 0, + /* Send_Reliable */ sizeof Protocol_Send, + /* Send_Unreliable */ sizeof Protocol_Send, + /* Send_Unsequenced */ sizeof Protocol_Send, +]; diff --git a/udp_client.onyx b/udp_client.onyx index dec1e2d..b7b244b 100644 --- a/udp_client.onyx +++ b/udp_client.onyx @@ -1,6 +1,8 @@ #load "core/std" +#load "src/module" use package core +onyx_net :: package onyx_net octets_to_addr :: (a, b, c, d: u8) -> u32 { return (cast(u32) a << 24) | @@ -10,6 +12,37 @@ octets_to_addr :: (a, b, c, d: u8) -> u32 { } main :: (args) => { + // + // 'null' signifies that this host should not bind a socket + // to a port. Only 1 peer is needed, as this is only connecting + // to one server. + host: ^onyx_net.Host; + if host', err := onyx_net.host_create(null, 1); err != .None { + println(err); + } + + addr: net.Socket_Address; + addr.addr = octets_to_addr(127, 0, 0, 1); + addr.port = 8080; + peer := onyx_net.host_connect(host, ^addr, 2); + + while true { + println("Waiting for events...."); + for host->get_events(timeout=1000) { + printf("{*}\n", it); + + if it.type == .Message { + packet := new(onyx_net.Packet); + packet.flags |= .Reliable; + packet.data = "HELLO"; + + onyx_net.peer_send(it.peer, 0, packet); + } + } + } +} + +old_main :: (args) => { udp_socket, err := net.socket_create(.Inet, .Dgram); assert(err == .None, "Failed to create socket"); defer udp_socket->close(); @@ -21,7 +54,7 @@ main :: (args) => { random.set_seed(12341); - for 1000 { + for 10 { to_send := random.string(50, alpha_numeric=true); sent_bytes := udp_socket->sendto(to_send, ^dest_addr); diff --git a/udp_server.onyx b/udp_server.onyx index 4e4af2b..304839e 100644 --- a/udp_server.onyx +++ b/udp_server.onyx @@ -1,14 +1,45 @@ #load "core/std" +#load "src/module" use package core +onyx_net :: package onyx_net + main :: (args) => { + addr: net.Socket_Address; + addr.port = 8080; + + server, err := onyx_net.host_create(^addr, 32); + if err != .None { + println(err); + return; + } + + while true { + println("Getting events..."); + for server->get_events(timeout = 2000) { + printf("{*}\n", it); + + if it.type == .Connection { + packet := new(onyx_net.Packet); + packet.flags |= .Reliable; + packet.data = "Welcome!!!"; + + onyx_net.peer_send(it.peer, 0, packet); + } + } + } +} + +old_main :: (args) => { udp_socket, err := net.socket_create(.Inet, .Dgram); assert(err == .None, "Failed to create socket"); assert(udp_socket->bind(8080), "Failed to bind socket"); + udp_socket->setting(.NonBlocking, 1); + while true { recv_buffer: [1024] u8; recv_addr, recv_bytes := udp_socket->recvfrom(recv_buffer); -- 2.25.1