daemon.con commit [PATCH] Fixed/Extended example for update hook (c65a947)
   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 <netdb.h>
   7#include <netinet/in.h>
   8
   9static const char daemon_usage[] = "git-daemon [--inetd | --port=n]";
  10
  11static 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        /*
  30         * We'll ignore SIGTERM from now on, we have a
  31         * good client.
  32         */
  33        signal(SIGTERM, SIG_IGN);
  34
  35        /* git-upload-pack only ever reads stuff, so this is safe */
  36        execlp("git-upload-pack", "git-upload-pack", ".", NULL);
  37        return -1;
  38}
  39
  40static int execute(void)
  41{
  42        static char line[1000];
  43        int len;
  44
  45        len = packet_read_line(0, line, sizeof(line));
  46
  47        if (len && line[len-1] == '\n')
  48                line[--len] = 0;
  49
  50        if (!strncmp("git-upload-pack /", line, 17))
  51                return upload(line + 16, len - 16);
  52
  53        fprintf(stderr, "got bad connection '%s'\n", line);
  54        return -1;
  55}
  56
  57
  58/*
  59 * We count spawned/reaped separately, just to avoid any
  60 * races when updating them from signals. The SIGCHLD handler
  61 * will only update children_reaped, and the fork logic will
  62 * only update children_spawned.
  63 *
  64 * MAX_CHILDREN should be a power-of-two to make the modulus
  65 * operation cheap. It should also be at least twice
  66 * the maximum number of connections we will ever allow.
  67 */
  68#define MAX_CHILDREN 128
  69
  70static int max_connections = 25;
  71
  72/* These are updated by the signal handler */
  73static volatile unsigned int children_reaped = 0;
  74static pid_t dead_child[MAX_CHILDREN];
  75
  76/* These are updated by the main loop */
  77static unsigned int children_spawned = 0;
  78static unsigned int children_deleted = 0;
  79
  80static struct child {
  81        pid_t pid;
  82        socklen_t addrlen;
  83        struct sockaddr_storage address;
  84} live_child[MAX_CHILDREN];
  85
  86static void add_child(int idx, pid_t pid, struct sockaddr *addr, socklen_t addrlen)
  87{
  88        live_child[idx].pid = pid;
  89        live_child[idx].addrlen = addrlen;
  90        memcpy(&live_child[idx].address, addr, addrlen);
  91}
  92
  93/*
  94 * Walk from "deleted" to "spawned", and remove child "pid".
  95 *
  96 * We move everything up by one, since the new "deleted" will
  97 * be one higher.
  98 */
  99static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
 100{
 101        struct child n;
 102
 103        deleted %= MAX_CHILDREN;
 104        spawned %= MAX_CHILDREN;
 105        if (live_child[deleted].pid == pid) {
 106                live_child[deleted].pid = -1;
 107                return;
 108        }
 109        n = live_child[deleted];
 110        for (;;) {
 111                struct child m;
 112                deleted = (deleted + 1) % MAX_CHILDREN;
 113                if (deleted == spawned)
 114                        die("could not find dead child %d\n", pid);
 115                m = live_child[deleted];
 116                live_child[deleted] = n;
 117                if (m.pid == pid)
 118                        return;
 119                n = m;
 120        }
 121}
 122
 123/*
 124 * This gets called if the number of connections grows
 125 * past "max_connections".
 126 *
 127 * We _should_ start off by searching for connections
 128 * from the same IP, and if there is some address wth
 129 * multiple connections, we should kill that first.
 130 *
 131 * As it is, we just "randomly" kill 25% of the connections,
 132 * and our pseudo-random generator sucks too. I have no
 133 * shame.
 134 *
 135 * Really, this is just a place-holder for a _real_ algorithm.
 136 */
 137static void kill_some_children(int signo, unsigned start, unsigned stop)
 138{
 139        start %= MAX_CHILDREN;
 140        stop %= MAX_CHILDREN;
 141        while (start != stop) {
 142                if (!(start & 3))
 143                        kill(live_child[start].pid, signo);
 144                start = (start + 1) % MAX_CHILDREN;
 145        }
 146}
 147
 148static void check_max_connections(void)
 149{
 150        for (;;) {
 151                int active;
 152                unsigned spawned, reaped, deleted;
 153
 154                spawned = children_spawned;
 155                reaped = children_reaped;
 156                deleted = children_deleted;
 157
 158                while (deleted < reaped) {
 159                        pid_t pid = dead_child[deleted % MAX_CHILDREN];
 160                        remove_child(pid, deleted, spawned);
 161                        deleted++;
 162                }
 163                children_deleted = deleted;
 164
 165                active = spawned - deleted;
 166                if (active <= max_connections)
 167                        break;
 168
 169                /* Kill some unstarted connections with SIGTERM */
 170                kill_some_children(SIGTERM, deleted, spawned);
 171                if (active <= max_connections << 1)
 172                        break;
 173
 174                /* If the SIGTERM thing isn't helping use SIGKILL */
 175                kill_some_children(SIGKILL, deleted, spawned);
 176                sleep(1);
 177        }
 178}
 179
 180static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 181{
 182        pid_t pid = fork();
 183
 184        if (pid) {
 185                unsigned idx;
 186
 187                close(incoming);
 188                if (pid < 0)
 189                        return;
 190
 191                idx = children_spawned % MAX_CHILDREN;
 192                children_spawned++;
 193                add_child(idx, pid, addr, addrlen);
 194
 195                check_max_connections();
 196                return;
 197        }
 198
 199        dup2(incoming, 0);
 200        dup2(incoming, 1);
 201        close(incoming);
 202        exit(execute());
 203}
 204
 205static void child_handler(int signo)
 206{
 207        for (;;) {
 208                pid_t pid = waitpid(-1, NULL, WNOHANG);
 209
 210                if (pid > 0) {
 211                        unsigned reaped = children_reaped;
 212                        dead_child[reaped % MAX_CHILDREN] = pid;
 213                        children_reaped = reaped + 1;
 214                        continue;
 215                }
 216                break;
 217        }
 218}
 219
 220static int serve(int port)
 221{
 222        struct addrinfo hints, *ai0, *ai;
 223        int gai;
 224        int socknum = 0, *socklist = NULL;
 225        int maxfd = -1;
 226        fd_set fds_init, fds;
 227        char pbuf[NI_MAXSERV];
 228
 229        signal(SIGCHLD, child_handler);
 230
 231        sprintf(pbuf, "%d", port);
 232        memset(&hints, 0, sizeof(hints));
 233        hints.ai_family = AF_UNSPEC;
 234        hints.ai_socktype = SOCK_STREAM;
 235        hints.ai_protocol = IPPROTO_TCP;
 236        hints.ai_flags = AI_PASSIVE;
 237
 238        gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
 239        if (gai)
 240                die("getaddrinfo() failed: %s\n", gai_strerror(gai));
 241
 242        FD_ZERO(&fds_init);
 243
 244        for (ai = ai0; ai; ai = ai->ai_next) {
 245                int sockfd;
 246                int *newlist;
 247
 248                sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 249                if (sockfd < 0)
 250                        continue;
 251                if (sockfd >= FD_SETSIZE) {
 252                        error("too large socket descriptor.");
 253                        close(sockfd);
 254                        continue;
 255                }
 256
 257#ifdef IPV6_V6ONLY
 258                if (ai->ai_family == AF_INET6) {
 259                        int on = 1;
 260                        setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
 261                                   &on, sizeof(on));
 262                        /* Note: error is not fatal */
 263                }
 264#endif
 265
 266                if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
 267                        close(sockfd);
 268                        continue;       /* not fatal */
 269                }
 270                if (listen(sockfd, 5) < 0) {
 271                        close(sockfd);
 272                        continue;       /* not fatal */
 273                }
 274
 275                newlist = realloc(socklist, sizeof(int) * (socknum + 1));
 276                if (!newlist)
 277                        die("memory allocation failed: %s", strerror(errno));
 278
 279                socklist = newlist;
 280                socklist[socknum++] = sockfd;
 281
 282                FD_SET(sockfd, &fds_init);
 283                if (maxfd < sockfd)
 284                        maxfd = sockfd;
 285        }
 286
 287        freeaddrinfo(ai0);
 288
 289        if (socknum == 0)
 290                die("unable to allocate any listen sockets on port %u", port);
 291
 292        for (;;) {
 293                int i;
 294                fds = fds_init;
 295                
 296                if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
 297                        if (errno != EINTR) {
 298                                error("select failed, resuming: %s",
 299                                      strerror(errno));
 300                                sleep(1);
 301                        }
 302                        continue;
 303                }
 304
 305                for (i = 0; i < socknum; i++) {
 306                        int sockfd = socklist[i];
 307
 308                        if (FD_ISSET(sockfd, &fds)) {
 309                                struct sockaddr_storage ss;
 310                                socklen_t sslen = sizeof(ss);
 311                                int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
 312                                if (incoming < 0) {
 313                                        switch (errno) {
 314                                        case EAGAIN:
 315                                        case EINTR:
 316                                        case ECONNABORTED:
 317                                                continue;
 318                                        default:
 319                                                die("accept returned %s", strerror(errno));
 320                                        }
 321                                }
 322                                handle(incoming, (struct sockaddr *)&ss, sslen);
 323                        }
 324                }
 325        }
 326}
 327
 328int main(int argc, char **argv)
 329{
 330        int port = DEFAULT_GIT_PORT;
 331        int inetd_mode = 0;
 332        int i;
 333
 334        for (i = 1; i < argc; i++) {
 335                char *arg = argv[i];
 336
 337                if (!strncmp(arg, "--port=", 7)) {
 338                        char *end;
 339                        unsigned long n;
 340                        n = strtoul(arg+7, &end, 0);
 341                        if (arg[7] && !*end) {
 342                                port = n;
 343                                continue;
 344                        }
 345                }
 346
 347                if (!strcmp(arg, "--inetd")) {
 348                        inetd_mode = 1;
 349                        continue;
 350                }
 351
 352                usage(daemon_usage);
 353        }
 354
 355        if (inetd_mode)
 356                return execute();
 357
 358        return serve(port);
 359}