snix/users/sterni/blipqn/flipdot.c
sterni 10dc365e34 feat(sterni/blipqn): print some extra information when using :debug
Change-Id: I92ebde397e679c7e3f8ddcf6fcecd6af5c84f629
Reviewed-on: https://cl.tvl.fyi/c/depot/+/13012
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
2025-01-17 15:50:33 +00:00

89 lines
2.7 KiB
C

#define _DEFAULT_SOURCE // see getnameinfo(3), for NI_MAX*
#define _POSIX_C_SOURCE 200112L // see getaddrinfo(3)
#include <assert.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#ifndef FLIPDOT_DEBUG
#define FLIPDOT_DEBUG 0
#endif
int resolve_addr(char *host, char *port, struct addrinfo **addrs) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
hints.ai_flags |= AI_NUMERICSERV;
return getaddrinfo(host, port, &hints, addrs);
}
struct flipdot {
int sockfd;
struct addrinfo *addrs;
};
// Assumes all pointers in struct flipdot are not NULL which should be the case
// for any struct returned by flipdot_open().
void flipdot_close(struct flipdot *flipdot) {
if (FLIPDOT_DEBUG) fprintf(stderr, "flipdot_close() called\n");
freeaddrinfo(flipdot->addrs);
close(flipdot->sockfd);
free(flipdot);
}
// Returns NULL if some error occurred. Note that errno isn't necessarily set.
struct flipdot *flipdot_open(char *host, in_port_t port_number) {
char port[NI_MAXSERV];
struct flipdot *flipdot = malloc(sizeof(struct flipdot));
if (flipdot == NULL) goto error;
memset(flipdot, 0, sizeof(struct flipdot));
flipdot->sockfd = -1;
flipdot->addrs = NULL;
if (snprintf(port, sizeof(port), "%d", port_number) < 0) goto error;
if (resolve_addr(host, port, &flipdot->addrs) != 0) goto error;
flipdot->sockfd = socket(flipdot->addrs->ai_family, SOCK_DGRAM, IPPROTO_UDP);
if (flipdot->sockfd < 0) goto error;
if (FLIPDOT_DEBUG) {
char resolved_ip[NI_MAXHOST], resolved_port[NI_MAXSERV];
if (getnameinfo(flipdot->addrs->ai_addr, flipdot->addrs->ai_addrlen,
resolved_ip, sizeof(resolved_ip), resolved_port,
sizeof(resolved_port),
NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM) == 0)
fprintf(stderr, "flipdot_open(): using %s, port %s\n", resolved_ip,
resolved_port);
}
return flipdot;
error:
if (flipdot != NULL) {
if (flipdot->sockfd >= 0) close(flipdot->sockfd);
if (flipdot->addrs != NULL) freeaddrinfo(flipdot->addrs);
free(flipdot);
}
return NULL;
}
// Send given bytes[len] to the given flipdot, returns 1 if all bytes were sent
// and no locally detectable errors occurred, 0 otherwise.
int8_t flipdot_send(struct flipdot *flipdot, uint8_t *bitmap,
size_t bitmap_len) {
ssize_t sent = sendto(flipdot->sockfd, bitmap, bitmap_len, 0,
flipdot->addrs->ai_addr, flipdot->addrs->ai_addrlen);
if (FLIPDOT_DEBUG) {
fprintf(stderr, "flipdot_send(): sent %ld bytes\n", sent);
}
return (sent == (ssize_t)bitmap_len);
}