[PATCH] Verbose git-daemon logging
[git.git] / daemon.c
1 #include "cache.h"
2 #include "pkt-line.h"
3 #include <signal.h>
4 #include <sys/wait.h>
5 #include <sys/socket.h>
6 #include <sys/time.h>
7 #include <netdb.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10
11 static int verbose;
12
13 static const char daemon_usage[] = "git-daemon [--verbose] [--inetd | --port=n]";
14
15
16 static void logreport(const char *err, va_list params)
17 {
18         /* We should do a single write so that it is atomic and output
19          * of several processes do not get intermingled. */
20         char buf[1024];
21         int buflen;
22         int maxlen, msglen;
23
24         /* sizeof(buf) should be big enough for "[pid] \n" */
25         buflen = snprintf(buf, sizeof(buf), "[%d] ", getpid());
26
27         maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
28         msglen = vsnprintf(buf + buflen, maxlen, err, params);
29
30         /* maxlen counted our own LF but also counts space given to
31          * vsnprintf for the terminating NUL.  We want to make sure that
32          * we have space for our own LF and NUL after the "meat" of the
33          * message, so truncate it at maxlen - 1.
34          */
35         if (msglen > maxlen - 1)
36                 msglen = maxlen - 1;
37         else if (msglen < 0)
38                 msglen = 0; /* Protect against weird return values. */
39         buflen += msglen;
40
41         buf[buflen++] = '\n';
42         buf[buflen] = '\0';
43
44         write(2, buf, buflen);
45 }
46
47 void logerror(const char *err, ...)
48 {
49         va_list params;
50         va_start(params, err);
51         logreport(err, params);
52         va_end(params);
53 }
54
55 void lognotice(const char *err, ...)
56 {
57         va_list params;
58         if (!verbose)
59                 return;
60         va_start(params, err);
61         logreport(err, params);
62         va_end(params);
63 }
64
65
66 static int upload(char *dir, int dirlen)
67 {
68         lognotice("Request for '%s'", dir);
69         if (chdir(dir) < 0) {
70                 logerror("Cannot chdir('%s'): %s", dir, strerror(errno));
71                 return -1;
72         }
73         chdir(".git");
74
75         /*
76          * Security on the cheap.
77          *
78          * We want a readable HEAD, usable "objects" directory, and 
79          * a "git-daemon-export-ok" flag that says that the other side
80          * is ok with us doing this.
81          */
82         if (access("git-daemon-export-ok", F_OK) ||
83             access("objects/00", X_OK) ||
84             access("HEAD", R_OK)) {
85                 logerror("Not a valid gitd-enabled repository: '%s'", dir);
86                 return -1;
87         }
88
89         /*
90          * We'll ignore SIGTERM from now on, we have a
91          * good client.
92          */
93         signal(SIGTERM, SIG_IGN);
94
95         /* git-upload-pack only ever reads stuff, so this is safe */
96         execlp("git-upload-pack", "git-upload-pack", ".", NULL);
97         return -1;
98 }
99
100 static int execute(void)
101 {
102         static char line[1000];
103         int len;
104
105         len = packet_read_line(0, line, sizeof(line));
106
107         if (len && line[len-1] == '\n')
108                 line[--len] = 0;
109
110         if (!strncmp("git-upload-pack /", line, 17))
111                 return upload(line + 16, len - 16);
112
113         logerror("Protocol error: '%s'", line);
114         return -1;
115 }
116
117
118 /*
119  * We count spawned/reaped separately, just to avoid any
120  * races when updating them from signals. The SIGCHLD handler
121  * will only update children_reaped, and the fork logic will
122  * only update children_spawned.
123  *
124  * MAX_CHILDREN should be a power-of-two to make the modulus
125  * operation cheap. It should also be at least twice
126  * the maximum number of connections we will ever allow.
127  */
128 #define MAX_CHILDREN 128
129
130 static int max_connections = 25;
131
132 /* These are updated by the signal handler */
133 static volatile unsigned int children_reaped = 0;
134 static pid_t dead_child[MAX_CHILDREN];
135
136 /* These are updated by the main loop */
137 static unsigned int children_spawned = 0;
138 static unsigned int children_deleted = 0;
139
140 static struct child {
141         pid_t pid;
142         int addrlen;
143         struct sockaddr_storage address;
144 } live_child[MAX_CHILDREN];
145
146 static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
147 {
148         live_child[idx].pid = pid;
149         live_child[idx].addrlen = addrlen;
150         memcpy(&live_child[idx].address, addr, addrlen);
151 }
152
153 /*
154  * Walk from "deleted" to "spawned", and remove child "pid".
155  *
156  * We move everything up by one, since the new "deleted" will
157  * be one higher.
158  */
159 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
160 {
161         struct child n;
162
163         deleted %= MAX_CHILDREN;
164         spawned %= MAX_CHILDREN;
165         if (live_child[deleted].pid == pid) {
166                 live_child[deleted].pid = -1;
167                 return;
168         }
169         n = live_child[deleted];
170         for (;;) {
171                 struct child m;
172                 deleted = (deleted + 1) % MAX_CHILDREN;
173                 if (deleted == spawned)
174                         die("could not find dead child %d\n", pid);
175                 m = live_child[deleted];
176                 live_child[deleted] = n;
177                 if (m.pid == pid)
178                         return;
179                 n = m;
180         }
181 }
182
183 /*
184  * This gets called if the number of connections grows
185  * past "max_connections".
186  *
187  * We _should_ start off by searching for connections
188  * from the same IP, and if there is some address wth
189  * multiple connections, we should kill that first.
190  *
191  * As it is, we just "randomly" kill 25% of the connections,
192  * and our pseudo-random generator sucks too. I have no
193  * shame.
194  *
195  * Really, this is just a place-holder for a _real_ algorithm.
196  */
197 static void kill_some_children(int signo, unsigned start, unsigned stop)
198 {
199         start %= MAX_CHILDREN;
200         stop %= MAX_CHILDREN;
201         while (start != stop) {
202                 if (!(start & 3))
203                         kill(live_child[start].pid, signo);
204                 start = (start + 1) % MAX_CHILDREN;
205         }
206 }
207
208 static void check_max_connections(void)
209 {
210         for (;;) {
211                 int active;
212                 unsigned spawned, reaped, deleted;
213
214                 spawned = children_spawned;
215                 reaped = children_reaped;
216                 deleted = children_deleted;
217
218                 while (deleted < reaped) {
219                         pid_t pid = dead_child[deleted % MAX_CHILDREN];
220                         remove_child(pid, deleted, spawned);
221                         deleted++;
222                 }
223                 children_deleted = deleted;
224
225                 active = spawned - deleted;
226                 if (active <= max_connections)
227                         break;
228
229                 /* Kill some unstarted connections with SIGTERM */
230                 kill_some_children(SIGTERM, deleted, spawned);
231                 if (active <= max_connections << 1)
232                         break;
233
234                 /* If the SIGTERM thing isn't helping use SIGKILL */
235                 kill_some_children(SIGKILL, deleted, spawned);
236                 sleep(1);
237         }
238 }
239
240 static void handle(int incoming, struct sockaddr *addr, int addrlen)
241 {
242         pid_t pid = fork();
243         char addrbuf[256] = "";
244         int port = -1;
245
246         if (pid) {
247                 unsigned idx;
248
249                 close(incoming);
250                 if (pid < 0)
251                         return;
252
253                 idx = children_spawned % MAX_CHILDREN;
254                 children_spawned++;
255                 add_child(idx, pid, addr, addrlen);
256
257                 check_max_connections();
258                 return;
259         }
260
261         dup2(incoming, 0);
262         dup2(incoming, 1);
263         close(incoming);
264
265         if (addr->sa_family == AF_INET) {
266                 struct sockaddr_in *sin_addr = (void *) addr;
267                 inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
268                 port = sin_addr->sin_port;
269
270         } else if (addr->sa_family == AF_INET6) {
271                 struct sockaddr_in6 *sin6_addr = (void *) addr;
272
273                 char *buf = addrbuf;
274                 *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
275                 inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
276                 strcat(buf, "]");
277
278                 port = sin6_addr->sin6_port;
279         }
280         lognotice("Connection from %s:%d", addrbuf, port);
281
282         exit(execute());
283 }
284
285 static void child_handler(int signo)
286 {
287         for (;;) {
288                 pid_t pid = waitpid(-1, NULL, WNOHANG);
289
290                 if (pid > 0) {
291                         unsigned reaped = children_reaped;
292                         dead_child[reaped % MAX_CHILDREN] = pid;
293                         children_reaped = reaped + 1;
294                         /* XXX: Custom logging, since we don't wanna getpid() */
295                         if (verbose)
296                                 fprintf(stderr, "[%d] Disconnected\n", pid);
297                         continue;
298                 }
299                 break;
300         }
301 }
302
303 static int serve(int port)
304 {
305         struct addrinfo hints, *ai0, *ai;
306         int gai;
307         int socknum = 0, *socklist = NULL;
308         int maxfd = -1;
309         fd_set fds_init, fds;
310         char pbuf[NI_MAXSERV];
311
312         signal(SIGCHLD, child_handler);
313
314         sprintf(pbuf, "%d", port);
315         memset(&hints, 0, sizeof(hints));
316         hints.ai_family = AF_UNSPEC;
317         hints.ai_socktype = SOCK_STREAM;
318         hints.ai_protocol = IPPROTO_TCP;
319         hints.ai_flags = AI_PASSIVE;
320
321         gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
322         if (gai)
323                 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
324
325         FD_ZERO(&fds_init);
326
327         for (ai = ai0; ai; ai = ai->ai_next) {
328                 int sockfd;
329                 int *newlist;
330
331                 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
332                 if (sockfd < 0)
333                         continue;
334                 if (sockfd >= FD_SETSIZE) {
335                         error("too large socket descriptor.");
336                         close(sockfd);
337                         continue;
338                 }
339
340 #ifdef IPV6_V6ONLY
341                 if (ai->ai_family == AF_INET6) {
342                         int on = 1;
343                         setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
344                                    &on, sizeof(on));
345                         /* Note: error is not fatal */
346                 }
347 #endif
348
349                 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
350                         close(sockfd);
351                         continue;       /* not fatal */
352                 }
353                 if (listen(sockfd, 5) < 0) {
354                         close(sockfd);
355                         continue;       /* not fatal */
356                 }
357
358                 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
359                 if (!newlist)
360                         die("memory allocation failed: %s", strerror(errno));
361
362                 socklist = newlist;
363                 socklist[socknum++] = sockfd;
364
365                 FD_SET(sockfd, &fds_init);
366                 if (maxfd < sockfd)
367                         maxfd = sockfd;
368         }
369
370         freeaddrinfo(ai0);
371
372         if (socknum == 0)
373                 die("unable to allocate any listen sockets on port %u", port);
374
375         for (;;) {
376                 int i;
377                 fds = fds_init;
378                 
379                 if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
380                         if (errno != EINTR) {
381                                 error("select failed, resuming: %s",
382                                       strerror(errno));
383                                 sleep(1);
384                         }
385                         continue;
386                 }
387
388                 for (i = 0; i < socknum; i++) {
389                         int sockfd = socklist[i];
390
391                         if (FD_ISSET(sockfd, &fds)) {
392                                 struct sockaddr_storage ss;
393                                 int sslen = sizeof(ss);
394                                 int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
395                                 if (incoming < 0) {
396                                         switch (errno) {
397                                         case EAGAIN:
398                                         case EINTR:
399                                         case ECONNABORTED:
400                                                 continue;
401                                         default:
402                                                 die("accept returned %s", strerror(errno));
403                                         }
404                                 }
405                                 handle(incoming, (struct sockaddr *)&ss, sslen);
406                         }
407                 }
408         }
409 }
410
411 int main(int argc, char **argv)
412 {
413         int port = DEFAULT_GIT_PORT;
414         int inetd_mode = 0;
415         int i;
416
417         for (i = 1; i < argc; i++) {
418                 char *arg = argv[i];
419
420                 if (!strncmp(arg, "--port=", 7)) {
421                         char *end;
422                         unsigned long n;
423                         n = strtoul(arg+7, &end, 0);
424                         if (arg[7] && !*end) {
425                                 port = n;
426                                 continue;
427                         }
428                 }
429
430                 if (!strcmp(arg, "--inetd")) {
431                         inetd_mode = 1;
432                         continue;
433                 }
434                 if (!strcmp(arg, "--verbose")) {
435                         verbose = 1;
436                         continue;
437                 }
438
439                 usage(daemon_usage);
440         }
441
442         if (inetd_mode) {
443                 fclose(stderr); //FIXME: workaround
444                 return execute();
445         }
446
447         return serve(port);
448 }