5 #include <sys/socket.h>
8 #include <netinet/in.h>
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. */
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)
38 msglen = 0; /* Protect against weird return values. */
44 write(2, buf, buflen);
47 void logerror(const char *err, ...)
50 va_start(params, err);
51 logreport(err, params);
55 void lognotice(const char *err, ...)
60 va_start(params, err);
61 logreport(err, params);
66 static int upload(char *dir, int dirlen)
68 lognotice("Request for '%s'", dir);
70 logerror("Cannot chdir('%s'): %s", dir, strerror(errno));
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);
90 * We'll ignore SIGTERM from now on, we have a
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);
100 static int execute(void)
102 static char line[1000];
105 len = packet_read_line(0, line, sizeof(line));
107 if (len && line[len-1] == '\n')
110 if (!strncmp("git-upload-pack /", line, 17))
111 return upload(line + 16, len - 16);
113 logerror("Protocol error: '%s'", line);
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 {
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
159 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
163 deleted %= MAX_CHILDREN;
164 spawned %= MAX_CHILDREN;
165 if (live_child[deleted].pid == pid) {
166 live_child[deleted].pid = -1;
169 n = live_child[deleted];
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;
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
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) {
203 kill(live_child[start].pid, signo);
204 start = (start + 1) % MAX_CHILDREN;
208 static void check_max_connections(void)
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);
223 children_deleted = deleted;
225 active = spawned - deleted;
226 if (active <= max_connections)
229 /* Kill some unstarted connections with SIGTERM */
230 kill_some_children(SIGTERM, deleted, spawned);
231 if (active <= max_connections << 1)
234 /* If the SIGTERM thing isn't helping use SIGKILL */
235 kill_some_children(SIGKILL, deleted, spawned);
240 static void handle(int incoming, struct sockaddr *addr, int addrlen)
243 char addrbuf[256] = "";
253 idx = children_spawned % MAX_CHILDREN;
255 add_child(idx, pid, addr, addrlen);
257 check_max_connections();
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;
274 *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
275 inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
278 port = sin6_addr->sin6_port;
280 lognotice("Connection from %s:%d", addrbuf, port);
285 static void child_handler(int signo)
288 pid_t pid = waitpid(-1, NULL, WNOHANG);
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() */
296 fprintf(stderr, "[%d] Disconnected\n", pid);
303 static int serve(int port)
305 struct addrinfo hints, *ai0, *ai;
307 int socknum = 0, *socklist = NULL;
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);
323 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
327 for (ai = ai0; ai; ai = ai->ai_next) {
331 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
334 if (sockfd >= FD_SETSIZE) {
335 error("too large socket descriptor.");
341 if (ai->ai_family == AF_INET6) {
343 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
345 /* Note: error is not fatal */
349 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
351 continue; /* not fatal */
353 if (listen(sockfd, 5) < 0) {
355 continue; /* not fatal */
358 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
360 die("memory allocation failed: %s", strerror(errno));
363 socklist[socknum++] = sockfd;
365 FD_SET(sockfd, &fds_init);
373 die("unable to allocate any listen sockets on port %u", port);
379 if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
380 if (errno != EINTR) {
381 error("select failed, resuming: %s",
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);
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;
417 for (i = 1; i < argc; i++) {
420 if (!strncmp(arg, "--port=", 7)) {
423 n = strtoul(arg+7, &end, 0);
424 if (arg[7] && !*end) {
430 if (!strcmp(arg, "--inetd")) {
434 if (!strcmp(arg, "--verbose")) {
443 fclose(stderr); //FIXME: workaround