#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include static int connect_local(unsigned short port) { struct sockaddr_in address; int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (connect(fd, (struct sockaddr *)&address, sizeof(address))) { close(fd); return -1; } return fd; } static int send_all(int fd, const char *data, size_t length) { while (length) { ssize_t sent = send(fd, data, length, 0); if (sent < 0 && errno == EINTR) continue; if (sent <= 0) return -1; data += sent; length -= (size_t)sent; } return 0; } static int request_page(unsigned short port, const char *url) { const char *key = "abcdef1234567890"; char request[4096], buffer[4096]; int fd, n; int length = snprintf(request, sizeof(request), "\n", key, url); if (length < 0 || (size_t)length >= sizeof(request)) return -1; fd = connect_local(port); if (fd < 0) return -1; if (send_all(fd, request, (size_t)length) || shutdown(fd, SHUT_WR)) { close(fd); return -1; } while ((n = (int)recv(fd, buffer, sizeof(buffer), 0)) > 0) { if (fwrite(buffer, 1, (size_t)n, stdout) != (size_t)n) { close(fd); return -1; } } close(fd); if (n < 0) return -1; return fflush(stdout) ? -1 : 0; } int main(int argc, char **argv) { struct sockaddr_in address; socklen_t address_length = sizeof(address); unsigned short port; int listener; pid_t child; int status, fd; if (argc != 3) { fprintf(stderr, "usage: %s DPI-HELPER URL\n", argv[0]); return 2; } listener = socket(AF_INET, SOCK_STREAM, 0); if (listener < 0) { perror("socket"); return 1; } memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); address.sin_port = 0; if (bind(listener, (struct sockaddr *)&address, sizeof(address)) || listen(listener, 8) || getsockname(listener, (struct sockaddr *)&address, &address_length)) { perror("bind/listen"); close(listener); return 1; } port = ntohs(address.sin_port); child = fork(); if (child < 0) { perror("fork"); close(listener); return 1; } if (!child) { if (dup2(listener, STDIN_FILENO) < 0) _exit(126); close(listener); execl(argv[1], argv[1], (char *)NULL); perror("exec"); _exit(127); } close(listener); if (request_page(port, argv[2])) { perror("request page"); kill(child, SIGTERM); waitpid(child, NULL, 0); return 1; } fd = connect_local(port); { const char *bye = "\n"; if (fd < 0 || send_all(fd, bye, strlen(bye))) { perror("send DpiBye"); kill(child, SIGTERM); waitpid(child, NULL, 0); return 1; } } shutdown(fd, SHUT_WR); close(fd); if (waitpid(child, &status, 0) < 0) { perror("waitpid"); return 1; } return WIFEXITED(status) ? WEXITSTATUS(status) : 1; }