PageRenderTime 7ms CodeModel.GetById 22ms app.highlight 88ms RepoModel.GetById 19ms app.codeStats 1ms

/io.c

https://github.com/stirnim/polipo
C | 1143 lines | 988 code | 118 blank | 37 comment | 303 complexity | 185399c741953cc35522f58879caafb3 MD5 | raw file
   1/*
   2Copyright (c) 2003-2006 by Juliusz Chroboczek
   3
   4Permission is hereby granted, free of charge, to any person obtaining a copy
   5of this software and associated documentation files (the "Software"), to deal
   6in the Software without restriction, including without limitation the rights
   7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8copies of the Software, and to permit persons to whom the Software is
   9furnished to do so, subject to the following conditions:
  10
  11The above copyright notice and this permission notice shall be included in
  12all copies or substantial portions of the Software.
  13
  14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20THE SOFTWARE.
  21*/
  22
  23#include "polipo.h"
  24
  25#ifdef HAVE_IPv6
  26#ifdef IPV6_PREFER_TEMPADDR
  27#define HAVE_IPV6_PREFER_TEMPADDR 1
  28#endif
  29#endif
  30
  31#ifdef HAVE_IPV6_PREFER_TEMPADDR
  32int useTemporarySourceAddress = 1;
  33#endif
  34
  35void
  36preinitIo()
  37{
  38#ifdef HAVE_IPV6_PREFER_TEMPADDR
  39    CONFIG_VARIABLE_SETTABLE(useTemporarySourceAddress, CONFIG_TRISTATE,
  40                             configIntSetter,
  41                             "Prefer IPv6 temporary source address.");
  42#endif
  43
  44#ifdef HAVE_WINSOCK
  45    /* Load the winsock dll */
  46    WSADATA wsaData;
  47    WORD wVersionRequested = MAKEWORD(2, 2);
  48    int err = WSAStartup( wVersionRequested, &wsaData );
  49    if (err != 0) {
  50        do_log_error(L_ERROR, err, "Couldn't load winsock dll");
  51        exit(-1);
  52    }
  53#endif
  54    return;
  55}
  56
  57void
  58initIo()
  59{
  60    return;
  61}
  62
  63FdEventHandlerPtr
  64do_stream(int operation, int fd, int offset, char *buf, int len,
  65          int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
  66          void *data)
  67{
  68    assert(len > offset || (operation & (IO_END | IO_IMMEDIATE)));
  69    return schedule_stream(operation, fd, offset, 
  70                           NULL, 0, buf, len, NULL, 0, NULL, 0, NULL,
  71                           handler, data);
  72}
  73
  74FdEventHandlerPtr
  75do_stream_2(int operation, int fd, int offset, 
  76            char *buf, int len, char *buf2, int len2,
  77            int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
  78            void *data)
  79{
  80    assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
  81    return schedule_stream(operation, fd, offset,
  82                           NULL, 0, buf, len, buf2, len2, NULL, 0, NULL,
  83                           handler, data);
  84}
  85
  86FdEventHandlerPtr
  87do_stream_3(int operation, int fd, int offset, 
  88            char *buf, int len, char *buf2, int len2, char *buf3, int len3,
  89            int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
  90            void *data)
  91{
  92    assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
  93    return schedule_stream(operation, fd, offset,
  94                           NULL, 0, buf, len, buf2, len2, buf3, len3, NULL,
  95                           handler, data);
  96}
  97
  98FdEventHandlerPtr
  99do_stream_h(int operation, int fd, int offset,
 100            char *header, int hlen, char *buf, int len,
 101            int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
 102            void *data)
 103{
 104    assert(hlen + len > offset || (operation & (IO_END | IO_IMMEDIATE)));
 105    return schedule_stream(operation, fd, offset, 
 106                           header, hlen, buf, len, NULL, 0, NULL, 0, NULL,
 107                           handler, data);
 108}
 109
 110FdEventHandlerPtr
 111do_stream_buf(int operation, int fd, int offset, char **buf_location, int len,
 112              int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
 113              void *data)
 114{
 115    assert((len > offset || (operation & (IO_END | IO_IMMEDIATE)))
 116           && len <= CHUNK_SIZE);
 117    return schedule_stream(operation, fd, offset,
 118                           NULL, 0, *buf_location, len, 
 119                           NULL, 0, NULL, 0, buf_location,
 120                           handler, data);
 121}
 122
 123static int
 124chunkHeaderLen(int i)
 125{
 126    if(i <= 0)
 127        return 0;
 128    if(i < 0x10)
 129        return 3;
 130    else if(i < 0x100)
 131        return 4;
 132    else if(i < 0x1000)
 133        return 5;
 134    else if(i < 0x10000)
 135        return 6;
 136    else
 137        abort();
 138}
 139
 140static int
 141chunkHeader(char *buf, int buflen, int i)
 142{
 143    int n;
 144    if(i <= 0)
 145        return 0;
 146    n = snprintf(buf, buflen, "%x\r\n", i);
 147    return n;
 148}
 149
 150
 151FdEventHandlerPtr
 152schedule_stream(int operation, int fd, int offset,
 153                char *header, int hlen,
 154                char *buf, int len, char *buf2, int len2, char *buf3, int len3,
 155                char **buf_location,
 156                int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
 157                void *data)
 158{
 159    StreamRequestRec request;
 160    FdEventHandlerPtr event;
 161    int done;
 162
 163    request.operation = operation;
 164    request.fd = fd;
 165    if(len3) {
 166        assert(hlen == 0 && buf_location == NULL);
 167        request.u.b.len3 = len3;
 168        request.u.b.buf3 = buf3;
 169        request.operation |= IO_BUF3;
 170    } else if(buf_location) {
 171        assert(hlen == 0);
 172        request.u.l.buf_location = buf_location;
 173        request.operation |= IO_BUF_LOCATION;
 174    } else {
 175        request.u.h.hlen = hlen;
 176        request.u.h.header = header;
 177    }
 178    request.buf = buf;
 179    request.len = len;
 180    request.buf2 = buf2;
 181    request.len2 = len2;
 182    if((operation & IO_CHUNKED) || 
 183       (!(request.operation & (IO_BUF3 | IO_BUF_LOCATION)) && hlen > 0)) {
 184        assert(offset == 0);
 185        request.offset = -hlen;
 186        if(operation & IO_CHUNKED)
 187            request.offset += -chunkHeaderLen(len + len2);
 188    } else {
 189        request.offset = offset;
 190    }
 191    request.handler = handler;
 192    request.data = data;
 193    event = makeFdEvent(fd, 
 194                        (operation & IO_MASK) == IO_WRITE ?
 195                        POLLOUT : POLLIN, 
 196                        do_scheduled_stream, 
 197                        sizeof(StreamRequestRec), &request);
 198    if(!event) {
 199        done = (*handler)(-ENOMEM, NULL, &request);
 200        assert(done);
 201        return NULL;
 202    }
 203
 204    if(!(operation & IO_NOTNOW)) {
 205        done = event->handler(0, event);
 206        if(done) {
 207            free(event);
 208            return NULL;
 209        }
 210    } 
 211
 212    if(operation & IO_IMMEDIATE) {
 213        assert(hlen == 0 && !(operation & IO_CHUNKED));
 214        done = (*handler)(0, event, &request);
 215        if(done) {
 216            free(event);
 217            return NULL;
 218        }
 219    }
 220    event = registerFdEventHelper(event);
 221    return event;
 222}
 223
 224static const char *endChunkTrailer = "\r\n0\r\n\r\n";
 225
 226int
 227do_scheduled_stream(int status, FdEventHandlerPtr event)
 228{
 229    StreamRequestPtr request = (StreamRequestPtr)&event->data;
 230    int rc, done, i;
 231    struct iovec iov[6];
 232    int chunk_header_len;
 233    char chunk_header[10];
 234    int len12 = request->len + request->len2;
 235    int len123 = 
 236        request->len + request->len2 + 
 237        ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
 238
 239    if(status) {
 240        done = request->handler(status, event, request);
 241        return done;
 242    }
 243
 244    i = 0;
 245
 246    if(request->offset < 0) {
 247        assert((request->operation & (IO_MASK | IO_BUF3 | IO_BUF_LOCATION)) == 
 248               IO_WRITE);
 249        if(request->operation & IO_CHUNKED) {
 250            chunk_header_len = chunkHeaderLen(len123);
 251        } else {
 252            chunk_header_len = 0;
 253        }
 254
 255        if(request->offset < -chunk_header_len) {
 256            assert(request->offset >= -(request->u.h.hlen + chunk_header_len));
 257            iov[i].iov_base = request->u.h.header;
 258            iov[i].iov_len = -request->offset - chunk_header_len;
 259            i++;
 260        }
 261
 262        if(chunk_header_len > 0) {
 263            chunkHeader(chunk_header, 10, len123);
 264            if(request->offset < -chunk_header_len) {
 265                iov[i].iov_base = chunk_header;
 266                iov[i].iov_len = chunk_header_len;
 267            } else {
 268                iov[i].iov_base = chunk_header + 
 269                    chunk_header_len + request->offset;
 270                iov[i].iov_len = -request->offset;
 271            }
 272            i++;
 273        }
 274    }
 275
 276    if(request->len > 0) {
 277        if(request->buf == NULL && 
 278           (request->operation & IO_BUF_LOCATION)) {
 279            assert(*request->u.l.buf_location == NULL);
 280            request->buf = *request->u.l.buf_location = get_chunk();
 281            if(request->buf == NULL) {
 282                done = request->handler(-ENOMEM, event, request);
 283                return done;
 284            }
 285        }
 286        if(request->offset <= 0) {
 287            iov[i].iov_base = request->buf;
 288            iov[i].iov_len = request->len;
 289            i++;
 290        } else if(request->offset < request->len) {
 291            iov[i].iov_base = request->buf + request->offset;
 292            iov[i].iov_len = request->len - request->offset;
 293            i++;
 294        }
 295    }
 296
 297    if(request->len2 > 0) {
 298        if(request->offset <= request->len) {
 299            iov[i].iov_base = request->buf2;
 300            iov[i].iov_len = request->len2;
 301            i++;
 302        } else if(request->offset < request->len + request->len2) {
 303            iov[i].iov_base = request->buf2 + request->offset - request->len;
 304            iov[i].iov_len = request->len2 - request->offset + request->len;
 305            i++;
 306        }
 307    }
 308
 309    if((request->operation & IO_BUF3) && request->u.b.len3 > 0) {
 310        if(request->offset <= len12) {
 311            iov[i].iov_base = request->u.b.buf3;
 312            iov[i].iov_len = request->u.b.len3;
 313            i++;
 314        } else if(request->offset < len12 + request->u.b.len3) {
 315            iov[i].iov_base = request->u.b.buf3 + request->offset - len12;
 316            iov[i].iov_len = request->u.b.len3 - request->offset + len12;
 317            i++;
 318        }
 319    }
 320
 321    if((request->operation & IO_CHUNKED)) {
 322        int l;
 323        const char *trailer;
 324        if(request->operation & IO_END) {
 325            if(len123 == 0) {
 326                trailer = endChunkTrailer + 2;
 327                l = 5;
 328            } else {
 329                trailer = endChunkTrailer;
 330                l = 7;
 331            }
 332        } else {
 333            trailer = endChunkTrailer;
 334            l = 2;
 335        }
 336
 337        if(request->offset <= len123) {
 338            iov[i].iov_base = (char*)trailer;
 339            iov[i].iov_len = l;
 340            i++;
 341        } else if(request->offset < len123 + l) {
 342            iov[i].iov_base = 
 343                (char*)endChunkTrailer + request->offset - len123;
 344            iov[i].iov_len = l - request->offset + len123;
 345            i++;
 346        }
 347    }
 348
 349    assert(i > 0);
 350
 351    if((request->operation & IO_MASK) == IO_WRITE) {
 352        if(i > 1) 
 353            rc = WRITEV(request->fd, iov, i);
 354        else
 355            rc = WRITE(request->fd, iov[0].iov_base, iov[0].iov_len);
 356    } else {
 357        if(i > 1) 
 358            rc = READV(request->fd, iov, i);
 359        else
 360            rc = READ(request->fd, iov[0].iov_base, iov[0].iov_len);
 361    }
 362
 363    if(rc > 0) {
 364        request->offset += rc;
 365        if(request->offset < 0) return 0;
 366        done = request->handler(0, event, request);
 367        return done;
 368    } else if(rc == 0 || errno == EPIPE) {
 369        done = request->handler(1, event, request);
 370    } else if(errno == EAGAIN || errno == EINTR) {
 371        return 0;
 372    } else if(errno == EFAULT || errno == EBADF) {
 373        abort();
 374    } else {
 375        done = request->handler(-errno, event, request);
 376    }
 377    assert(done);
 378    return done;
 379}
 380
 381int
 382streamRequestDone(StreamRequestPtr request)
 383{
 384    int len123 = 
 385        request->len + request->len2 +
 386        ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
 387
 388    if(request->offset < 0)
 389        return 0;
 390    else if(request->offset < len123)
 391        return 0;
 392    else if(request->operation & IO_CHUNKED) {
 393        if(request->operation & IO_END) {
 394            if(request->offset < len123 + (len123 ? 7 : 5))
 395                return 0;
 396        } else {
 397            if(request->offset < len123 + 2)
 398                return 0;
 399        }
 400    }
 401
 402    return 1;
 403}
 404
 405static int
 406serverSocket(int af)
 407{
 408    int fd, rc;
 409    if(af == 4) {
 410        fd = socket(PF_INET, SOCK_STREAM, 0);
 411    } else if(af == 6) {
 412#ifdef HAVE_IPv6
 413        fd = socket(PF_INET6, SOCK_STREAM, 0);
 414#else
 415        fd = -1;
 416        errno = EAFNOSUPPORT;
 417#endif
 418    } else {
 419        abort();
 420    }
 421
 422    if(fd >= 0) {
 423        rc = setNonblocking(fd, 1);
 424        if(rc < 0) {
 425            int errno_save = errno;
 426            CLOSE(fd);
 427            errno = errno_save;
 428            return -1;
 429        }
 430#ifdef HAVE_IPV6_PREFER_TEMPADDR
 431	if (af == 6 && useTemporarySourceAddress != 1) {
 432            int value;
 433            value = (useTemporarySourceAddress == 2) ? 1 : 0;
 434            rc = setsockopt(fd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
 435                            &value, sizeof(value));
 436            if (rc < 0) {
 437                /* no error, warning only */
 438                do_log_error(L_WARN, errno, "Couldn't set IPV6CTL_USETEMPADDR");
 439            }
 440	}
 441
 442#endif
 443    }
 444    return fd;
 445}
 446
 447FdEventHandlerPtr
 448do_connect(AtomPtr addr, int index, int port,
 449           int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr),
 450           void *data)
 451{
 452    ConnectRequestRec request;
 453    FdEventHandlerPtr event;
 454    int done, fd, af;
 455
 456    assert(addr->length > 0 && addr->string[0] == DNS_A);
 457    assert(addr->length % sizeof(HostAddressRec) == 1);
 458
 459    if(index >= (addr->length - 1)/ sizeof(HostAddressRec))
 460        index = 0;
 461
 462    request.firstindex = index;
 463    request.port = port;
 464    request.handler = handler;
 465    request.data = data;
 466 again:
 467    af = addr->string[1 + index * sizeof(HostAddressRec)];
 468    fd = serverSocket(af);
 469
 470    request.fd = fd;
 471    request.af = af;
 472    request.addr = addr;
 473    request.index = index;
 474
 475    if(fd < 0) {
 476        int n = (addr->length - 1) / sizeof(HostAddressRec);
 477        if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
 478            if((index + 1) % n != request.firstindex) {
 479                index = (index + 1) % n;
 480                goto again;
 481            }
 482        }
 483        do_log_error(L_ERROR, errno, "Couldn't create socket");
 484        done = (*handler)(-errno, NULL, &request);
 485        assert(done);
 486        return NULL;
 487    }
 488
 489    /* POLLIN is apparently needed on Windows */
 490    event = registerFdEvent(fd, POLLIN | POLLOUT,
 491                            do_scheduled_connect,
 492                            sizeof(ConnectRequestRec), &request);
 493    if(event == NULL) {
 494        done = (*handler)(-ENOMEM, NULL, &request);
 495        assert(done);
 496        return NULL;
 497    }
 498
 499    done = event->handler(0, event);
 500    if(done) {
 501        unregisterFdEvent(event);
 502        return NULL;
 503    }
 504    return event;
 505}
 506
 507int
 508do_scheduled_connect(int status, FdEventHandlerPtr event)
 509{
 510    ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
 511    AtomPtr addr = request->addr;
 512    int done;
 513    int rc;
 514    HostAddressPtr host;
 515    struct sockaddr_in servaddr;
 516#ifdef HAVE_IPv6
 517    struct sockaddr_in6 servaddr6;
 518#endif
 519
 520    assert(addr->length > 0 && addr->string[0] == DNS_A);
 521    assert(addr->length % sizeof(HostAddressRec) == 1);
 522    assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));
 523
 524    if(status) {
 525        done = request->handler(status, event, request);
 526        if(done) {
 527            releaseAtom(addr);
 528            request->addr = NULL;
 529            return 1;
 530        }
 531        return 0;
 532    }
 533
 534 again:
 535    host = (HostAddressPtr)&addr->string[1 + 
 536                                         request->index * 
 537                                         sizeof(HostAddressRec)];
 538    if(host->af != request->af) {
 539        int newfd;
 540        /* Ouch.  Our socket has a different protocol than the host
 541           address. */
 542        CLOSE(request->fd);
 543        newfd = serverSocket(host->af);
 544        if(newfd < 0) {
 545            if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
 546                int n = request->addr->length / sizeof(HostAddressRec);
 547                if((request->index + 1) % n != request->firstindex) {
 548                    request->index = (request->index + 1) % n;
 549                    goto again;
 550                }
 551            }
 552            request->fd = -1;
 553            done = request->handler(-errno, event, request);
 554            assert(done);
 555            return 1;
 556        }
 557        if(newfd != request->fd) {
 558            request->fd = dup2(newfd, request->fd);
 559            CLOSE(newfd);
 560            if(request->fd < 0) {
 561                done = request->handler(-errno, event, request);
 562                assert(done);
 563                return 1;
 564            }
 565        }
 566        request->af = host->af;
 567    }
 568    switch(host->af) {
 569    case 4:
 570        memset(&servaddr, 0, sizeof(servaddr));
 571        servaddr.sin_family = AF_INET;
 572        servaddr.sin_port = htons(request->port);
 573        memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
 574        rc = connect(request->fd,
 575                     (struct sockaddr*)&servaddr, sizeof(servaddr));
 576        break;
 577    case 6:
 578#ifdef HAVE_IPv6
 579        memset(&servaddr6, 0, sizeof(servaddr6));
 580        servaddr6.sin6_family = AF_INET6;
 581        servaddr6.sin6_port = htons(request->port);
 582        memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
 583        rc = connect(request->fd,
 584                     (struct sockaddr*)&servaddr6, sizeof(servaddr6));
 585#else
 586        rc = -1;
 587        errno = EAFNOSUPPORT;
 588#endif
 589        break;
 590    default:
 591        abort();
 592    }
 593        
 594    if(rc >= 0 || errno == EISCONN) {
 595        done = request->handler(1, event, request);
 596        assert(done);
 597        releaseAtom(request->addr);
 598        request->addr = NULL;
 599        return 1;
 600    }
 601
 602    if(errno == EINPROGRESS || errno == EINTR) {
 603        return 0;
 604    } else if(errno == EFAULT || errno == EBADF) {
 605        abort();
 606    } else {
 607        int n = request->addr->length / sizeof(HostAddressRec);
 608        if((request->index + 1) % n != request->firstindex) {
 609            request->index = (request->index + 1) % n;
 610            goto again;
 611        }
 612        done = request->handler(-errno, event, request);
 613        assert(done);
 614        releaseAtom(request->addr);
 615        request->addr = NULL;
 616        return 1;
 617    }
 618}
 619
 620FdEventHandlerPtr
 621do_accept(int fd,
 622          int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
 623          void *data)
 624{
 625    FdEventHandlerPtr event;
 626    int done;
 627
 628    event = schedule_accept(fd, handler, data);
 629    if(event == NULL) {
 630        done = (*handler)(-ENOMEM, NULL, NULL);
 631        assert(done);
 632    }
 633
 634    /* But don't invoke it now - this will delay accept if under load. */
 635    return event;
 636}
 637
 638FdEventHandlerPtr
 639schedule_accept(int fd,
 640                int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
 641                void *data)
 642{
 643    FdEventHandlerPtr event;
 644    AcceptRequestRec request;
 645    int done;
 646
 647    request.fd = fd;
 648    request.handler = handler;
 649    request.data = data;
 650    event = registerFdEvent(fd, POLLIN, 
 651                            do_scheduled_accept, sizeof(request), &request);
 652    if(!event) {
 653        done = (*handler)(-ENOMEM, NULL, NULL);
 654        assert(done);
 655    }
 656    return event;
 657}
 658
 659int
 660do_scheduled_accept(int status, FdEventHandlerPtr event)
 661{
 662    AcceptRequestPtr request = (AcceptRequestPtr)&event->data;
 663    int rc, done;
 664    unsigned len;
 665    struct sockaddr_in addr;
 666
 667    if(status) {
 668        done = request->handler(status, event, request);
 669        if(done) return done;
 670    }
 671
 672    len = sizeof(struct sockaddr_in);
 673
 674    rc = accept(request->fd, (struct sockaddr*)&addr, &len);
 675
 676    if(rc >= 0)
 677        done = request->handler(rc, event, request);
 678    else
 679        done = request->handler(-errno, event, request);
 680    return done;
 681}
 682
 683FdEventHandlerPtr
 684create_listener(char *address, int port,
 685                int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
 686                void *data)
 687{
 688    int fd, rc;
 689    int one = 1;
 690    int done;
 691    struct sockaddr_in addr;
 692#ifdef HAVE_IPv6
 693    int inet6 = 1;
 694    struct sockaddr_in6 addr6;
 695#else
 696    int inet6 = 0;
 697#endif
 698
 699    if(inet6 && address) {
 700        struct in_addr buf;
 701        rc = inet_aton(address, &buf);
 702        if(rc == 1)
 703            inet6 = 0;
 704    }
 705    fd = -1;
 706    errno = EAFNOSUPPORT;
 707
 708#ifdef HAVE_IPv6
 709    if(inet6) {
 710        fd = socket(PF_INET6, SOCK_STREAM, 0);
 711    }
 712#endif
 713
 714    if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) {
 715        inet6 = 0;
 716        fd = socket(PF_INET, SOCK_STREAM, 0);
 717    }
 718
 719    if(fd < 0) {
 720        done = (*handler)(-errno, NULL, NULL);
 721        assert(done);
 722        return NULL;
 723    }
 724
 725#ifndef WIN32
 726    /* on WIN32 SO_REUSEADDR allows two sockets bind to the same port */
 727    rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
 728    if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR");
 729#endif
 730
 731    if(inet6) {
 732#ifdef HAVE_IPv6
 733        rc = setV6only(fd, 0);
 734        if(rc < 0)
 735            /* Reportedly OpenBSD returns an error for that.  So only
 736               log it as a debugging message. */
 737            do_log_error(D_CLIENT_CONN, errno, "Couldn't reset IPV6_V6ONLY");
 738
 739        memset(&addr6, 0, sizeof(addr6));
 740        rc = inet_pton(AF_INET6, address, &addr6.sin6_addr);
 741        if(rc != 1) {
 742            done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
 743            assert(done);
 744            return NULL;
 745        }
 746        addr6.sin6_family = AF_INET6;
 747        addr6.sin6_port = htons(port);
 748        rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
 749#else
 750        rc = -1;
 751        errno = EAFNOSUPPORT;
 752#endif
 753    } else {
 754        memset(&addr, 0, sizeof(addr));
 755        rc = inet_aton(address, &addr.sin_addr);
 756        if(rc != 1) {
 757            done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
 758            assert(done);
 759            return NULL;
 760        }
 761        addr.sin_family = AF_INET;
 762        addr.sin_port = htons(port);
 763        rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
 764    }
 765
 766    if(rc < 0) {
 767        do_log_error(L_ERROR, errno, "Couldn't bind");
 768        CLOSE(fd);
 769        done = (*handler)(-errno, NULL, NULL);
 770        assert(done);
 771        return NULL;
 772    }
 773
 774    rc = setNonblocking(fd, 1);
 775    if(rc < 0) {
 776        do_log_error(L_ERROR, errno, "Couldn't set non blocking mode");
 777        CLOSE(fd);
 778        done = (*handler)(-errno, NULL, NULL);
 779        assert(done);
 780        return NULL;
 781    }
 782        
 783    rc = listen(fd, 1024);
 784    if(rc < 0) {
 785        do_log_error(L_ERROR, errno, "Couldn't listen");
 786        CLOSE(fd);
 787        done = (*handler)(-errno, NULL, NULL);
 788        assert(done);
 789        return NULL;
 790    }
 791
 792    do_log(L_INFO, "Established listening socket on port %d.\n", port);
 793
 794    return schedule_accept(fd, handler, data);
 795}
 796
 797#ifndef SOL_TCP
 798/* BSD */
 799#define SOL_TCP IPPROTO_TCP
 800#endif
 801
 802int
 803setNonblocking(int fd, int nonblocking)
 804{
 805#ifdef WIN32 /*MINGW*/
 806    return win32_setnonblocking(fd, nonblocking);
 807#else
 808    int rc;
 809    rc = fcntl(fd, F_GETFL, 0);
 810    if(rc < 0)
 811        return -1;
 812
 813    rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
 814    if(rc < 0)
 815        return -1;
 816
 817    return 0;
 818#endif
 819}
 820
 821int
 822setNodelay(int fd, int nodelay)
 823{
 824    int val = nodelay ? 1 : 0;
 825    int rc;
 826    rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 827    if(rc < 0)
 828        return -1;
 829    return 0;
 830}
 831
 832#ifdef IPV6_V6ONLY
 833int
 834setV6only(int fd, int v6only)
 835{
 836    int val = v6only ? 1 : 0;
 837    int rc;
 838    rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
 839    if(rc < 0)
 840        return -1;
 841    return 0;
 842}
 843#else
 844int
 845setV6only(int fd, int v6only)
 846{
 847    return 0;
 848}
 849#endif
 850
 851typedef struct _LingeringClose {
 852    int fd;
 853    FdEventHandlerPtr handler;
 854    TimeEventHandlerPtr timeout;
 855} LingeringCloseRec, *LingeringClosePtr;
 856
 857static int
 858lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
 859{
 860    LingeringClosePtr l = *(LingeringClosePtr*)event->data;
 861    assert(l->timeout == event);
 862    l->timeout = NULL;
 863    if(l->handler)
 864        pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
 865    else {
 866        CLOSE(l->fd);
 867        free(l);
 868    }
 869    return 1;
 870}
 871
 872static int
 873lingeringCloseHandler(int status, FdEventHandlerPtr event)
 874{
 875    LingeringClosePtr l = *(LingeringClosePtr*)event->data;
 876    char buf[17];
 877    int rc;
 878
 879    assert(l->handler == event);
 880
 881    l->handler = NULL;
 882    if(status && status != -EDOGRACEFUL)
 883        goto done;
 884
 885    rc = READ(l->fd, &buf, 17);
 886    if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
 887        goto done;
 888
 889    /* The client is still sending data.  Ignore it in order to let
 890       TCP's flow control do its work.  The timeout will close the
 891       connection. */
 892    return 1;
 893
 894 done:
 895    if(l->timeout) {
 896        cancelTimeEvent(l->timeout);
 897        l->timeout = NULL;
 898    }
 899    CLOSE(l->fd);
 900    free(l);
 901    return 1;
 902}
 903
 904int
 905lingeringClose(int fd)
 906{
 907    int rc;
 908    LingeringClosePtr l;
 909
 910    rc = shutdown(fd, 1);
 911    if(rc < 0) {
 912        if(errno != ENOTCONN) {
 913            do_log_error(L_ERROR, errno, "Shutdown failed");
 914        } else if(errno == EFAULT || errno == EBADF) {
 915            abort();
 916        }
 917        CLOSE(fd);
 918        return 1;
 919    }
 920
 921    l = malloc(sizeof(LingeringCloseRec));
 922    if(l == NULL)
 923        goto fail;
 924    l->fd = fd;
 925    l->handler = NULL;
 926    l->timeout = NULL;
 927
 928    l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
 929                                   sizeof(LingeringClosePtr), &l);
 930    if(l->timeout == NULL) {
 931        free(l);
 932        goto fail;
 933    }
 934
 935    l->handler = registerFdEvent(fd, POLLIN,
 936                                 lingeringCloseHandler,
 937                                 sizeof(LingeringClosePtr), &l);
 938    if(l->handler == NULL) {
 939        do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
 940        /* But don't close -- the timeout will do its work. */
 941    }
 942    return 1;
 943
 944 fail:
 945    do_log(L_ERROR, "Couldn't schedule lingering close.\n");
 946    CLOSE(fd);
 947    return 1;
 948}
 949
 950NetAddressPtr
 951parseNetAddress(AtomListPtr list)
 952{
 953    NetAddressPtr nl;
 954    int i, rc, rc6;
 955    char buf[100];
 956    struct in_addr ina;
 957#ifdef HAVE_IPv6
 958    struct in6_addr ina6;
 959#endif
 960
 961    nl = malloc((list->length + 1) * sizeof(NetAddressRec));
 962    if(nl == NULL) {
 963        do_log(L_ERROR, "Couldn't allocate network list.\n");
 964        return NULL;
 965    }
 966
 967    for(i = 0; i < list->length; i++) {
 968        int prefix;
 969        char *s = list->list[i]->string, *p;
 970        int n = list->list[i]->length;
 971        char *suffix;
 972
 973        while(*s == ' ' || *s == '\t') {
 974            s++;
 975            n--;
 976        }
 977
 978        if(n >= 100) {
 979            do_log(L_ERROR, "Network name too long.\n");
 980            goto fail;
 981        }
 982        p = memchr(s, '/', n);
 983        if(p) {
 984            memcpy(buf, s, p - s);
 985            buf[p - s] = '\0';
 986            prefix = strtol(p + 1, &suffix, 10);
 987        } else {
 988            char *s1, *s2;
 989            prefix = -1;
 990            strcpy(buf, s);
 991            s1 = strchr(s, ' ');
 992            s2 = strchr(s, '\t');
 993            if(s1 == NULL) suffix = s2;
 994            else if(s2 == NULL) suffix = s1;
 995            else if(s1 < s2) suffix = s1;
 996            else suffix = s2;
 997            if(suffix == NULL)
 998                suffix = s + n;
 999        }
1000
1001        if(!isWhitespace(suffix)) {
1002            do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1003            goto fail;
1004        }
1005
1006        rc = 0; rc6 = 0;
1007        rc = inet_aton(buf, &ina);
1008#ifdef HAVE_IPv6
1009        if(rc == 0) {
1010            rc6 = inet_pton(AF_INET6, buf, &ina6);
1011        }
1012#endif
1013        if(rc == 0 && rc6 == 0) {
1014            do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1015            goto fail;
1016        }
1017        nl[i].prefix = prefix;
1018        if(rc) {
1019            nl[i].af = 4;
1020            memcpy(nl[i].data, &ina, 4);
1021        } else {
1022#ifdef HAVE_IPv6
1023            nl[i].af = 6;
1024            memcpy(nl[i].data, &ina6, 16);
1025#else
1026            abort();
1027#endif
1028        }
1029    }
1030    nl[i].af = 0;
1031    return nl;
1032
1033 fail:
1034    free(nl);
1035    return NULL;
1036}
1037
1038/* Returns 1 if the first n bits of a and b are equal */
1039static int
1040bitmatch(const unsigned char *a, const unsigned char *b, int n)
1041{
1042    if(n >= 8) {
1043        if(memcmp(a, b, n / 8) != 0)
1044            return 0;
1045    }
1046
1047    if(n % 8 != 0) {
1048        int mask = (~0) << (8 - n % 8);
1049        if((a[n / 8] & mask) != (b[n / 8] & mask))
1050            return 0;
1051    }
1052
1053    return 1;
1054}
1055
1056/* Returns 1 if the address in data is in list */
1057static int
1058match(int af, unsigned char *data, NetAddressPtr list)
1059{
1060    int i;
1061#ifdef HAVE_IPv6
1062    static const unsigned char v6mapped[] =
1063        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1064#endif
1065
1066    i = 0;
1067    while(list[i].af != 0) {
1068        if(af == 4 && list[i].af == 4) {
1069            if(bitmatch(data, list[i].data,
1070                        list[i].prefix >= 0 ? list[i].prefix : 32))
1071                return 1;
1072#ifdef HAVE_IPv6
1073        } else if(af == 6 && list[i].af == 6) {
1074            if(bitmatch(data, list[i].data,
1075                        list[i].prefix >= 0 ? list[i].prefix : 128))
1076                return 1;
1077        } else if(af == 6 && list[i].af == 4) {
1078            if(bitmatch(data, v6mapped, 96)) {
1079                if(bitmatch(data + 12, list[i].data,
1080                            list[i].prefix >= 0 ? list[i].prefix : 32))
1081                    return 1;
1082            }
1083        } else if(af == 4 && list[i].af == 6) {
1084            if(bitmatch(list[i].data, v6mapped, 96)) {
1085                if(bitmatch(data, list[i].data + 12,
1086                            list[i].prefix >= 96 ?
1087                            list[i].prefix - 96 : 32))
1088                    return 1;
1089            }
1090#endif
1091        } else {
1092            abort();
1093        }
1094        i++;
1095    }
1096    return 0;
1097}
1098
1099int
1100netAddressMatch(int fd, NetAddressPtr list)
1101{
1102    int rc;
1103    unsigned int len;
1104    struct sockaddr_in sain;
1105#ifdef HAVE_IPv6
1106    struct sockaddr_in6 sain6;
1107#endif
1108
1109    len = sizeof(sain);
1110    rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1111    if(rc < 0) {
1112        do_log_error(L_ERROR, errno, "Couldn't get peer name");
1113        return -1;
1114    }
1115
1116    if(sain.sin_family == AF_INET) {
1117        return match(4, (unsigned char*)&sain.sin_addr, list);
1118#ifdef HAVE_IPv6
1119    } else if(sain.sin_family == AF_INET6) {
1120        len = sizeof(sain6);
1121        rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1122        if(rc < 0) {
1123            do_log_error(L_ERROR, errno, "Couldn't get peer name");
1124            return -1;
1125        }
1126        if(sain6.sin6_family != AF_INET6) {
1127            do_log(L_ERROR, "Inconsistent peer name");
1128            return -1;
1129        }
1130        return match(6, (unsigned char*)&sain6.sin6_addr, list);
1131#endif
1132    } else {
1133        do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1134        return -1;
1135    }
1136    return 0;
1137}
1138
1139
1140        
1141        
1142
1143