#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define S0(x) (x ? x : "") struct entry { uint64_t time __attribute__((packed)); uint64_t value __attribute__((packed)); } __attribute__((packed)); int samomor = 0; void handle_me (int s __attribute__((unused))) { samomor++; } int main (int argc, char ** argv) { if (argc < 1+1) error_at_line(1, 0, __FILE__, __LINE__, "uporaba: %s db [port=35358] [bind=::] [src=]", S0(argv[0])); struct sigaction act = { .sa_handler = handle_me, .sa_flags = SA_RESTART }; if (sigaction(SIGINT, &act, NULL) == -1) error_at_line(2, errno, __FILE__, __LINE__, "sigaction SIGINT"); if (sigaction(SIGTERM, &act, NULL) == -1) error_at_line(3, errno, __FILE__, __LINE__, "sigaction SIGTERM"); #define DB argv[1] int port = 35358; if (argc >= 1+2) port = atoi(argv[2]); struct sockaddr_in6 bind_address = { .sin6_family = AF_INET6, .sin6_port = htons(port), .sin6_addr = in6addr_any }; if (argc >= 1+3) switch (inet_pton(AF_INET6, argv[3], &bind_address.sin6_addr)) { case 0: error_at_line(4, 0, __FILE__, __LINE__, "!inet_pton(AF_INET6, argv[3], &bind_address.sin6_addr)"); break; case -1: error_at_line(5, errno, __FILE__, __LINE__, "inet_pton"); } struct sockaddr_in6 src = { .sin6_family = AF_INET6, .sin6_port = htons(port), .sin6_addr = in6addr_any }; int whitelist_src = 0; if (argc >= 1+4) { whitelist_src++; switch (inet_pton(AF_INET6, argv[4], &src.sin6_addr)) { case 0: error_at_line(6, 0, __FILE__, __LINE__, "!inet_pton(AF_INET6, argv[4], &src.sin6_addr)"); break; case -1: error_at_line(7, errno, __FILE__, __LINE__, "inet_pton"); } } int udp = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (udp == -1) error_at_line(10, errno, __FILE__, __LINE__, "socket"); FILE * db = NULL; int z = 1; int r = 0; if (setsockopt(udp, SOL_SOCKET, SO_BROADCAST, &z, sizeof z) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "setsockopt"); r = 11; goto r; } if (bind(udp, (struct sockaddr *) &bind_address, sizeof bind_address)) { error_at_line(0, errno, __FILE__, __LINE__, "bind"); r = 12; goto r; } if (!(db = fopen(DB, "a"))) { error_at_line(0, errno, __FILE__, __LINE__, "fopen"); r = 13; goto r; } while (!samomor) { struct pollfd pollfd = { .fd = udp, .events = POLLIN | POLLERR | POLLHUP | POLLNVAL }; if (poll(&pollfd, 1, -1) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "poll"); r = 14; goto r; } if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP) || (pollfd.revents & POLLNVAL)) { error_at_line(0, 0, __FILE__, __LINE__, "POLLERR || POLLHUP || POLLNVAL"); r = 15; goto r; } struct sockaddr_storage sender; socklen_t sender_len = sizeof sender; char buf[512]; ssize_t bytes = recvfrom(udp, buf, 256, MSG_DONTWAIT, (struct sockaddr *) &sender, &sender_len); if (bytes == -1) { error_at_line(0, errno, __FILE__, __LINE__, "recvfrom"); r = 16; goto r; } struct timespec current_time; if (clock_gettime(CLOCK_REALTIME, ¤t_time) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "clock_gettime"); r = 17; goto r; } uint64_t current_time_us = current_time.tv_sec*1000000+current_time.tv_nsec/1000; unsigned long long int current_Wh = strtoull(buf, NULL, 10); struct entry entry = { .time = htobe64(current_time_us), .value = htobe64(current_Wh) }; char sender_host[512]; char sender_port[512]; int gni = getnameinfo((struct sockaddr *) &sender, sender_len, sender_host, 512, sender_port, 512, NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV); if (gni) { error_at_line(0, 0, __FILE__, __LINE__, "getnameinfo: %s", gai_strerror(gni)); r = 19; goto r; } time_t sedaj = time(NULL); strcpy(buf, ctime(&sedaj)); buf[strlen(buf)-1] = '\0'; if (sender.ss_family != AF_INET6) if (whitelist_src) { fprintf(stderr, "[%s] %s:%s\tsender.ss_family != AF_INET6\n", buf, sender_host, sender_port); continue; } if (whitelist_src && memcmp(&((struct sockaddr_in6 *) &sender)->sin6_addr, &src.sin6_addr, sizeof(src.sin6_addr))) { fprintf(stderr, "[%s] %s:%s\tfailed src whitelist\n", buf, sender_host, sender_port); continue; } fprintf(stderr, "[%s] %s:%s\t%llu Wh\n", buf, sender_host, sender_port, current_Wh); if (fwrite(&entry, sizeof entry, 1, db) != 1) { error_at_line(0, 0, __FILE__, __LINE__, "fwrite"); r = 18; goto r; } fflush(db); } r: if (close(udp) == -1) error_at_line(19, errno, __FILE__, __LINE__, "close(udp)"); if (db != NULL) if (fclose(db) == -1) error_at_line(20, errno, __FILE__, __LINE__, "fclose(db)"); return r; }