#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <limits.h>
#include <time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include "repo.h"
-
-#include "md5.h"
+#include "client.h"
static const char *guess_repo_name(const char *path);
+static void sighandler(int s);
static int parse_args(int argc, char **argv);
-static const char *repo_path, *repo_name;
+static const char *repo_name;
+static int lis = -1;
+static int port = 64357;
+static int quit;
+
+static struct client *clients;
+
+const char *repo_path;
+
int main(int argc, char **argv)
{
+ struct sockaddr_in addr;
+
if(parse_args(argc, argv) == -1) {
return 1;
}
+ signal(SIGINT, sighandler);
+ signal(SIGQUIT, sighandler);
+ signal(SIGILL, sighandler);
+ signal(SIGSEGV, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGPIPE, SIG_IGN);
+
if(repo_init(repo_path) == -1) {
return 1;
}
printf("Serving %s from %s\n", repo_name, repo_path);
- /* DBG */
- {
- struct md5_state sum;
- int i, count = repo_num_files();
- for(i=0; i<count; i++) {
- struct repo_file *file = repo_file(i);
- memcpy(sum.sum, file->chksum, sizeof sum.sum);
- printf("%s\tmd5:%s size:%lu mtime:%s", file->path, md5_sumstr(&sum),
- (unsigned long)file->size, ctime(&file->mtime));
+ if(!(lis = socket(PF_INET, SOCK_STREAM, 0))) {
+ fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
+ return 1;
+ }
+ fcntl(lis, F_SETFL, fcntl(lis, F_GETFL) | O_NONBLOCK);
+
+ memset(&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if(bind(lis, (struct sockaddr*)&addr, sizeof addr) == -1) {
+ fprintf(stderr, "failed to bind listening socket to port %d\n", port);
+ return 1;
+ }
+ listen(lis, 8);
+
+ for(;;) {
+ int res, max_fd, s;
+ fd_set rdset;
+ struct client *c, dummy;
+
+ FD_SET(lis, &rdset);
+ max_fd = lis;
+
+ c = clients;
+ while(c) {
+ FD_SET(c->s, &rdset);
+ if(c->s > max_fd) max_fd = c->s;
+ c = c->next;
+ }
+
+ if((res = select(max_fd + 1, &rdset, 0, 0, 0)) == -1 && errno != EINTR) {
+ perror("select failed");
+ break;
+ }
+ if(quit) break;
+ if(res <= 0) continue;
+
+ dummy.next = clients;
+ c = &dummy;
+ while(c->next) {
+ if(FD_ISSET(c->next->s, &rdset)) {
+ if(handle_client(c->next) == -1) {
+ struct client *tmp = c->next;
+ c->next = tmp->next;
+
+ printf("Client %s disconnected\n", tmp->addr ? tmp->addr : "unknown");
+ close(tmp->s);
+ free(tmp->addr);
+ free(tmp);
+ continue;
+ }
+ }
+ c = c->next;
+ }
+ clients = dummy.next;
+
+ if(FD_ISSET(lis, &rdset)) {
+ struct sockaddr_in addr;
+ unsigned int addrsz = sizeof addr;
+
+ if((s = accept(lis, (struct sockaddr*)&addr, &addrsz)) == -1) {
+ perror("failed to accept connection");
+ continue;
+ }
+ fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
+
+ if(!(c = calloc(1, sizeof *c))) {
+ perror("failed to allocate memory for client structure");
+ close(s);
+ continue;
+ }
+ c->s = s;
+ c->next = clients;
+ c->addr = strdup(inet_ntoa(addr.sin_addr));
+ clients = c;
+
+ send_string(c, "reposerve-0.1 protocol:0\n");
+
+ printf("Connection from: %s\n", c->addr ? c->addr : "unknown");
}
}
+ printf("Shutting down\n");
return 0;
}
return 0;
}
+static void sighandler(int s)
+{
+ quit = 1;
+}
+
static void print_usage(const char *argv0)
{
printf("Usage: %s [options] [repo path]\n", argv0);