#define _DEFAULT_SOURCE // see getnameinfo(3), for NI_MAX* #define _POSIX_C_SOURCE 200112L // see getaddrinfo(3) #include #include #include #include #include #include #include #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); }