5 #include <sys/socket.h>
6 #include <netinet/in.h>
9 static const char daemon_usage
[] = "git-daemon [--inetd | --port=n]";
11 static int upload(char *dir
, int dirlen
)
18 * Security on the cheap.
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.
24 if (access("git-daemon-export-ok", F_OK
) ||
25 access("objects/00", X_OK
) ||
29 /* git-upload-pack only ever reads stuff, so this is safe */
30 execlp("git-upload-pack", "git-upload-pack", ".", NULL
);
34 static int execute(void)
36 static char line
[1000];
39 len
= packet_read_line(0, line
, sizeof(line
));
41 if (len
&& line
[len
-1] == '\n')
44 if (!strncmp("git-upload-pack /", line
, 17))
45 return upload(line
+ 16, len
- 16);
47 fprintf(stderr
, "got bad connection '%s'\n", line
);
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.
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.
62 #define MAX_CHILDREN 128
64 static int max_connections
= 25;
66 /* These are updated by the signal handler */
67 static volatile unsigned int children_reaped
= 0;
68 pid_t dead_child
[MAX_CHILDREN
];
70 /* These are updated by the main loop */
71 static unsigned int children_spawned
= 0;
72 static unsigned int children_deleted
= 0;
77 struct sockaddr_in address
;
78 } live_child
[MAX_CHILDREN
];
80 static void add_child(int idx
, pid_t pid
, struct sockaddr_in
*addr
, int addrlen
)
82 live_child
[idx
].pid
= pid
;
83 live_child
[idx
].addrlen
= addrlen
;
84 live_child
[idx
].address
= *addr
;
88 * Walk from "deleted" to "spawned", and remove child "pid".
90 * We move everything up by one, since the new "deleted" will
93 static void remove_child(pid_t pid
, unsigned deleted
, unsigned spawned
)
97 deleted
%= MAX_CHILDREN
;
98 spawned
%= MAX_CHILDREN
;
99 if (live_child
[deleted
].pid
== pid
) {
100 live_child
[deleted
].pid
= -1;
103 n
= live_child
[deleted
];
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
;
118 * This gets called if the number of connections grows
119 * past "max_connections".
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.
125 * As it is, we just "randomly" kill 25% of the connections,
126 * and our pseudo-random generator sucks too. I have no
129 * Really, this is just a place-holder for a _real_ algorithm.
131 static void kill_some_children(int connections
, unsigned start
, unsigned stop
)
133 start
%= MAX_CHILDREN
;
134 stop
%= MAX_CHILDREN
;
135 while (start
!= stop
) {
137 kill(live_child
[start
].pid
, SIGTERM
);
138 start
= (start
+ 1) % MAX_CHILDREN
;
142 static void handle(int incoming
, struct sockaddr_in
*addr
, int addrlen
)
148 unsigned spawned
, reaped
, deleted
;
154 spawned
= children_spawned
;
155 add_child(spawned
% MAX_CHILDREN
, pid
, addr
, addrlen
);
156 children_spawned
= ++spawned
;
158 reaped
= children_reaped
;
159 deleted
= children_deleted
;
161 while (deleted
< reaped
) {
162 pid_t pid
= dead_child
[deleted
% MAX_CHILDREN
];
163 remove_child(pid
, deleted
, spawned
);
166 children_deleted
= deleted
;
168 active
= spawned
- deleted
;
169 if (active
> max_connections
) {
170 kill_some_children(active
, deleted
, spawned
);
172 /* Wait to make sure they're gone */
173 while (spawned
- children_reaped
> max_connections
)
187 static void child_handler(int signo
)
190 pid_t pid
= waitpid(-1, NULL
, WNOHANG
);
193 unsigned reaped
= children_reaped
;
194 dead_child
[reaped
% MAX_CHILDREN
] = pid
;
195 children_reaped
= reaped
+ 1;
202 static int serve(int port
)
205 struct sockaddr_in addr
;
207 signal(SIGCHLD
, child_handler
);
208 sockfd
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_IP
);
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
));
220 struct sockaddr_in in
;
221 socklen_t addrlen
= sizeof(in
);
222 int incoming
= accept(sockfd
, (void *)&in
, &addrlen
);
231 die("accept returned %s", strerror(errno
));
234 handle(incoming
, &in
, addrlen
);
238 int main(int argc
, char **argv
)
240 int port
= DEFAULT_GIT_PORT
;
244 for (i
= 1; i
< argc
; i
++) {
247 if (!strncmp(arg
, "--port=", 7)) {
250 n
= strtoul(arg
+7, &end
, 0);
251 if (arg
[7] && !*end
) {
257 if (!strcmp(arg
, "--inetd")) {