Back to index

webcit  8.12-dfsg
tcp_sockets.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1987-2012 by the citadel.org team
00003  *
00004  * This program is open source software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License, version 3.
00006  * 
00007  * This program is distributed in the hope that it will be useful,
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  * GNU General Public License for more details.
00011  */
00012 
00013 /*
00014  * Uncomment this to log all communications with the Citadel server
00015 #define SERV_TRACE 1
00016  */
00017 
00018 #include "webcit.h"
00019 #include "webserver.h"
00020 
00021 long MaxRead = -1; /* should we do READ scattered or all at once? */
00022 
00023 /*
00024  * register the timeout
00025  */
00026 RETSIGTYPE timeout(int signum)
00027 {
00028        syslog(1, "Connection timed out; unable to reach citserver\n");
00029        /* no exit here, since we need to server the connection unreachable thing. exit(3); */
00030 }
00031 
00032 
00033 /*
00034  * Client side - connect to a unix domain socket
00035  */
00036 int uds_connectsock(char *sockpath)
00037 {
00038        struct sockaddr_un addr;
00039        int s;
00040 
00041        memset(&addr, 0, sizeof(addr));
00042        addr.sun_family = AF_UNIX;
00043        strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
00044 
00045        s = socket(AF_UNIX, SOCK_STREAM, 0);
00046        if (s < 0) {
00047               syslog(1, "Can't create socket [%s]: %s\n", sockpath, strerror(errno));
00048               return(-1);
00049        }
00050 
00051        if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00052               syslog(1, "Can't connect [%s]: %s\n", sockpath, strerror(errno));
00053               close(s);
00054               return(-1);
00055        }
00056 
00057        return s;
00058 }
00059 
00060 
00061 /*
00062  * TCP client - connect to a host/port 
00063  */
00064 int tcp_connectsock(char *host, char *service)
00065 {
00066        struct in6_addr serveraddr;
00067        struct addrinfo hints;
00068        struct addrinfo *res = NULL;
00069        struct addrinfo *ai = NULL;
00070        int rc = (-1);
00071        int s = (-1);
00072 
00073        if ((host == NULL) || IsEmptyStr(host))
00074               return (-1);
00075        if ((service == NULL) || IsEmptyStr(service))
00076               return (-1);
00077 
00078        syslog(9, "tcp_connectsock(%s,%s)\n", host, service);
00079 
00080        memset(&hints, 0x00, sizeof(hints));
00081        hints.ai_flags = AI_NUMERICSERV;
00082        hints.ai_family = AF_UNSPEC;
00083        hints.ai_socktype = SOCK_STREAM;
00084 
00085        /*
00086         * Handle numeric IPv4 and IPv6 addresses
00087         */
00088        rc = inet_pton(AF_INET, host, &serveraddr);
00089        if (rc == 1) {                                          /* dotted quad */
00090               hints.ai_family = AF_INET;
00091               hints.ai_flags |= AI_NUMERICHOST;
00092        } else {
00093               rc = inet_pton(AF_INET6, host, &serveraddr);
00094               if (rc == 1) {                                   /* IPv6 address */
00095                      hints.ai_family = AF_INET6;
00096                      hints.ai_flags |= AI_NUMERICHOST;
00097               }
00098        }
00099 
00100        /* Begin the connection process */
00101 
00102        rc = getaddrinfo(host, service, &hints, &res);
00103        if (rc != 0) {
00104               syslog(1, "%s: %s\n", host, gai_strerror(rc));
00105               freeaddrinfo(res);
00106               return(-1);
00107        }
00108 
00109        /*
00110         * Try all available addresses until we connect to one or until we run out.
00111         */
00112        for (ai = res; ai != NULL; ai = ai->ai_next) {
00113 
00114               if (ai->ai_family == AF_INET) syslog(9, "Trying IPv4\n");
00115               else if (ai->ai_family == AF_INET6) syslog(9, "Trying IPv6\n");
00116               else syslog(9, "This is going to fail.\n");
00117 
00118               s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00119               if (s < 0) {
00120                      syslog(1, "socket() failed: %s\n", strerror(errno));
00121                      freeaddrinfo(res);
00122                      return(-1);
00123               }
00124               rc = connect(s, ai->ai_addr, ai->ai_addrlen);
00125               if (rc >= 0) {
00126                      freeaddrinfo(res);
00127                      return(s);
00128               }
00129               else {
00130                      syslog(1, "connect() failed: %s\n", strerror(errno));
00131                      close(s);
00132               }
00133        }
00134         freeaddrinfo(res);
00135        return(-1);
00136 }
00137 
00138 
00139 /*
00140  *  input string from pipe
00141  */
00142 int serv_getln(char *strbuf, int bufsize)
00143 {
00144        wcsession *WCC = WC;
00145        int len;
00146 
00147        *strbuf = '\0';
00148        StrBuf_ServGetln(WCC->MigrateReadLineBuf);
00149        len = StrLength(WCC->MigrateReadLineBuf);
00150        if (len > bufsize)
00151               len = bufsize - 1;
00152        memcpy(strbuf, ChrPtr(WCC->MigrateReadLineBuf), len);
00153        FlushStrBuf(WCC->MigrateReadLineBuf);
00154        strbuf[len] = '\0';
00155 #ifdef SERV_TRACE
00156        syslog(9, "%3d<<<%s\n", WC->serv_sock, strbuf);
00157 #endif
00158        return len;
00159 }
00160 
00161 
00162 int StrBuf_ServGetln(StrBuf *buf)
00163 {
00164        wcsession *WCC = WC;
00165        const char *ErrStr = NULL;
00166        int rc;
00167        
00168        if (!WCC->connected)
00169               return -1;
00170 
00171        FlushStrBuf(buf);
00172        rc = StrBufTCP_read_buffered_line_fast(buf, 
00173                                           WCC->ReadBuf, 
00174                                           &WCC->ReadPos, 
00175                                           &WCC->serv_sock, 
00176                                           5, 1, 
00177                                           &ErrStr);
00178        if (rc < 0)
00179        {
00180               syslog(1, "StrBuf_ServGetln(): Server connection broken: %s\n",
00181                      (ErrStr)?ErrStr:"");
00182               wc_backtrace();
00183               if (WCC->serv_sock > 0) close(WCC->serv_sock);
00184               WCC->serv_sock = (-1);
00185               WCC->connected = 0;
00186               WCC->logged_in = 0;
00187        }
00188 #ifdef SERV_TRACE
00189        else 
00190        {
00191               long pos = 0;
00192               if (WCC->ReadPos != NULL)
00193                      pos = WCC->ReadPos - ChrPtr(WCC->ReadBuf);
00194               syslog(9, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf));
00195        }
00196 #endif
00197        return rc;
00198 }
00199 
00200 int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize)
00201 {
00202        wcsession *WCC = WC;
00203        const char *ErrStr;
00204        int rc;
00205        
00206        rc = StrBufReadBLOBBuffered(buf, 
00207                                 WCC->ReadBuf, 
00208                                 &WCC->ReadPos,
00209                                 &WCC->serv_sock, 
00210                                 1, 
00211                                 BlobSize, 
00212                                 NNN_TERM,
00213                                 &ErrStr);
00214        if (rc < 0)
00215        {
00216               syslog(1, "StrBuf_ServGetBLOBBuffered(): Server connection broken: %s\n",
00217                      (ErrStr)?ErrStr:"");
00218               wc_backtrace();
00219               if (WCC->serv_sock > 0) close(WCC->serv_sock);
00220               WCC->serv_sock = (-1);
00221               WCC->connected = 0;
00222               WCC->logged_in = 0;
00223        }
00224 #ifdef SERV_TRACE
00225         else
00226                 syslog(9, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
00227 #endif
00228 
00229        return rc;
00230 }
00231 
00232 int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize)
00233 {
00234        wcsession *WCC = WC;
00235        const char *ErrStr;
00236        int rc;
00237        
00238        WCC->ReadPos = NULL;
00239        rc = StrBufReadBLOB(buf, &WCC->serv_sock, 1, BlobSize, &ErrStr);
00240        if (rc < 0)
00241        {
00242               syslog(1, "StrBuf_ServGetBLOB(): Server connection broken: %s\n",
00243                      (ErrStr)?ErrStr:"");
00244               wc_backtrace();
00245               if (WCC->serv_sock > 0) close(WCC->serv_sock);
00246               WCC->serv_sock = (-1);
00247               WCC->connected = 0;
00248               WCC->logged_in = 0;
00249        }
00250 #ifdef SERV_TRACE
00251         else
00252                 syslog(9, "%3d<<<BLOB: %d bytes\n", WC->serv_sock, StrLength(buf));
00253 #endif
00254 
00255        return rc;
00256 }
00257 
00258 
00259 void FlushReadBuf (void)
00260 {
00261        long len;
00262        const char *pch;
00263        const char *pche;
00264        wcsession *WCC = WC;
00265 
00266        len = StrLength(WCC->ReadBuf);
00267        if ((len > 0) &&
00268            (WCC->ReadPos != NULL) && 
00269            (WCC->ReadPos != StrBufNOTNULL))
00270               
00271        {
00272               pch = ChrPtr(WCC->ReadBuf);
00273               pche = pch + len;
00274               if (WCC->ReadPos != pche)
00275               {
00276                      syslog(1,
00277                             "ERROR: somebody didn't eat his soup! Remaing Chars: %ld [%s]\n", 
00278                             (long)(pche - WCC->ReadPos),
00279                             pche
00280                      );
00281                      syslog(1, 
00282                             "--------------------------------------------------------------------------------\n"
00283                             "Whole buf: [%s]\n"
00284                             "--------------------------------------------------------------------------------\n", 
00285                             pch);
00286                      AppendImportantMessage(HKEY("Suppenkasper alert! watch your webcit logfile and get connected to your favourite opensource Crew."));
00287               }
00288        }
00289 
00290        FlushStrBuf(WCC->ReadBuf);
00291        WCC->ReadPos = NULL;
00292 
00293 
00294 }
00295 
00296 
00297 /*
00298  *  send binary to server
00299  *  buf the buffer to write to citadel server
00300  *  nbytes how many bytes to send to citadel server
00301  */
00302 int serv_write(const char *buf, int nbytes)
00303 {
00304        wcsession *WCC = WC;
00305        int bytes_written = 0;
00306        int retval;
00307 
00308        FlushReadBuf();
00309        while (bytes_written < nbytes) {
00310               retval = write(WCC->serv_sock, &buf[bytes_written],
00311                             nbytes - bytes_written);
00312               if (retval < 1) {
00313                      const char *ErrStr = strerror(errno);
00314                      syslog(1, "serv_write(): Server connection broken: %s\n",
00315                             (ErrStr)?ErrStr:"");
00316                      if (WCC->serv_sock > 0) close(WCC->serv_sock);
00317                      WCC->serv_sock = (-1);
00318                      WCC->connected = 0;
00319                      WCC->logged_in = 0;
00320                      return 0;
00321               }
00322               bytes_written = bytes_written + retval;
00323        }
00324        return 1;
00325 }
00326 
00327 
00328 /*
00329  *  send line to server
00330  *  string the line to send to the citadel server
00331  */
00332 int serv_puts(const char *string)
00333 {
00334 #ifdef SERV_TRACE
00335        syslog(9, "%3d>>>%s\n", WC->serv_sock, string);
00336 #endif
00337        FlushReadBuf();
00338 
00339        if (!serv_write(string, strlen(string)))
00340               return 0;
00341        return serv_write("\n", 1);
00342 }
00343 
00344 /*
00345  *  send line to server
00346  *  string the line to send to the citadel server
00347  */
00348 int serv_putbuf(const StrBuf *string)
00349 {
00350 #ifdef SERV_TRACE
00351        syslog(9, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string));
00352 #endif
00353        FlushReadBuf();
00354 
00355        if (!serv_write(ChrPtr(string), StrLength(string)))
00356               return 0;
00357        return serv_write("\n", 1);
00358 }
00359 
00360 
00361 /*
00362  *  convenience function to send stuff to the server
00363  *  format the formatstring
00364  *  ... the entities to insert into format 
00365  */
00366 int serv_printf(const char *format,...)
00367 {
00368        va_list arg_ptr;
00369        char buf[SIZ];
00370        size_t len;
00371        int rc;
00372 
00373        FlushReadBuf();
00374 
00375        va_start(arg_ptr, format);
00376        vsnprintf(buf, sizeof buf, format, arg_ptr);
00377        va_end(arg_ptr);
00378 
00379        len = strlen(buf);
00380        buf[len++] = '\n';
00381        buf[len] = '\0';
00382        rc = serv_write(buf, len);
00383 #ifdef SERV_TRACE
00384        syslog(9, ">>>%s", buf);
00385 #endif
00386        return rc;
00387 }
00388 
00389 
00390 /*
00391  * Read binary data from server into memory using a series of server READ commands.
00392  * returns the read content as StrBuf
00393  */
00394 int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) 
00395 {
00396        wcsession *WCC = WC;
00397        size_t bytes_read = 0;
00398        size_t this_block = 0;
00399        int rc = 6;
00400        int ServerRc = 6;
00401 
00402        if (Ret == NULL) {
00403               return -1;
00404        }
00405 
00406        while ((bytes_read < total_len) && (ServerRc == 6)) {
00407 
00408               if (WCC->serv_sock==-1) {
00409                      FlushStrBuf(Ret); 
00410                      return -1; 
00411               }
00412 
00413               serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read);
00414               if ( (rc = StrBuf_ServGetln(Buf) > 0) &&
00415                    (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) 
00416               {
00417                      if (rc < 0)
00418                             return rc;
00419                      StrBufCutLeft(Buf, 4);
00420                      this_block = StrTol(Buf);
00421                      rc = StrBuf_ServGetBLOBBuffered(Ret, this_block);
00422                      if (rc < 0) {
00423                             syslog(1, "Server connection broken during download\n");
00424                             wc_backtrace();
00425                             if (WCC->serv_sock > 0) close(WCC->serv_sock);
00426                             WCC->serv_sock = (-1);
00427                             WCC->connected = 0;
00428                             WCC->logged_in = 0;
00429                             return rc;
00430                      }
00431                      bytes_read += rc;
00432               }
00433        }
00434 
00435        return StrLength(Ret);
00436 }
00437 
00438 
00439 int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target)
00440 {
00441        const char *Error;
00442 #ifdef HAVE_OPENSSL
00443        const char *pch, *pchs;
00444        int rlen, len, retval = 0;
00445 
00446        if (is_https) {
00447               int ntries = 0;
00448               if (StrLength(Hdr->ReadBuf) > 0)
00449               {
00450                      pchs = ChrPtr(Hdr->ReadBuf);
00451                      pch = strchr(pchs, '\n');
00452                      if (pch != NULL) {
00453                             rlen = 0;
00454                             len = pch - pchs;
00455                             if (len > 0 && (*(pch - 1) == '\r') )
00456                                    rlen ++;
00457                             StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
00458                             StrBufCutLeft(Hdr->ReadBuf, len + 1);
00459                             return len - rlen;
00460                      }
00461               }
00462 
00463               while (retval == 0) { 
00464                             pch = NULL;
00465                             pchs = ChrPtr(Hdr->ReadBuf);
00466                             if (*pchs != '\0')
00467                                    pch = strchr(pchs, '\n');
00468                             if (pch == NULL) {
00469                                    retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING);
00470                                    pchs = ChrPtr(Hdr->ReadBuf);
00471                                    pch = strchr(pchs, '\n');
00472                                    if (pch == NULL)
00473                                           retval = 0;
00474                             }
00475                             if (retval == 0) {
00476                                    sleeeeeeeeeep(1);
00477                                    ntries ++;
00478                             }
00479                             if (ntries > 10)
00480                                    return 0;
00481               }
00482               if ((retval > 0) && (pch != NULL)) {
00483                      rlen = 0;
00484                      len = pch - pchs;
00485                      if (len > 0 && (*(pch - 1) == '\r') )
00486                             rlen ++;
00487                      StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
00488                      StrBufCutLeft(Hdr->ReadBuf, len + 1);
00489                      return len - rlen;
00490 
00491               }
00492               else 
00493                      return -1;
00494        }
00495        else 
00496 #endif
00497               return StrBufTCP_read_buffered_line_fast(Target, 
00498                                                   Hdr->ReadBuf,
00499                                                   &Hdr->Pos,
00500                                                   &Hdr->http_sock,
00501                                                   5,
00502                                                   1,
00503                                                   &Error);
00504 }
00505 
00506 
00507 /* 
00508  * This is a generic function to set up a master socket for listening on
00509  * a TCP port.  The server shuts down if the bind fails.  (IPv4/IPv6 version)
00510  *
00511  * ip_addr    IP address to bind
00512  * port_number       port number to bind
00513  * queue_len  number of incoming connections to allow in the queue
00514  */
00515 int webcit_tcp_server(char *ip_addr, int port_number, int queue_len)
00516 {
00517        struct protoent *p;
00518        struct sockaddr_in6 sin6;
00519        struct sockaddr_in sin4;
00520        int s, i, b;
00521        int ip_version = 6;
00522 
00523        memset(&sin6, 0, sizeof(sin6));
00524        memset(&sin4, 0, sizeof(sin4));
00525        sin6.sin6_family = AF_INET6;
00526        sin4.sin_family = AF_INET;
00527 
00528        if (   (ip_addr == NULL)                                              /* any IPv6 */
00529               || (IsEmptyStr(ip_addr))
00530               || (!strcmp(ip_addr, "*"))
00531        ) {
00532               ip_version = 6;
00533               sin6.sin6_addr = in6addr_any;
00534        }
00535        else if (!strcmp(ip_addr, "0.0.0.0"))                                        /* any IPv4 */
00536        {
00537               ip_version = 4;
00538               sin4.sin_addr.s_addr = INADDR_ANY;
00539        }
00540        else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':')))                  /* specific IPv4 */
00541        {
00542               ip_version = 4;
00543               if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
00544                      syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
00545                      return (-WC_EXIT_BIND);
00546               }
00547        }
00548        else                                                                  /* specific IPv6 */
00549        {
00550               ip_version = 6;
00551               if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
00552                      syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
00553                      return (-WC_EXIT_BIND);
00554               }
00555        }
00556 
00557        if (port_number == 0) {
00558               syslog(1, "Cannot start: no port number specified.\n");
00559               return (-WC_EXIT_BIND);
00560        }
00561        sin6.sin6_port = htons((u_short) port_number);
00562        sin4.sin_port = htons((u_short) port_number);
00563 
00564        p = getprotobyname("tcp");
00565 
00566        s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
00567        if (s < 0) {
00568               syslog(1, "Can't create a listening socket: %s\n", strerror(errno));
00569               return (-WC_EXIT_BIND);
00570        }
00571        /* Set some socket options that make sense. */
00572        i = 1;
00573        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
00574 
00575        if (ip_version == 6) {
00576               b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
00577        }
00578        else {
00579               b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
00580        }
00581 
00582        if (b < 0) {
00583               syslog(1, "Can't bind: %s\n", strerror(errno));
00584               close(s);
00585               return (-WC_EXIT_BIND);
00586        }
00587 
00588        if (listen(s, queue_len) < 0) {
00589               syslog(1, "Can't listen: %s\n", strerror(errno));
00590               close(s);
00591               return (-WC_EXIT_BIND);
00592        }
00593        return (s);
00594 }
00595 
00596 
00597 /*
00598  * Create a Unix domain socket and listen on it
00599  * sockpath - file name of the unix domain socket
00600  * queue_len - Number of incoming connections to allow in the queue
00601  */
00602 int webcit_uds_server(char *sockpath, int queue_len)
00603 {
00604        struct sockaddr_un addr;
00605        int s;
00606        int i;
00607        int actual_queue_len;
00608 
00609        actual_queue_len = queue_len;
00610        if (actual_queue_len < 5) actual_queue_len = 5;
00611 
00612        i = unlink(sockpath);
00613        if ((i != 0) && (errno != ENOENT)) {
00614               syslog(1, "webcit: can't unlink %s: %s\n",
00615                      sockpath, strerror(errno));
00616               return (-WC_EXIT_BIND);
00617        }
00618 
00619        memset(&addr, 0, sizeof(addr));
00620        addr.sun_family = AF_UNIX;
00621        safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
00622 
00623        s = socket(AF_UNIX, SOCK_STREAM, 0);
00624        if (s < 0) {
00625               syslog(1, "webcit: Can't create a unix domain socket: %s\n", strerror(errno));
00626               return (-WC_EXIT_BIND);
00627        }
00628 
00629        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00630               syslog(1, "webcit: Can't bind: %s\n", strerror(errno));
00631               close(s);
00632               return (-WC_EXIT_BIND);
00633        }
00634 
00635        if (listen(s, actual_queue_len) < 0) {
00636               syslog(1, "webcit: Can't listen: %s\n", strerror(errno));
00637               close(s);
00638               return (-WC_EXIT_BIND);
00639        }
00640 
00641        chmod(sockpath, 0777);
00642        return(s);
00643 }
00644 
00645 
00646 
00647 
00648 /*
00649  * Read data from the client socket.
00650  *
00651  * sock              socket fd to read from
00652  * buf        buffer to read into 
00653  * bytes      number of bytes to read
00654  * timeout    Number of seconds to wait before timing out
00655  *
00656  * Possible return values:
00657  *      1       Requested number of bytes has been read.
00658  *      0       Request timed out.
00659  *     -1     Connection is broken, or other error.
00660  */
00661 int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout)
00662 {
00663        const char *Error;
00664        int retval = 0;
00665 
00666 #ifdef HAVE_OPENSSL
00667        if (is_https) {
00668               long bufremain = 0;
00669               long baselen;
00670 
00671               baselen = StrLength(Target);
00672 
00673               if (Hdr->Pos == NULL)
00674                      Hdr->Pos = ChrPtr(Hdr->ReadBuf);
00675 
00676               if (StrLength(Hdr->ReadBuf) > 0)
00677               {
00678                      bufremain = StrLength(Hdr->ReadBuf) - (Hdr->Pos - ChrPtr(Hdr->ReadBuf));
00679                      
00680                      if (bytes < bufremain)
00681                             bufremain = bytes;
00682                      StrBufAppendBufPlain(Target, Hdr->Pos, bufremain, 0);
00683                      StrBufCutLeft(Hdr->ReadBuf, bufremain);
00684               }
00685 
00686               if (bytes > bufremain) 
00687               {
00688                      while ((StrLength(Hdr->ReadBuf) + StrLength(Target) < bytes + baselen) &&
00689                             (retval >= 0))
00690                             retval = client_read_sslbuffer(Hdr->ReadBuf, timeout);
00691                      if (retval >= 0) {
00692                             StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */
00693                             return 1;
00694                      }
00695                      else {
00696                             syslog(2, "client_read_ssl() failed\n");
00697                             return -1;
00698                      }
00699               }
00700               else 
00701                      return 1;
00702        }
00703 #endif
00704 
00705        retval = StrBufReadBLOBBuffered(Target, 
00706                                    Hdr->ReadBuf, 
00707                                    &Hdr->Pos, 
00708                                    &Hdr->http_sock, 
00709                                    1, 
00710                                    bytes,
00711                                    O_TERM,
00712                                    &Error);
00713        if (retval < 0) {
00714               syslog(2, "client_read() failed: %s\n",
00715                      Error);
00716               wc_backtrace();
00717               return retval;
00718        }
00719 
00720        return 1;
00721 }
00722 
00723 
00724 /*
00725  * Begin buffering HTTP output so we can transmit it all in one write operation later.
00726  */
00727 void begin_burst(void)
00728 {
00729        if (WC->WBuf == NULL) {
00730               WC->WBuf = NewStrBufPlain(NULL, 32768);
00731        }
00732 }
00733 
00734 
00735 /*
00736  * Finish buffering HTTP output.  [Compress using zlib and] output with a Content-Length: header.
00737  */
00738 long end_burst(void)
00739 {
00740        wcsession *WCC = WC;
00741         const char *ptr, *eptr;
00742         long count;
00743        ssize_t res = 0;
00744         fd_set wset;
00745         int fdflags;
00746 
00747        if (!DisableGzip && (WCC->Hdr->HR.gzip_ok))
00748        {
00749               if (CompressBuffer(WCC->WBuf) > 0)
00750                      hprintf("Content-encoding: gzip\r\n");
00751               else {
00752                      syslog(LOG_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno));
00753                      wc_backtrace();
00754               }
00755        }
00756 
00757        if (WCC->WFBuf != NULL) {
00758               WildFireSerializePayload(WCC->WFBuf, WCC->HBuf, &WCC->Hdr->nWildfireHeaders, NULL);
00759               FreeStrBuf(&WCC->WFBuf);
00760        }
00761 
00762        if (WCC->Hdr->HR.prohibit_caching)
00763               hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
00764        hprintf("Content-length: %d\r\n\r\n", StrLength(WCC->WBuf));
00765 
00766        ptr = ChrPtr(WCC->HBuf);
00767        count = StrLength(WCC->HBuf);
00768        eptr = ptr + count;
00769 
00770 #ifdef HAVE_OPENSSL
00771        if (is_https) {
00772               client_write_ssl(WCC->HBuf);
00773               client_write_ssl(WCC->WBuf);
00774               return (count);
00775        }
00776 #endif
00777 
00778        if (WCC->Hdr->http_sock == -1)
00779               return -1;
00780        fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
00781 
00782        while ((ptr < eptr) && (WCC->Hdr->http_sock != -1)){
00783                 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
00784                         FD_ZERO(&wset);
00785                         FD_SET(WCC->Hdr->http_sock, &wset);
00786                         if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
00787                                 syslog(2, "client_write: Socket select failed (%s)\n", strerror(errno));
00788                                 return -1;
00789                         }
00790                 }
00791 
00792                 if ((WCC->Hdr->http_sock == -1) || 
00793                   (res = write(WCC->Hdr->http_sock, 
00794                              ptr,
00795                              count)) == -1) {
00796                         syslog(2, "client_write: Socket write failed (%s)\n", strerror(errno));
00797                       wc_backtrace();
00798                         return res;
00799                 }
00800                 count -= res;
00801               ptr += res;
00802         }
00803 
00804        ptr = ChrPtr(WCC->WBuf);
00805        count = StrLength(WCC->WBuf);
00806        eptr = ptr + count;
00807 
00808         while ((ptr < eptr) && (WCC->Hdr->http_sock != -1)) {
00809                 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
00810                         FD_ZERO(&wset);
00811                         FD_SET(WCC->Hdr->http_sock, &wset);
00812                         if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
00813                                 syslog(2, "client_write: Socket select failed (%s)\n", strerror(errno));
00814                                 return -1;
00815                         }
00816                 }
00817 
00818                 if ((WCC->Hdr->http_sock == -1) || 
00819                   (res = write(WCC->Hdr->http_sock, 
00820                              ptr,
00821                              count)) == -1) {
00822                         syslog(2, "client_write: Socket write failed (%s)\n", strerror(errno));
00823                      wc_backtrace();
00824                         return res;
00825                 }
00826                 count -= res;
00827               ptr += res;
00828         }
00829 
00830        return StrLength(WCC->WBuf);
00831 }
00832 
00833 
00834 /*
00835  * lingering_close() a`la Apache. see
00836  * http://www.apache.org/docs/misc/fin_wait_2.html for rationale
00837  */
00838 int lingering_close(int fd)
00839 {
00840        char buf[SIZ];
00841        int i;
00842        fd_set set;
00843        struct timeval tv, start;
00844 
00845        gettimeofday(&start, NULL);
00846        if (fd == -1)
00847               return -1;
00848        shutdown(fd, 1);
00849        do {
00850               do {
00851                      gettimeofday(&tv, NULL);
00852                      tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
00853                      tv.tv_usec = start.tv_usec - tv.tv_usec;
00854                      if (tv.tv_usec < 0) {
00855                             tv.tv_sec--;
00856                             tv.tv_usec += 1000000;
00857                      }
00858                      FD_ZERO(&set);
00859                      FD_SET(fd, &set);
00860                      i = select(fd + 1, &set, NULL, NULL, &tv);
00861               } while (i == -1 && errno == EINTR);
00862 
00863               if (i <= 0)
00864                      break;
00865 
00866               i = read(fd, buf, sizeof buf);
00867        } while (i != 0 && (i != -1 || errno == EINTR));
00868 
00869        return close(fd);
00870 }
00871 
00872 void
00873 HttpNewModule_TCPSOCKETS
00874 (ParsedHttpHdrs *httpreq)
00875 {
00876 
00877        httpreq->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
00878 }
00879 
00880 void
00881 HttpDetachModule_TCPSOCKETS
00882 (ParsedHttpHdrs *httpreq)
00883 {
00884 
00885        FlushStrBuf(httpreq->ReadBuf);
00886        ReAdjustEmptyBuf(httpreq->ReadBuf, 4 * SIZ, SIZ);
00887 }
00888 
00889 void
00890 HttpDestroyModule_TCPSOCKETS
00891 (ParsedHttpHdrs *httpreq)
00892 {
00893 
00894        FreeStrBuf(&httpreq->ReadBuf);
00895 }
00896 
00897 
00898 void
00899 SessionNewModule_TCPSOCKETS
00900 (wcsession *sess)
00901 {
00902        sess->CLineBuf = NewStrBuf();
00903        sess->MigrateReadLineBuf = NewStrBuf();
00904 }
00905 
00906 void 
00907 SessionDestroyModule_TCPSOCKETS
00908 (wcsession *sess)
00909 {
00910        FreeStrBuf(&sess->CLineBuf);
00911        FreeStrBuf(&sess->ReadBuf);
00912        sess->connected = 0;
00913        sess->ReadPos = NULL;
00914        FreeStrBuf(&sess->MigrateReadLineBuf);
00915        if (sess->serv_sock > 0) {
00916               syslog(LOG_DEBUG, "Closing socket %d", sess->serv_sock);
00917               close(sess->serv_sock);
00918        }
00919        sess->serv_sock = -1;
00920 }