ab5c05568dbf19017b0974e8b9583c7ae9ac654b
[reposerve] / server / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <limits.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/select.h>
11 #include <netinet/in.h>
12 #include "repo.h"
13 #include "client.h"
14
15 static const char *guess_repo_name(const char *path);
16 static int parse_args(int argc, char **argv);
17
18 static const char *repo_name;
19 static int lis = -1;
20 static int port = 64357;
21
22 static struct client *clients;
23
24 const char *repo_path;
25
26
27 int main(int argc, char **argv)
28 {
29         struct sockaddr_in addr;
30
31         if(parse_args(argc, argv) == -1) {
32                 return 1;
33         }
34
35         if(repo_init(repo_path) == -1) {
36                 return 1;
37         }
38         /* repo_cleanup(); */
39
40         if(!repo_name) {
41                 if(!(repo_name = guess_repo_name(repo_path))) {
42                         return 1;
43                 }
44         }
45
46         printf("Serving %s from %s\n", repo_name, repo_path);
47
48         if(!(lis = socket(PF_INET, SOCK_STREAM, 0))) {
49                 fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
50                 return 1;
51         }
52
53         memset(&addr, 0, sizeof addr);
54         addr.sin_family = AF_INET;
55         addr.sin_port = htons(port);
56         addr.sin_addr.s_addr = INADDR_ANY;
57
58         if(bind(lis, (struct sockaddr*)&addr, sizeof addr) == -1) {
59                 fprintf(stderr, "failed to bind listening socket to port %d\n", port);
60                 return 1;
61         }
62         listen(lis, 8);
63
64         for(;;) {
65                 int res, max_fd, s;
66                 fd_set rdset;
67                 struct client *c, dummy;
68
69                 FD_SET(lis, &rdset);
70                 max_fd = lis;
71
72                 c = clients;
73                 while(c) {
74                         FD_SET(c->s, &rdset);
75                         if(c->s > max_fd) max_fd = c->s;
76                         c = c->next;
77                 }
78
79                 if((res = select(max_fd + 1, &rdset, 0, 0, 0)) == -1 && errno != EINTR) {
80                         perror("select failed");
81                         break;
82                 }
83
84                 if(res <= 0) continue;
85
86                 dummy.next = clients;
87                 c = &dummy;
88                 while(c->next) {
89                         if(FD_ISSET(c->next->s, &rdset)) {
90                                 if(handle_client(c->next) == -1) {
91                                         struct client *tmp = c->next;
92                                         c->next = tmp->next;
93                                         close(tmp->s);
94                                         free(tmp);
95                                         continue;
96                                 }
97                         }
98                         c = c->next;
99                 }
100                 clients = dummy.next;
101
102                 if(FD_ISSET(lis, &rdset)) {
103                         if((s = accept(lis, 0, 0)) == -1) {
104                                 perror("failed to accept connection");
105                                 continue;
106                         }
107                         if(!(c = calloc(1, sizeof *c))) {
108                                 perror("failed to allocate memory for client structure");
109                                 close(s);
110                                 continue;
111                         }
112                         c->s = s;
113                         c->next = clients;
114                         clients = c;
115
116                         send_string(c, "reposerve-0.1 protocol:0\n");
117                 }
118         }
119
120         return 0;
121 }
122
123 static const char *guess_repo_name(const char *path)
124 {
125         static char pathbuf[PATH_MAX];
126         char *last_slash;
127         int len;
128
129         if(!realpath(path, pathbuf)) {
130                 goto fail;
131         }
132         len = strlen(pathbuf);
133
134         if(len > 0 && pathbuf[len - 1] == '/') {
135                 pathbuf[--len] = 0;
136         }
137         if(len <= 0) goto fail;
138
139         if((last_slash = strrchr(pathbuf, '/'))) {
140                 return last_slash + 1;
141         }
142         return pathbuf;
143
144 fail:
145         fprintf(stderr, "failed to resolve path %s while determining the repo name. Please specify an explicit name with -id\n", repo_path);
146         return 0;
147 }
148
149 static void print_usage(const char *argv0)
150 {
151         printf("Usage: %s [options] [repo path]\n", argv0);
152         printf("options:\n");
153         printf("  -id <name>: repo identifier (defaults to directory name)\n");
154         printf("  -h,-help: print help and exit\n");
155 }
156
157 static int parse_args(int argc, char **argv)
158 {
159         int i;
160
161         for(i=1; i<argc; i++) {
162                 if(argv[i][0] == '-') {
163                         if(strcmp(argv[i], "-id") == 0) {
164                                 repo_name = argv[++i];
165                         } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
166                                 print_usage(argv[0]);
167                                 exit(0);
168                         } else {
169                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
170                                 return -1;
171                         }
172                 } else {
173                         if(repo_path) {
174                                 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
175                                 return -1;
176                         }
177                         repo_path = argv[i];
178                 }
179         }
180
181         if(!repo_path) repo_path = ".";
182         return 0;
183 }