#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SPOOF #include #endif //SPOOF #define LOGF(x, ...) do { logf_impl(x, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0); #define LOG(x) do { log_impl(x, __FILE__, __LINE__, __func__); } while(0); #define DEFAULT_PORT 9305 #define MBUF_SIZE 2048 #define TROMMEL_PIN 17 const char *SOCKET_ERROR = "Socket-fout"; const char *LOG_FMT = "[%s:%d %s]: %s"; int log_prefix_length = 0; typedef struct mbuf { /// Internal buffer char buffer[MBUF_SIZE]; /// Socket/file descriptor int sock; /// Read position size_t rpos, /// Write position wpos; } mbuf_t; void log_impl(const char *message, const char *file, int line, const char *func) { syslog(LOG_INFO, LOG_FMT, file + log_prefix_length, line, func, message); } void logf_impl(const char *message, const char *file, int line, const char *func, ...) { va_list args; va_start(args, func); int c = snprintf(NULL, 0, LOG_FMT, file + log_prefix_length, line, func, message); char *msg = malloc(c + 1); snprintf(msg, c + 1, LOG_FMT, file + log_prefix_length, line, func, message); vsyslog(LOG_INFO, msg, args); va_end(args); free(msg); } int quit_if_fail(int err, const char *failMessage) { if (err < 0) { int no = errno; LOGF( "%s: %s", failMessage, strerror(no)); exit(EXIT_FAILURE); } return err; } mbuf_t *mbuf_create(void) { mbuf_t *res = malloc(sizeof(mbuf_t)); res->rpos = 0; res->wpos = 0; res->sock = -1; memset(res->buffer, 0, MBUF_SIZE * sizeof(char)); return res; } /** * Reads until it encounters `c` from the given socket * * `c` is not included in the output. The output is null-terminated. * * @param c The character to stop reading * @param out A pointer to allocated memory where the read line can be stored. * @param max_size The max size. */ int mbuf_read_until(mbuf_t *buf, char c, char *out, size_t max_size) { size_t i = 0; ssize_t n; while (i < max_size) { if (buf->rpos == buf->wpos) { size_t wpos = buf->wpos % MBUF_SIZE; if ((n = read(buf->sock, buf->buffer + wpos, MBUF_SIZE - wpos)) < 0) { //if (errno == EINTR) continue; return -1; } else if (n == 0) { return 0; } else { buf->wpos += n; } } out[i++] = buf->buffer[buf->rpos++ % MBUF_SIZE]; if (out[i - 1] == c) break; } if (i == max_size) { errno = EOVERFLOW; //LOGF("Buffer is te klein (bijts gelezen %d > %d)", i, max_size); return -1; } out[i - 1] = '\0'; return i - 1; } void do_trommel() { #ifndef SPOOF bcm2835_gpio_write(TROMMEL_PIN, HIGH); bcm2835_delay(250); bcm2835_gpio_write(TROMMEL_PIN, LOW); #endif //SPOOF } int do_handshake(mbuf_t *mbuf) { char buf[1024]; if (mbuf_read_until(mbuf, '\n', buf, sizeof(buf)) < 0) return -1; int reslen = strlen(buf) - strlen("e gaat 'ie?"); if (reslen < 2 || (reslen & 1)) { errno = EPROTO; return -1; } // oed\0 size_t response_size = reslen + 4; char *response = (char *) malloc(response_size); response[0] = '\0'; reslen /= 2; for (int i = 0; i < reslen; i++) { strcat(response, "go"); } strcat(response, "ed\n"); if (write(mbuf->sock, response, response_size - 1) < 0) return -1; free(response); return 0; } int do_command_loop(mbuf_t *mbuf) { char buf[1024]; int len; while(1) { if ( (len = mbuf_read_until(mbuf, '\n', buf, sizeof(buf))) < 0) return -1; if (len == 0) return 0; LOGF("COMMANDO: %s", buf); if (strcmp(buf, "trommel") == 0) { do_trommel(); const char *ok = "oké\n"; write(mbuf->sock, ok, strlen(ok) * sizeof(char)); } else if (strcmp(buf, "ping") == 0) { write(mbuf->sock, "pong\n", 5 * sizeof(char)); } else { const char *mesg = "onbekend commando\n"; write(mbuf->sock, mesg, strlen(mesg) * sizeof(char)); } } return 0; } int main(int argc, char *argv[]) { #ifdef LOG_PREFIX log_prefix_length = strlen(LOG_PREFIX); #endif openlog(argv[0], LOG_ODELAY, LOG_DAEMON); if (argc < 3) { LOGF("GEBRUIK: %s ADRES POORT", argv[0]); return EXIT_FAILURE; } LOG("Kerstezel starten"); // Daemonize //pid_t pid; //pid = quit_if_fail(fork(), "Kon niet vorken"); //if (pid > 0) exit(EXIT_SUCCESS); quit_if_fail(chdir("/"), "Kon werkmap niet veranderen"); //quit_if_fail(setsid(), "Kon sid niet veranderen"); // Zorg ervoor dat de daemon geen TTY kan bemachtigen //pid = quit_if_fail(fork(), "Kon niet vorken"); //if (pid > 0) exit(EXIT_SUCCESS); // WRITE PIDFILE /*FILE *fd = fopen(pid_path, "w"); if (fd != NULL) { fprintf(fd, "%d", getpid()); fclose(fd); }*/ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); #ifndef SPOOF bcm2835_init(); bcm2835_gpio_fsel(TROMMEL_PIN, BCM2835_GPIO_FSEL_OUTP); LOG("bcm2835 geinitialiseerd") #endif //SPOOF struct addrinfo hints, *servinfo, *p; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int res, res2; if ((res = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) { LOGF("Fout bij het herleiden van de gastheernaam: %s", gai_strerror(res)); exit(EXIT_FAILURE); } mbuf_t *buf = mbuf_create(); char address[INET6_ADDRSTRLEN] = {0}; for (p = servinfo; p != NULL; p = p->ai_next) { void *ptr = NULL; switch(p->ai_family) { case AF_INET: ptr = &((struct sockaddr_in *) p->ai_addr)->sin_addr; break; case AF_INET6: ptr = &((struct sockaddr_in6 *) p->ai_addr)->sin6_addr; break; } if (inet_ntop(p->ai_family, ptr, address, p->ai_addrlen) == NULL) { LOGF("Kon adres niet omzetten: %s", strerror(errno)); } else { LOGF("Verbinden met %s", address); } res = socket(p->ai_family, SOCK_STREAM, 0); if (res < 0) continue; res2 = connect(res, p->ai_addr, sizeof(address)); if (res2 == 0) break; } buf->sock = res; quit_if_fail(res, "Kon niet verbinden"); //(void) quit_if_fail(connect(buf->sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)), "Kon niet verbinden"); /*if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT) < 0) { LOGF("Kon seccomp niet aanroepen: %s", strerror(errno)); }*/ (void) quit_if_fail(do_handshake(buf), "Handenschudden mislukt"); LOG("Handjeschudden voltooid") (void) quit_if_fail(do_command_loop(buf), "Fout"); LOG("De andere kant heeft de verbinding verbroken"); free(buf); #ifndef SPOOF bcm2835_close(); #endif //SPOOF return 0; }