[PATCH] Documentation: update recommended workflow when working with others.
[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 <netinet/in.h>
7 #include <arpa/inet.h>
8
9 static const char daemon_usage[] = "git-daemon [--inetd | --port=n]";
10
11 static int upload(char *dir, int dirlen)
12 {
13         if (chdir(dir) < 0)
14                 return -1;
15         chdir(".git");
16
17         /*
18          * Security on the cheap.
19          *
20          * We want a readable HEAD, usable "objects" directory, and 
21          * a "git-daemon-export-ok" flag that says that the other side
22          * is ok with us doing this.
23          */
24         if (access("git-daemon-export-ok", F_OK) ||
25             access("objects/00", X_OK) ||
26             access("HEAD", R_OK))
27                 return -1;
28
29         /* git-upload-pack only ever reads stuff, so this is safe */
30         execlp("git-upload-pack", "git-upload-pack", ".", NULL);
31         return -1;
32 }
33
34 static int execute(void)
35 {
36         static char line[1000];
37         int len;
38
39         len = packet_read_line(0, line, sizeof(line));
40
41         if (len && line[len-1] == '\n')
42                 line[--len] = 0;
43
44         if (!strncmp("git-upload-pack /", line, 17))
45                 return upload(line + 16, len - 16);
46
47         fprintf(stderr, "got bad connection '%s'\n", line);
48         return -1;
49 }
50
51
52 /*
53  * We count spawned/reaped separately, just to avoid any
54  * races when updating them from signals. The SIGCHLD handler
55  * will only update children_reaped, and the fork logic will
56  * only update children_spawned.
57  *
58  * MAX_CHILDREN should be a power-of-two to make the modulus
59  * operation cheap. It should also be at least twice
60  * the maximum number of connections we will ever allow.
61  */
62 #define MAX_CHILDREN 128
63
64 static int max_connections = 25;
65
66 /* These are updated by the signal handler */
67 static volatile unsigned int children_reaped = 0;
68 pid_t dead_child[MAX_CHILDREN];
69
70 /* These are updated by the main loop */
71 static unsigned int children_spawned = 0;
72 static unsigned int children_deleted = 0;
73
74 struct child {
75         pid_t pid;
76         int addrlen;
77         struct sockaddr_in address;
78 } live_child[MAX_CHILDREN];
79
80 static void add_child(int idx, pid_t pid, struct sockaddr_in *addr, int addrlen)
81 {
82         live_child[idx].pid = pid;
83         live_child[idx].addrlen = addrlen;
84         live_child[idx].address = *addr;
85 }
86
87 /*
88  * Walk from "deleted" to "spawned", and remove child "pid".
89  *
90  * We move everything up by one, since the new "deleted" will
91  * be one higher.
92  */
93 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
94 {
95         struct child n;
96
97         deleted %= MAX_CHILDREN;
98         spawned %= MAX_CHILDREN;
99         if (live_child[deleted].pid == pid) {
100                 live_child[deleted].pid = -1;
101                 return;
102         }
103         n = live_child[deleted];
104         for (;;) {
105                 struct child m;
106                 deleted = (deleted + 1) % MAX_CHILDREN;
107                 if (deleted == spawned)
108                         die("could not find dead child %d\n", pid);
109                 m = live_child[deleted];
110                 live_child[deleted] = n;
111                 if (m.pid == pid)
112                         return;
113                 n = m;
114         }
115 }
116
117 /*
118  * This gets called if the number of connections grows
119  * past "max_connections".
120  *
121  * We _should_ start off by searching for connections
122  * from the same IP, and if there is some address wth
123  * multiple connections, we should kill that first.
124  *
125  * As it is, we just "randomly" kill 25% of the connections,
126  * and our pseudo-random generator sucks too. I have no
127  * shame.
128  *
129  * Really, this is just a place-holder for a _real_ algorithm.
130  */
131 static void kill_some_children(int connections, unsigned start, unsigned stop)
132 {
133         start %= MAX_CHILDREN;
134         stop %= MAX_CHILDREN;
135         while (start != stop) {
136                 if (!(start & 3))
137                         kill(live_child[start].pid, SIGTERM);
138                 start = (start + 1) % MAX_CHILDREN;
139         }
140 }
141
142 static void handle(int incoming, struct sockaddr_in *addr, int addrlen)
143 {
144         pid_t pid = fork();
145
146         if (pid) {
147                 int active;
148                 unsigned spawned, reaped, deleted;
149
150                 close(incoming);
151                 if (pid < 0)
152                         return;
153
154                 spawned = children_spawned;
155                 add_child(spawned % MAX_CHILDREN, pid, addr, addrlen);
156                 children_spawned = ++spawned;
157
158                 reaped = children_reaped;
159                 deleted = children_deleted;
160
161                 while (deleted < reaped) {
162                         pid_t pid = dead_child[deleted % MAX_CHILDREN];
163                         remove_child(pid, deleted, spawned);
164                         deleted++;
165                 }
166                 children_deleted = deleted;
167
168                 active = spawned - deleted;
169                 if (active > max_connections) {
170                         kill_some_children(active, deleted, spawned);
171
172                         /* Wait to make sure they're gone */
173                         while (spawned - children_reaped > max_connections)
174                                 sleep(1);
175                 }
176                         
177
178                 return;
179         }
180
181         dup2(incoming, 0);
182         dup2(incoming, 1);
183         close(incoming);
184         exit(execute());
185 }
186
187 static void child_handler(int signo)
188 {
189         for (;;) {
190                 pid_t pid = waitpid(-1, NULL, WNOHANG);
191
192                 if (pid > 0) {
193                         unsigned reaped = children_reaped;
194                         dead_child[reaped % MAX_CHILDREN] = pid;
195                         children_reaped = reaped + 1;
196                         continue;
197                 }
198                 break;
199         }
200 }
201
202 static int serve(int port)
203 {
204         int sockfd;
205         struct sockaddr_in addr;
206
207         signal(SIGCHLD, child_handler);
208         sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
209         if (sockfd < 0)
210                 die("unable to open socket (%s)", strerror(errno));
211         memset(&addr, 0, sizeof(addr));
212         addr.sin_port = htons(port);
213         addr.sin_family = AF_INET;
214         if (bind(sockfd, (void *)&addr, sizeof(addr)) < 0)
215                 die("unable to bind to port %d (%s)", port, strerror(errno));
216         if (listen(sockfd, 5) < 0)
217                 die("unable to listen to port %d (%s)", port, strerror(errno));
218
219         for (;;) {
220                 struct sockaddr_in in;
221                 socklen_t addrlen = sizeof(in);
222                 int incoming = accept(sockfd, (void *)&in, &addrlen);
223
224                 if (incoming < 0) {
225                         switch (errno) {
226                         case EAGAIN:
227                         case EINTR:
228                         case ECONNABORTED:
229                                 continue;
230                         default:
231                                 die("accept returned %s", strerror(errno));
232                         }
233                 }
234                 handle(incoming, &in, addrlen);
235         }
236 }
237
238 int main(int argc, char **argv)
239 {
240         int port = DEFAULT_GIT_PORT;
241         int inetd_mode = 0;
242         int i;
243
244         for (i = 1; i < argc; i++) {
245                 char *arg = argv[i];
246
247                 if (!strncmp(arg, "--port=", 7)) {
248                         char *end;
249                         unsigned long n;
250                         n = strtoul(arg+7, &end, 0);
251                         if (arg[7] && !*end) {
252                                 port = n;
253                                 continue;
254                         }
255                 }
256
257                 if (!strcmp(arg, "--inetd")) {
258                         inetd_mode = 1;
259                         continue;
260                 }
261
262                 usage(daemon_usage);
263         }
264
265         if (inetd_mode)
266                 return execute();
267
268         return serve(port);
269 }