[PATCH] Update git-daemon documentation wrt. the --verbose parameter
[git/gitweb.git] / daemon.c
blobb1fd60dd0c6ea5915340675a9f9691b027ca87e5
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>
11 static int verbose;
13 static const char daemon_usage[] = "git-daemon [--verbose] [--inetd | --port=n]";
16 static void logreport(const char *err, va_list params)
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;
24 /* sizeof(buf) should be big enough for "[pid] \n" */
25 buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid());
27 maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
28 msglen = vsnprintf(buf + buflen, maxlen, err, params);
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.
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;
41 buf[buflen++] = '\n';
42 buf[buflen] = '\0';
44 write(2, buf, buflen);
47 void logerror(const char *err, ...)
49 va_list params;
50 va_start(params, err);
51 logreport(err, params);
52 va_end(params);
55 void lognotice(const char *err, ...)
57 va_list params;
58 if (!verbose)
59 return;
60 va_start(params, err);
61 logreport(err, params);
62 va_end(params);
66 static int upload(char *dir, int dirlen)
68 lognotice("Request for '%s'", dir);
69 if (chdir(dir) < 0) {
70 logerror("Cannot chdir('%s'): %s", dir, strerror(errno));
71 return -1;
73 chdir(".git");
76 * Security on the cheap.
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.
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;
90 * We'll ignore SIGTERM from now on, we have a
91 * good client.
93 signal(SIGTERM, SIG_IGN);
95 /* git-upload-pack only ever reads stuff, so this is safe */
96 execlp("git-upload-pack", "git-upload-pack", ".", NULL);
97 return -1;
100 static int execute(void)
102 static char line[1000];
103 int len;
105 len = packet_read_line(0, line, sizeof(line));
107 if (len && line[len-1] == '\n')
108 line[--len] = 0;
110 if (!strncmp("git-upload-pack /", line, 17))
111 return upload(line + 16, len - 16);
113 logerror("Protocol error: '%s'", line);
114 return -1;
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.
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.
128 #define MAX_CHILDREN 128
130 static int max_connections = 25;
132 /* These are updated by the signal handler */
133 static volatile unsigned int children_reaped = 0;
134 static pid_t dead_child[MAX_CHILDREN];
136 /* These are updated by the main loop */
137 static unsigned int children_spawned = 0;
138 static unsigned int children_deleted = 0;
140 static struct child {
141 pid_t pid;
142 int addrlen;
143 struct sockaddr_storage address;
144 } live_child[MAX_CHILDREN];
146 static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
148 live_child[idx].pid = pid;
149 live_child[idx].addrlen = addrlen;
150 memcpy(&live_child[idx].address, addr, addrlen);
154 * Walk from "deleted" to "spawned", and remove child "pid".
156 * We move everything up by one, since the new "deleted" will
157 * be one higher.
159 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
161 struct child n;
163 deleted %= MAX_CHILDREN;
164 spawned %= MAX_CHILDREN;
165 if (live_child[deleted].pid == pid) {
166 live_child[deleted].pid = -1;
167 return;
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;
184 * This gets called if the number of connections grows
185 * past "max_connections".
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.
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.
195 * Really, this is just a place-holder for a _real_ algorithm.
197 static void kill_some_children(int signo, unsigned start, unsigned stop)
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;
208 static void check_max_connections(void)
210 for (;;) {
211 int active;
212 unsigned spawned, reaped, deleted;
214 spawned = children_spawned;
215 reaped = children_reaped;
216 deleted = children_deleted;
218 while (deleted < reaped) {
219 pid_t pid = dead_child[deleted % MAX_CHILDREN];
220 remove_child(pid, deleted, spawned);
221 deleted++;
223 children_deleted = deleted;
225 active = spawned - deleted;
226 if (active <= max_connections)
227 break;
229 /* Kill some unstarted connections with SIGTERM */
230 kill_some_children(SIGTERM, deleted, spawned);
231 if (active <= max_connections << 1)
232 break;
234 /* If the SIGTERM thing isn't helping use SIGKILL */
235 kill_some_children(SIGKILL, deleted, spawned);
236 sleep(1);
240 static void handle(int incoming, struct sockaddr *addr, int addrlen)
242 pid_t pid = fork();
243 char addrbuf[256] = "";
244 int port = -1;
246 if (pid) {
247 unsigned idx;
249 close(incoming);
250 if (pid < 0)
251 return;
253 idx = children_spawned % MAX_CHILDREN;
254 children_spawned++;
255 add_child(idx, pid, addr, addrlen);
257 check_max_connections();
258 return;
261 dup2(incoming, 0);
262 dup2(incoming, 1);
263 close(incoming);
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;
270 } else if (addr->sa_family == AF_INET6) {
271 struct sockaddr_in6 *sin6_addr = (void *) addr;
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, "]");
278 port = sin6_addr->sin6_port;
280 lognotice("Connection from %s:%d", addrbuf, port);
282 exit(execute());
285 static void child_handler(int signo)
287 for (;;) {
288 pid_t pid = waitpid(-1, NULL, WNOHANG);
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;
299 break;
303 static int serve(int port)
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];
312 signal(SIGCHLD, child_handler);
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;
321 gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
322 if (gai)
323 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
325 FD_ZERO(&fds_init);
327 for (ai = ai0; ai; ai = ai->ai_next) {
328 int sockfd;
329 int *newlist;
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;
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 */
347 #endif
349 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
350 close(sockfd);
351 continue; /* not fatal */
353 if (listen(sockfd, 5) < 0) {
354 close(sockfd);
355 continue; /* not fatal */
358 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
359 if (!newlist)
360 die("memory allocation failed: %s", strerror(errno));
362 socklist = newlist;
363 socklist[socknum++] = sockfd;
365 FD_SET(sockfd, &fds_init);
366 if (maxfd < sockfd)
367 maxfd = sockfd;
370 freeaddrinfo(ai0);
372 if (socknum == 0)
373 die("unable to allocate any listen sockets on port %u", port);
375 for (;;) {
376 int i;
377 fds = fds_init;
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);
385 continue;
388 for (i = 0; i < socknum; i++) {
389 int sockfd = socklist[i];
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));
405 handle(incoming, (struct sockaddr *)&ss, sslen);
411 int main(int argc, char **argv)
413 int port = DEFAULT_GIT_PORT;
414 int inetd_mode = 0;
415 int i;
417 for (i = 1; i < argc; i++) {
418 char *arg = argv[i];
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;
430 if (!strcmp(arg, "--inetd")) {
431 inetd_mode = 1;
432 continue;
434 if (!strcmp(arg, "--verbose")) {
435 verbose = 1;
436 continue;
439 usage(daemon_usage);
442 if (inetd_mode) {
443 fclose(stderr); //FIXME: workaround
444 return execute();
447 return serve(port);