145 lines
4.3 KiB
C
145 lines
4.3 KiB
C
// udp.c
|
|
|
|
/* TODO:
|
|
* convert error codes to strings and print them, we could just make a table
|
|
* option to change port, handle when we cant get gur port
|
|
* be able to send packets when sounds / recording starts / ends ?
|
|
|
|
* store from ip + port in message ?
|
|
*/
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include "ampler.h"
|
|
|
|
// sadly, these mess with gur FD_SET macro ; - ;
|
|
#undef do
|
|
#undef if
|
|
#undef for
|
|
#undef while
|
|
|
|
// G l o b a L E v i L //
|
|
static SOCKET udp_sock;
|
|
|
|
void udp_init(Ampler_state *state) {
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup
|
|
WSADATA wsa;
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsa)) // we want version 2.2
|
|
printf("error: WSAStartup() != 0, WSAGetLastError() = %i\n", WSAGetLastError());
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
|
|
// SOCKET s = socket(
|
|
udp_sock = socket(
|
|
AF_INET, // ipv4
|
|
SOCK_DGRAM, // udp
|
|
0 // protocol, 0 = unspecified
|
|
);
|
|
if (udp_sock == INVALID_SOCKET)
|
|
printf("error: socket is invalid, WSAGetLastError() = %i\n" , WSAGetLastError());
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
|
|
struct sockaddr_in server; // sockaddr_in = ipv4
|
|
const int PORT = 8888;
|
|
server.sin_family = AF_INET; // ipv4
|
|
server.sin_addr.s_addr = INADDR_ANY;
|
|
server.sin_port = htons(PORT); // convert host to network byte order for short
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind
|
|
int bind_result = bind(
|
|
udp_sock, // unbound socket, to be bound
|
|
&server, // local address of socket
|
|
sizeof(server) // sizeof address struct
|
|
);
|
|
if (bind_result == SOCKET_ERROR)
|
|
printf("error: bind returned SOCKET_ERROR, WSAGetLastError() = %i\n" , WSAGetLastError());
|
|
}
|
|
|
|
void udp_quit(Ampler_state *state) {
|
|
closesocket(udp_sock);
|
|
WSACleanup();
|
|
}
|
|
|
|
void recv_packet(Ampler_state *state) {
|
|
char discard_buf[32] = { 0 }; // for dropped packets
|
|
char *buf = discard_buf;
|
|
int buf_len = sizeof discard_buf;
|
|
|
|
for (int i = 0; i < arraylen(state -> messages); i += 1) {
|
|
Udp_msg *msg = &(state -> messages[i]);
|
|
if (msg -> state == MSG_FREE) {
|
|
msg -> state = MSG_TRIGGER;
|
|
buf = msg -> text;
|
|
buf_len = sizeof msg -> text;
|
|
SDL_memset(buf, 0, buf_len);
|
|
break;
|
|
}
|
|
}
|
|
if (buf == discard_buf)
|
|
puts("dropped udp packet.");
|
|
|
|
struct sockaddr_in from_addr;
|
|
int from_addr_size = sizeof from_addr;
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
|
|
int recv_len = recvfrom(
|
|
udp_sock, // socket to recive on
|
|
buf, // buffer for recv'd data
|
|
buf_len - 1, // size of buffer in bytes, '- 1' preserves null terminator
|
|
0, // flags
|
|
&from_addr, // address struct to recieve source of packet
|
|
&from_addr_size // POINTER to size of address struct
|
|
);
|
|
if (recv_len == SOCKET_ERROR)
|
|
if (WSAGetLastError() != WSAEMSGSIZE) // packet was truncated to fit buffer
|
|
printf("error: recvfrom returned SOCKET_ERROR, WSAGetLastError() = %i\n" , WSAGetLastError());
|
|
|
|
// convert to ipv4 address string, stored in static buffer, next call overwrites
|
|
const char *from_ip_str = inet_ntoa(from_addr.sin_addr);
|
|
int from_port = ntohs(from_addr.sin_port); // convert network to host byte order for short
|
|
if (0) // FOR DEBUGGING
|
|
printf("%s:%d\t%s\n", from_ip_str, from_port, buf);
|
|
}
|
|
|
|
void udp_frame(Ampler_state *state) {
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select
|
|
fd_set recv_fd_set;
|
|
FD_ZERO(&recv_fd_set); // init / clear set
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-timeval
|
|
TIMEVAL timeout;
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 1000; // 1 ms
|
|
|
|
while (1) {
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select
|
|
FD_SET(udp_sock, &recv_fd_set); // add server socket to set
|
|
int can_recv = select( // returns gur number of sockets, we can recv on, 0 on timeout
|
|
0, // ignored on win, used for compatability
|
|
&recv_fd_set, // soc set to be checked for reading
|
|
NULL, // set to be checked for writing
|
|
NULL, // set to be checked for errors
|
|
&timeout // max time to wait for
|
|
);
|
|
if (can_recv == SOCKET_ERROR)
|
|
printf("error: select returned SOCKET_ERROR, WSAGetLastError() = %i\n", WSAGetLastError());
|
|
|
|
if (FD_ISSET(udp_sock, &recv_fd_set)) {
|
|
// puts("soc in set, we can recv data!");
|
|
}
|
|
else {
|
|
// puts("timeout");
|
|
return;
|
|
}
|
|
|
|
recv_packet(state);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|