From 9114ea6691f8442b9ccddeb17274a3d735dcdd63 Mon Sep 17 00:00:00 2001 From: Sheldon Lee Date: Tue, 5 Nov 2024 00:57:12 +0800 Subject: [PATCH] Implement basic UDP broadcast/discovery --- main.c | 24 ++++++++- net.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net.h | 16 ++++++ 3 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 net.c create mode 100644 net.h diff --git a/main.c b/main.c index 81c30a2..9ddb52f 100644 --- a/main.c +++ b/main.c @@ -4,16 +4,20 @@ #include "texture.h" #include "audio.h" +#include "net.h" #include "log.h" #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 +#define PORT 55555 + typedef enum { SELECTING_DEVICE, RECORDING, RECORDED, PLAYBACK, + SOCKET, } application_state; typedef struct { @@ -45,7 +49,7 @@ int main(int argc, char* argv[]) char default_fmt[] = "Device selected: %i"; state state; - state.application_state = SELECTING_DEVICE; + state.application_state = SOCKET; if (!audio_init(&state.audio)) return 1; state.device_index = -1; state.update_ui = 0; @@ -203,6 +207,17 @@ int handle_input(SDL_Event* event, state* state) } break; + case SOCKET: + switch (keysym) { + case SDLK_1: + log_message(LOG_INFO, "Socket button 1 pressed"); + net_broadcast(); + break; + case SDLK_2: + log_message(LOG_INFO, "Socket button 2 pressed"); + net_listen_clients(); + break; + } } return 1; } @@ -231,6 +246,8 @@ void handle_task(state* state) } break; + case SOCKET: + break; } } @@ -261,6 +278,8 @@ int init() return 0; } + net_init(PORT); + return 1; } @@ -311,5 +330,8 @@ void application_state_to_string(application_state state, char* string) case PLAYBACK: sprintf(string, "Playing [ESC]: CANCEL"); break; + case SOCKET: + sprintf(string, "Socket"); + break; } } diff --git a/net.c b/net.c new file mode 100644 index 0000000..216350e --- /dev/null +++ b/net.c @@ -0,0 +1,153 @@ +#include "net.h" +#include "log.h" +#include + +typedef struct { + struct sockaddr_in addr; + int socket; + socklen_t addr_len; +} net_info; + +static net_info broadcast_info; +static net_info listen_info; +static net_info peer_info; +static int PORT; + +static int init = 0; + +int net_init(unsigned int port) +{ + PORT = port; + // broadcast socket init + broadcast_info.socket = socket(AF_INET, SOCK_DGRAM, 0); + if (broadcast_info.socket < 0) { + log_message(LOG_ERROR, "Error creating broadcast socket"); + close(broadcast_info.socket); + return 0; + } + + int broadcast_enable = 1; + if (setsockopt(broadcast_info.socket, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) return 0; + + memset(&broadcast_info.addr, 0, sizeof(broadcast_info.addr)); + broadcast_info.addr.sin_family = AF_INET; + broadcast_info.addr.sin_addr.s_addr = inet_addr("255.255.255.255"); + broadcast_info.addr.sin_port = htons(port); + + broadcast_info.addr_len = sizeof(broadcast_info.addr); + + // listen socket init + listen_info.socket = socket(AF_INET, SOCK_DGRAM, 0); + if (listen_info.socket < 0) { + log_message(LOG_ERROR, "Error creating listen socket", strerror(errno)); + close(listen_info.socket); + return 0; + } + + int reuse_enable = 1; + if (setsockopt(listen_info.socket, SOL_SOCKET, SO_REUSEADDR, &reuse_enable, sizeof(reuse_enable)) < 0) return 0; + + memset(&listen_info.addr, 0, sizeof(listen_info.addr)); + listen_info.addr.sin_family = AF_INET; + listen_info.addr.sin_addr.s_addr = INADDR_BROADCAST; + listen_info.addr.sin_port = htons(port); + + listen_info.addr_len =sizeof(listen_info.addr); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; + setsockopt(listen_info.socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + if (bind(listen_info.socket, (const struct sockaddr*)&listen_info.addr, sizeof(listen_info.addr)) < 0) { + log_message(LOG_ERROR, "Socket bind failed: %s", strerror(errno)); + close(listen_info.socket); + return 0; + } + + peer_info.socket = -1; + + init = 1; + return 1; +} + +int net_broadcast() +{ + if (!init) return 0;; + const char* message = "broadcast message"; + int retv = sendto(broadcast_info.socket, message, + strlen(message), 0, + (struct sockaddr*)&broadcast_info.addr, + broadcast_info.addr_len); + if (retv < 0) { + log_message(LOG_ERROR, "Failed to send broadcast message: %s", strerror(errno)); + log_message(LOG_ERROR, "retv: %i", retv); + return 0; + } + log_message(LOG_INFO, "Broadcast message sent"); + return 1; +} + +int net_listen_clients() +{ + if (!init) return 0; + + if (peer_info.socket >= 0) { + log_message(LOG_WARNING, "Peer socket already created"); + log_message(LOG_INFO, + "Peer socket address:\n%s:%d", + inet_ntoa(peer_info.addr.sin_addr), + ntohs(peer_info.addr.sin_port)); + close(peer_info.socket); + peer_info.socket = -1; + //return 1; + } + + peer_info.socket = socket(AF_INET, SOCK_DGRAM, 0); + if (peer_info.socket < 0) { + log_message(LOG_ERROR, "Error creating listen socket", strerror(errno)); + close(peer_info.socket); + return 0; + } + + char buffer[64]; + + memset(&peer_info.addr, 0, sizeof(peer_info.addr)); + peer_info.addr.sin_family = AF_INET; + peer_info.addr.sin_addr.s_addr = INADDR_ANY; + peer_info.addr.sin_port = htons(PORT); + + peer_info.addr_len = sizeof(peer_info.addr); + + int retv = recvfrom(listen_info.socket, buffer, sizeof(buffer), 0, + (struct sockaddr*)&peer_info.addr, + &peer_info.addr_len); + + if (retv < 0) { + log_message(LOG_ERROR, "Failed to receive broadcast message: %s", strerror(errno)); + close(peer_info.socket); + peer_info.socket = -1; + return 0; + } + + buffer[retv] = '\0'; + log_message(LOG_INFO, + "Broadcast message received from:\n%s:%d", + inet_ntoa(peer_info.addr.sin_addr), + ntohs(peer_info.addr.sin_port)); + log_message(LOG_INFO, "%s", buffer); + + return 1; +} + +int net_send() +{ + if (!init) return 0; + return 1; +} + +int net_receive() +{ + if (!init) return 0; + return 1; +} diff --git a/net.h b/net.h new file mode 100644 index 0000000..19cdcda --- /dev/null +++ b/net.h @@ -0,0 +1,16 @@ +#ifndef NET_H +#define NET_H + +#include +#include +#include +#include +#include + +int net_init(unsigned int port); +int net_broadcast(); +int net_listen_clients(); +int net_send(); +int net_receive(); + +#endif