Change-Id: I92ebde397e679c7e3f8ddcf6fcecd6af5c84f629 Reviewed-on: https://cl.tvl.fyi/c/depot/+/13012 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
89 lines
2.7 KiB
C
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);
|
|
}
|