[PATCH] Make git-apply understand incomplete lines in non-C locales
[git/jnareb-git/bp-gitweb.git] / daemon.c
blobfb3f25c48665596f41ebcee66037bdd1be2dd30a
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>
10 static const char daemon_usage[] = "git-daemon [--inetd | --port=n]";
12 static int upload(char *dir, int dirlen)
14 if (chdir(dir) < 0)
15 return -1;
16 chdir(".git");
19 * Security on the cheap.
21 * We want a readable HEAD, usable "objects" directory, and
22 * a "git-daemon-export-ok" flag that says that the other side
23 * is ok with us doing this.
25 if (access("git-daemon-export-ok", F_OK) ||
26 access("objects/00", X_OK) ||
27 access("HEAD", R_OK))
28 return -1;
31 * We'll ignore SIGTERM from now on, we have a
32 * good client.
34 signal(SIGTERM, SIG_IGN);
36 /* git-upload-pack only ever reads stuff, so this is safe */
37 execlp("git-upload-pack", "git-upload-pack", ".", NULL);
38 return -1;
41 static int execute(void)
43 static char line[1000];
44 int len;
46 len = packet_read_line(0, line, sizeof(line));
48 if (len && line[len-1] == '\n')
49 line[--len] = 0;
51 if (!strncmp("git-upload-pack /", line, 17))
52 return upload(line + 16, len - 16);
54 fprintf(stderr, "got bad connection '%s'\n", line);
55 return -1;
60 * We count spawned/reaped separately, just to avoid any
61 * races when updating them from signals. The SIGCHLD handler
62 * will only update children_reaped, and the fork logic will
63 * only update children_spawned.
65 * MAX_CHILDREN should be a power-of-two to make the modulus
66 * operation cheap. It should also be at least twice
67 * the maximum number of connections we will ever allow.
69 #define MAX_CHILDREN 128
71 static int max_connections = 25;
73 /* These are updated by the signal handler */
74 static volatile unsigned int children_reaped = 0;
75 static pid_t dead_child[MAX_CHILDREN];
77 /* These are updated by the main loop */
78 static unsigned int children_spawned = 0;
79 static unsigned int children_deleted = 0;
81 static struct child {
82 pid_t pid;
83 socklen_t addrlen;
84 struct sockaddr_storage address;
85 } live_child[MAX_CHILDREN];
87 static void add_child(int idx, pid_t pid, struct sockaddr *addr, socklen_t addrlen)
89 live_child[idx].pid = pid;
90 live_child[idx].addrlen = addrlen;
91 memcpy(&live_child[idx].address, addr, addrlen);
95 * Walk from "deleted" to "spawned", and remove child "pid".
97 * We move everything up by one, since the new "deleted" will
98 * be one higher.
100 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
102 struct child n;
104 deleted %= MAX_CHILDREN;
105 spawned %= MAX_CHILDREN;
106 if (live_child[deleted].pid == pid) {
107 live_child[deleted].pid = -1;
108 return;
110 n = live_child[deleted];
111 for (;;) {
112 struct child m;
113 deleted = (deleted + 1) % MAX_CHILDREN;
114 if (deleted == spawned)
115 die("could not find dead child %d\n", pid);
116 m = live_child[deleted];
117 live_child[deleted] = n;
118 if (m.pid == pid)
119 return;
120 n = m;
125 * This gets called if the number of connections grows
126 * past "max_connections".
128 * We _should_ start off by searching for connections
129 * from the same IP, and if there is some address wth
130 * multiple connections, we should kill that first.
132 * As it is, we just "randomly" kill 25% of the connections,
133 * and our pseudo-random generator sucks too. I have no
134 * shame.
136 * Really, this is just a place-holder for a _real_ algorithm.
138 static void kill_some_children(int signo, unsigned start, unsigned stop)
140 start %= MAX_CHILDREN;
141 stop %= MAX_CHILDREN;
142 while (start != stop) {
143 if (!(start & 3))
144 kill(live_child[start].pid, signo);
145 start = (start + 1) % MAX_CHILDREN;
149 static void check_max_connections(void)
151 for (;;) {
152 int active;
153 unsigned spawned, reaped, deleted;
155 spawned = children_spawned;
156 reaped = children_reaped;
157 deleted = children_deleted;
159 while (deleted < reaped) {
160 pid_t pid = dead_child[deleted % MAX_CHILDREN];
161 remove_child(pid, deleted, spawned);
162 deleted++;
164 children_deleted = deleted;
166 active = spawned - deleted;
167 if (active <= max_connections)
168 break;
170 /* Kill some unstarted connections with SIGTERM */
171 kill_some_children(SIGTERM, deleted, spawned);
172 if (active <= max_connections << 1)
173 break;
175 /* If the SIGTERM thing isn't helping use SIGKILL */
176 kill_some_children(SIGKILL, deleted, spawned);
177 sleep(1);
181 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
183 pid_t pid = fork();
185 if (pid) {
186 unsigned idx;
188 close(incoming);
189 if (pid < 0)
190 return;
192 idx = children_spawned % MAX_CHILDREN;
193 children_spawned++;
194 add_child(idx, pid, addr, addrlen);
196 check_max_connections();
197 return;
200 dup2(incoming, 0);
201 dup2(incoming, 1);
202 close(incoming);
203 exit(execute());
206 static void child_handler(int signo)
208 for (;;) {
209 pid_t pid = waitpid(-1, NULL, WNOHANG);
211 if (pid > 0) {
212 unsigned reaped = children_reaped;
213 dead_child[reaped % MAX_CHILDREN] = pid;
214 children_reaped = reaped + 1;
215 continue;
217 break;
221 static int serve(int port)
223 struct addrinfo hints, *ai0, *ai;
224 int gai;
225 int socknum = 0, *socklist = NULL;
226 int maxfd = -1;
227 fd_set fds_init, fds;
228 char pbuf[NI_MAXSERV];
230 signal(SIGCHLD, child_handler);
232 sprintf(pbuf, "%d", port);
233 memset(&hints, 0, sizeof(hints));
234 hints.ai_family = AF_UNSPEC;
235 hints.ai_socktype = SOCK_STREAM;
236 hints.ai_protocol = IPPROTO_TCP;
237 hints.ai_flags = AI_PASSIVE;
239 gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
240 if (gai)
241 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
243 FD_ZERO(&fds_init);
245 for (ai = ai0; ai; ai = ai->ai_next) {
246 int sockfd;
247 int *newlist;
249 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
250 if (sockfd < 0)
251 continue;
252 if (sockfd >= FD_SETSIZE) {
253 error("too large socket descriptor.");
254 close(sockfd);
255 continue;
258 #ifdef IPV6_V6ONLY
259 if (ai->ai_family == AF_INET6) {
260 int on = 1;
261 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
262 &on, sizeof(on));
263 /* Note: error is not fatal */
265 #endif
267 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
268 close(sockfd);
269 continue; /* not fatal */
271 if (listen(sockfd, 5) < 0) {
272 close(sockfd);
273 continue; /* not fatal */
276 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
277 if (!newlist)
278 die("memory allocation failed: %s", strerror(errno));
280 socklist = newlist;
281 socklist[socknum++] = sockfd;
283 FD_SET(sockfd, &fds_init);
284 if (maxfd < sockfd)
285 maxfd = sockfd;
288 freeaddrinfo(ai0);
290 if (socknum == 0)
291 die("unable to allocate any listen sockets on port %u", port);
293 for (;;) {
294 int i;
295 fds = fds_init;
297 if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
298 if (errno != EINTR) {
299 error("select failed, resuming: %s",
300 strerror(errno));
301 sleep(1);
303 continue;
306 for (i = 0; i < socknum; i++) {
307 int sockfd = socklist[i];
309 if (FD_ISSET(sockfd, &fds)) {
310 struct sockaddr_storage ss;
311 socklen_t sslen = sizeof(ss);
312 int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
313 if (incoming < 0) {
314 switch (errno) {
315 case EAGAIN:
316 case EINTR:
317 case ECONNABORTED:
318 continue;
319 default:
320 die("accept returned %s", strerror(errno));
323 handle(incoming, (struct sockaddr *)&ss, sslen);
329 int main(int argc, char **argv)
331 int port = DEFAULT_GIT_PORT;
332 int inetd_mode = 0;
333 int i;
335 for (i = 1; i < argc; i++) {
336 char *arg = argv[i];
338 if (!strncmp(arg, "--port=", 7)) {
339 char *end;
340 unsigned long n;
341 n = strtoul(arg+7, &end, 0);
342 if (arg[7] && !*end) {
343 port = n;
344 continue;
348 if (!strcmp(arg, "--inetd")) {
349 inetd_mode = 1;
350 continue;
353 usage(daemon_usage);
356 if (inetd_mode)
357 return execute();
359 return serve(port);