+ return 1;
+}
+
+void sigterm_handler(int sig)
+{
+ if (unlink(PID_FILE) == -1)
+ perror("Can't remove PID file");
+
+ exit(EXIT_SUCCESS);
+}
+
+#define FLAG_DAEMON (1 << 0)
+#define FLAG_PID_FILE (1 << 1)
+
+static int socket_server(char *iface, int port, int flags)
+{
+ struct sigaction sact;
+ struct sockaddr_in sin;
+ int sock;
+ int n;
+ pid_t pid;
+
+ if (flags & FLAG_DAEMON) {
+ FILE *pidfile = NULL;
+
+ if (flags & FLAG_PID_FILE) {
+ int fd;
+
+ fd = open(PID_FILE, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ if (fd == -1) {
+ if (errno == EEXIST) {
+ pid_t old_pid;
+ pidfile = fopen(PID_FILE, "r");
+ if (!pidfile) {
+ perror("PID file " PID_FILE " already exists, already running?");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fscanf(pidfile, "%u", &old_pid) != 1) {
+ fclose(pidfile);
+ fprintf(stderr, "Can't read old PID from " PID_FILE ", already running?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(pidfile);
+
+ fprintf(stderr, "Already running with PID %u according to " PID_FILE "!\n", old_pid);
+ exit(EXIT_FAILURE);
+ }
+ perror("Can't create PID file " PID_FILE);
+ exit(EXIT_FAILURE);
+ }
+
+ pidfile = fdopen(fd, "w");
+ if (!pidfile) {
+ perror("Can't reopen PID file fd");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&sact, 0, sizeof(sact));
+ sact.sa_handler = sigterm_handler;
+
+ if (sigaction(SIGTERM, &sact, NULL) == -1) {
+ perror("sigaction(SIGTERM)");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ pid = fork();
+ if (pid > 0) {
+ if (pidfile) {
+ fprintf(pidfile, "%u\n", pid);
+ fclose(pidfile);
+ }
+
+ printf("Daemon with PID %u started!\n", pid);
+ exit(EXIT_SUCCESS);
+ } else if (pid < 0) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ }
+
+ if (pidfile)
+ fclose(pidfile);
+ }
+
+ memset(&sact, 0, sizeof(sact));
+ sact.sa_handler = SIG_IGN;
+
+ if (sigaction(SIGPIPE, &sact, NULL) == -1) {
+ perror("sigaction(SIGPIPE)");
+ exit(EXIT_FAILURE);
+ }
+
+ impersonate_hmlanif = 1;
+
+ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == -1) {
+ perror("Can't open socket");
+ return EXIT_FAILURE;
+ }
+
+ n = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
+ perror("Can't set socket options");
+ return EXIT_FAILURE;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ if (!iface) {
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ if (inet_pton(AF_INET, iface, &(sin.sin_addr.s_addr)) != 1) {
+ fprintf(stderr, "Can't convert IP %s, aborting!\n", iface);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
+ perror("Can't bind socket");
+ return EXIT_FAILURE;
+ }
+
+ if (listen(sock, 1) == -1) {
+ perror("Can't listen on socket");
+ return EXIT_FAILURE;
+ }
+
+ while(1) {
+ struct sockaddr_in csin;
+ socklen_t csinlen;
+ int client;
+ in_addr_t client_addr;
+
+ memset(&csin, 0, sizeof(csin));
+ csinlen = sizeof(csin);
+ client = accept(sock, (struct sockaddr*)&csin, &csinlen);
+ if (client == -1) {
+ perror("Couldn't accept client");
+ continue;
+ }
+
+ /* FIXME: getnameinfo... */
+ client_addr = ntohl(csin.sin_addr.s_addr);
+
+ if (verbose) {
+ print_timestamp(stdout);
+ printf("Client %d.%d.%d.%d connected!\n",
+ (client_addr & 0xff000000) >> 24,
+ (client_addr & 0x00ff0000) >> 16,
+ (client_addr & 0x0000ff00) >> 8,
+ (client_addr & 0x000000ff));
+ }
+
+ comm(client, client, sock, flags);
+
+ shutdown(client, SHUT_RDWR);
+ close(client);
+
+ if (verbose) {
+ print_timestamp(stdout);
+ printf("Connection to %d.%d.%d.%d closed!\n",
+ (client_addr & 0xff000000) >> 24,
+ (client_addr & 0x00ff0000) >> 16,
+ (client_addr & 0x0000ff00) >> 8,
+ (client_addr & 0x000000ff));
+ }
+ sleep(1);
+ }