"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/socket.c" (25 Mar 2018, 20726 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "socket.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Socket operations.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  */
    7 /*
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 #undef n_FILE
   33 #define n_FILE socket
   34 
   35 #ifndef HAVE_AMALGAMATION
   36 # include "nail.h"
   37 #endif
   38 
   39 EMPTY_FILE()
   40 #ifdef HAVE_SOCKETS
   41 #include <sys/socket.h>
   42 
   43 #include <netdb.h>
   44 
   45 #include <netinet/in.h>
   46 
   47 #ifdef HAVE_ARPA_INET_H
   48 # include <arpa/inet.h>
   49 #endif
   50 
   51 #ifdef HAVE_XSSL
   52 # include <openssl/err.h>
   53 # include <openssl/rand.h>
   54 # include <openssl/ssl.h>
   55 # include <openssl/x509v3.h>
   56 # include <openssl/x509.h>
   57 #endif
   58 
   59 /* */
   60 static bool_t a_socket_open(struct sock *sp, struct url *urlp);
   61 
   62 /* Write to socket fd, restarting on EINTR, unless anything is written */
   63 static long a_socket_xwrite(int fd, char const *data, size_t sz);
   64 
   65 static sigjmp_buf __sopen_actjmp; /* TODO someday, we won't need it no more */
   66 static int        __sopen_sig; /* TODO someday, we won't need it no more */
   67 static void
   68 __sopen_onsig(int sig) /* TODO someday, we won't need it no more */
   69 {
   70    NYD_X; /* Signal handler */
   71    if (__sopen_sig == -1) {
   72       fprintf(n_stderr, _("\nInterrupting this operation may turn "
   73          "the DNS resolver unusable\n"));
   74       __sopen_sig = 0;
   75    } else {
   76       __sopen_sig = sig;
   77       siglongjmp(__sopen_actjmp, 1);
   78    }
   79 }
   80 
   81 static bool_t
   82 a_socket_open(struct sock *sp, struct url *urlp) /* TODO sigstuff; refactor */
   83 {
   84 # ifdef HAVE_SO_SNDTIMEO
   85    struct timeval tv;
   86 # endif
   87 # ifdef HAVE_SO_LINGER
   88    struct linger li;
   89 # endif
   90 # ifdef HAVE_GETADDRINFO
   91 #  ifndef NI_MAXHOST
   92 #   define NI_MAXHOST 1025
   93 #  endif
   94    char hbuf[NI_MAXHOST];
   95    struct addrinfo hints, *res0 = NULL, *res;
   96 # else
   97    struct sockaddr_in servaddr;
   98    struct in_addr **pptr;
   99    struct hostent *hp;
  100    struct servent *ep;
  101 # endif
  102    sighandler_type volatile ohup, oint;
  103    char const * volatile serv;
  104    int volatile sofd = -1, errval;
  105    NYD2_ENTER;
  106 
  107    n_UNINIT(errval, 0);
  108 
  109    /* Connect timeouts after 30 seconds XXX configurable */
  110 # ifdef HAVE_SO_SNDTIMEO
  111    tv.tv_sec = 30;
  112    tv.tv_usec = 0;
  113 # endif
  114    serv = (urlp->url_port != NULL) ? urlp->url_port : urlp->url_proto;
  115 
  116    if (n_poption & n_PO_D_V)
  117       n_err(_("Resolving host %s:%s ... "), urlp->url_host.s, serv);
  118 
  119    /* Signal handling (in respect to __sopen_sig dealing) is heavy, but no
  120     * healing until v15.0 and i want to end up with that functionality */
  121    hold_sigs();
  122    __sopen_sig = 0;
  123    ohup = safe_signal(SIGHUP, &__sopen_onsig);
  124    oint = safe_signal(SIGINT, &__sopen_onsig);
  125    if (sigsetjmp(__sopen_actjmp, 0)) {
  126 jpseudo_jump:
  127       n_err("%s\n",
  128          (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
  129       if (sofd >= 0) {
  130          close(sofd);
  131          sofd = -1;
  132       }
  133       goto jjumped;
  134    }
  135    rele_sigs();
  136 
  137 # ifdef HAVE_GETADDRINFO
  138    for (;;) {
  139       memset(&hints, 0, sizeof hints);
  140       hints.ai_socktype = SOCK_STREAM;
  141       __sopen_sig = -1;
  142       errval = getaddrinfo(urlp->url_host.s, serv, &hints, &res0);
  143       if (__sopen_sig != -1) {
  144          __sopen_sig = SIGINT;
  145          goto jpseudo_jump;
  146       }
  147       __sopen_sig = 0;
  148       if (errval == 0)
  149          break;
  150 
  151       if (n_poption & n_PO_D_V)
  152          n_err(_("failed\n"));
  153       n_err(_("Lookup of %s:%s failed: %s\n"),
  154          urlp->url_host.s, serv, gai_strerror(errval));
  155 
  156       /* Error seems to depend on how "smart" the /etc/service code is: is it
  157        * "able" to state whether the service as such is NONAME or does it only
  158        * check for the given ai_socktype.. */
  159       if (errval == EAI_NONAME || errval == EAI_SERVICE) {
  160          if (serv == urlp->url_proto &&
  161                (serv = n_servbyname(urlp->url_proto, NULL)) != NULL &&
  162                *serv != '\0') {
  163             n_err(_("  Trying standard protocol port %s\n"), serv);
  164             n_err(_("  If that succeeds consider including the "
  165                "port in the URL!\n"));
  166             continue;
  167          }
  168          if (serv != urlp->url_port)
  169             n_err(_("  Including a port number in the URL may "
  170                "circumvent this problem\n"));
  171       }
  172       assert(sofd == -1);
  173       errval = 0;
  174       goto jjumped;
  175    }
  176    if (n_poption & n_PO_D_V)
  177       n_err(_("done\n"));
  178 
  179    for (res = res0; res != NULL && sofd < 0; res = res->ai_next) {
  180       if (n_poption & n_PO_D_V) {
  181          if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf,
  182                NULL, 0, NI_NUMERICHOST))
  183             memcpy(hbuf, "unknown host", sizeof("unknown host"));
  184          n_err(_("%sConnecting to %s:%s ... "),
  185                (res == res0 ? n_empty : "\n"), hbuf, serv);
  186       }
  187 
  188       sofd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  189       if (sofd >= 0) {
  190 #  ifdef HAVE_SO_SNDTIMEO
  191          (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  192 #  endif
  193          if (connect(sofd, res->ai_addr, res->ai_addrlen)) {
  194             n_perr("connect(2) failed:", errval = n_err_no);
  195             close(sofd);
  196             sofd = -1;
  197          }
  198       }
  199    }
  200 
  201 jjumped:
  202    if (res0 != NULL) {
  203       freeaddrinfo(res0);
  204       res0 = NULL;
  205    }
  206 
  207 # else /* HAVE_GETADDRINFO */
  208    if (serv == urlp->url_proto) {
  209       if ((ep = getservbyname(n_UNCONST(serv), "tcp")) != NULL)
  210          urlp->url_portno = ntohs(ep->s_port);
  211       else {
  212          if (n_poption & n_PO_D_V)
  213             n_err(_("failed\n"));
  214          if ((serv = n_servbyname(urlp->url_proto, &urlp->url_portno)) != NULL)
  215             n_err(_("  Unknown service: %s\n"), urlp->url_proto);
  216             n_err(_("  Trying standard protocol port %s\n"), serv);
  217             n_err(_("  If that succeeds consider including the "
  218                "port in the URL!\n"));
  219          else {
  220             n_err(_("  Unknown service: %s\n"), urlp->url_proto);
  221             n_err(_("  Including a port number in the URL may "
  222                "circumvent this problem\n"));
  223             assert(sofd == -1 && errval == 0);
  224             goto jjumped;
  225          }
  226       }
  227    }
  228 
  229    __sopen_sig = -1;
  230    hp = gethostbyname(urlp->url_host.s);
  231    if (__sopen_sig != -1) {
  232       __sopen_sig = SIGINT;
  233       goto jpseudo_jump;
  234    }
  235    __sopen_sig = 0;
  236 
  237    if (hp == NULL) {
  238       char const *emsg;
  239 
  240       if (n_poption & n_PO_D_V)
  241          n_err(_("failed\n"));
  242       switch (h_errno) {
  243       case HOST_NOT_FOUND: emsg = N_("host not found"); break;
  244       default:
  245       case TRY_AGAIN:      emsg = N_("(maybe) try again later"); break;
  246       case NO_RECOVERY:    emsg = N_("non-recoverable server error"); break;
  247       case NO_DATA:        emsg = N_("valid name without IP address"); break;
  248       }
  249       n_err(_("Lookup of %s:%s failed: %s\n"),
  250          urlp->url_host.s, serv, V_(emsg));
  251       goto jjumped;
  252    } else if (n_poption & n_PO_D_V)
  253       n_err(_("done\n"));
  254 
  255    pptr = (struct in_addr**)hp->h_addr_list;
  256    if ((sofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  257       n_perr(_("could not create socket"), 0);
  258       assert(sofd == -1 && errval == 0);
  259       goto jjumped;
  260    }
  261 
  262    memset(&servaddr, 0, sizeof servaddr);
  263    servaddr.sin_family = AF_INET;
  264    servaddr.sin_port = htons(urlp->url_portno);
  265    memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
  266    if (n_poption & n_PO_D_V)
  267       n_err(_("%sConnecting to %s:%d ... "),
  268          n_empty, inet_ntoa(**pptr), (int)urlp->url_portno);
  269 #  ifdef HAVE_SO_SNDTIMEO
  270    (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  271 #  endif
  272    if (connect(sofd, (struct sockaddr*)&servaddr, sizeof servaddr)) {
  273       n_perr("connect(2) failed:", errval = n_err_no);
  274       close(sofd);
  275       sofd = -1;
  276    }
  277 jjumped:
  278 # endif /* !HAVE_GETADDRINFO */
  279 
  280    hold_sigs();
  281    safe_signal(SIGINT, oint);
  282    safe_signal(SIGHUP, ohup);
  283    rele_sigs();
  284 
  285    if (sofd < 0) {
  286       if (errval != 0) {
  287          n_err_no = errval;
  288          n_perr(_("Could not connect"), 0);
  289       }
  290       goto jleave;
  291    }
  292 
  293    if (n_poption & n_PO_D_V)
  294       n_err(_("connected.\n"));
  295 
  296    /* And the regular timeouts XXX configurable */
  297 # ifdef HAVE_SO_SNDTIMEO
  298    tv.tv_sec = 42;
  299    tv.tv_usec = 0;
  300    (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  301    (void)setsockopt(sofd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
  302 # endif
  303 # ifdef HAVE_SO_LINGER
  304    li.l_onoff = 1;
  305    li.l_linger = 42;
  306    (void)setsockopt(sofd, SOL_SOCKET, SO_LINGER, &li, sizeof li);
  307 # endif
  308 
  309    memset(sp, 0, sizeof *sp);
  310    sp->s_fd = sofd;
  311 
  312    /* SSL/TLS upgrade? */
  313 # ifdef HAVE_SSL
  314    hold_sigs();
  315 
  316 #  if defined HAVE_GETADDRINFO && defined SSL_CTRL_SET_TLSEXT_HOSTNAME /* TODO
  317       * TODO the SSL_ def check should NOT be here */
  318    if(urlp->url_flags & n_URL_TLS_MASK){
  319       memset(&hints, 0, sizeof hints);
  320       hints.ai_family = AF_UNSPEC;
  321       hints.ai_flags = AI_NUMERICHOST;
  322       res0 = NULL;
  323       if(getaddrinfo(urlp->url_host.s, NULL, &hints, &res0) == 0)
  324          freeaddrinfo(res0);
  325       else
  326          urlp->url_flags |= n_URL_HOST_IS_NAME;
  327    }
  328 #  endif
  329 
  330    if (urlp->url_flags & n_URL_TLS_REQUIRED) {
  331       ohup = safe_signal(SIGHUP, &__sopen_onsig);
  332       oint = safe_signal(SIGINT, &__sopen_onsig);
  333       if (sigsetjmp(__sopen_actjmp, 0)) {
  334          n_err(_("%s during SSL/TLS handshake\n"),
  335             (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
  336          goto jsclose;
  337       }
  338       rele_sigs();
  339 
  340       if (ssl_open(urlp, sp) != OKAY) {
  341 jsclose:
  342          sclose(sp);
  343          sofd = -1;
  344       }
  345 
  346       hold_sigs();
  347       safe_signal(SIGINT, oint);
  348       safe_signal(SIGHUP, ohup);
  349    }
  350 
  351    rele_sigs();
  352 # endif /* HAVE_SSL */
  353 
  354 jleave:
  355    /* May need to bounce the signal to the go.c trampoline (or wherever) */
  356    if (__sopen_sig != 0) {
  357       sigset_t cset;
  358       sigemptyset(&cset);
  359       sigaddset(&cset, __sopen_sig);
  360       sigprocmask(SIG_UNBLOCK, &cset, NULL);
  361       n_raise(__sopen_sig);
  362    }
  363    NYD2_LEAVE;
  364    return (sofd >= 0);
  365 }
  366 
  367 static long
  368 a_socket_xwrite(int fd, char const *data, size_t sz)
  369 {
  370    long rv = -1, wo;
  371    size_t wt = 0;
  372    NYD_ENTER;
  373 
  374    do {
  375       if ((wo = write(fd, data + wt, sz - wt)) < 0) {
  376          if (n_err_no == n_ERR_INTR)
  377             continue;
  378          else
  379             goto jleave;
  380       }
  381       wt += wo;
  382    } while (wt < sz);
  383    rv = (long)sz;
  384 jleave:
  385    NYD_LEAVE;
  386    return rv;
  387 }
  388 
  389 FL int
  390 sclose(struct sock *sp)
  391 {
  392    int i;
  393    NYD_ENTER;
  394 
  395    i = sp->s_fd;
  396    sp->s_fd = -1;
  397    /* TODO NOTE: we MUST NOT close the descriptor 0 here...
  398     * TODO of course this should be handled in a VMAILFS->open() .s_fd=-1,
  399     * TODO but unfortunately it isn't yet */
  400    if (i <= 0)
  401       i = 0;
  402    else {
  403       if (sp->s_onclose != NULL)
  404          (*sp->s_onclose)();
  405       if (sp->s_wbuf != NULL)
  406          free(sp->s_wbuf);
  407 # ifdef HAVE_XSSL
  408       if (sp->s_use_ssl) {
  409          void *s_ssl = sp->s_ssl;
  410 
  411          sp->s_ssl = NULL;
  412          sp->s_use_ssl = 0;
  413          while (!SSL_shutdown(s_ssl)) /* XXX proper error handling;signals! */
  414             ;
  415          SSL_free(s_ssl);
  416       }
  417 # endif
  418       i = close(i);
  419    }
  420    NYD_LEAVE;
  421    return i;
  422 }
  423 
  424 FL enum okay
  425 swrite(struct sock *sp, char const *data)
  426 {
  427    enum okay rv;
  428    NYD2_ENTER;
  429 
  430    rv = swrite1(sp, data, strlen(data), 0);
  431    NYD2_LEAVE;
  432    return rv;
  433 }
  434 
  435 FL enum okay
  436 swrite1(struct sock *sp, char const *data, int sz, int use_buffer)
  437 {
  438    enum okay rv = STOP;
  439    int x;
  440    NYD2_ENTER;
  441 
  442    if (use_buffer > 0) {
  443       int di;
  444 
  445       if (sp->s_wbuf == NULL) {
  446          sp->s_wbufsize = 4096;
  447          sp->s_wbuf = smalloc(sp->s_wbufsize);
  448          sp->s_wbufpos = 0;
  449       }
  450       while (sp->s_wbufpos + sz > sp->s_wbufsize) {
  451          di = sp->s_wbufsize - sp->s_wbufpos;
  452          sz -= di;
  453          if (sp->s_wbufpos > 0) {
  454             memcpy(sp->s_wbuf + sp->s_wbufpos, data, di);
  455             rv = swrite1(sp, sp->s_wbuf, sp->s_wbufsize, -1);
  456          } else
  457             rv = swrite1(sp, data, sp->s_wbufsize, -1);
  458          if (rv != OKAY)
  459             goto jleave;
  460          data += di;
  461          sp->s_wbufpos = 0;
  462       }
  463       if (sz == sp->s_wbufsize) {
  464          rv = swrite1(sp, data, sp->s_wbufsize, -1);
  465          if (rv != OKAY)
  466             goto jleave;
  467       } else if (sz) {
  468          memcpy(sp->s_wbuf+ sp->s_wbufpos, data, sz);
  469          sp->s_wbufpos += sz;
  470       }
  471       rv = OKAY;
  472       goto jleave;
  473    } else if (use_buffer == 0 && sp->s_wbuf != NULL && sp->s_wbufpos > 0) {
  474       x = sp->s_wbufpos;
  475       sp->s_wbufpos = 0;
  476       if ((rv = swrite1(sp, sp->s_wbuf, x, -1)) != OKAY)
  477          goto jleave;
  478    }
  479    if (sz == 0) {
  480       rv = OKAY;
  481       goto jleave;
  482    }
  483 
  484 # ifdef HAVE_XSSL
  485    if (sp->s_use_ssl) {
  486 jssl_retry:
  487       x = SSL_write(sp->s_ssl, data, sz);
  488       if (x < 0) {
  489          switch (SSL_get_error(sp->s_ssl, x)) {
  490          case SSL_ERROR_WANT_READ:
  491          case SSL_ERROR_WANT_WRITE:
  492             goto jssl_retry;
  493          }
  494       }
  495    } else
  496 # endif
  497    {
  498       x = a_socket_xwrite(sp->s_fd, data, sz);
  499    }
  500    if (x != sz) {
  501       char o[512];
  502 
  503       snprintf(o, sizeof o, "%s write error",
  504          (sp->s_desc ? sp->s_desc : "socket"));
  505 # ifdef HAVE_XSSL
  506       if (sp->s_use_ssl)
  507          ssl_gen_err("%s", o);
  508       else
  509 # endif
  510          n_perr(o, 0);
  511       if (x < 0)
  512          sclose(sp);
  513       rv = STOP;
  514       goto jleave;
  515    }
  516    rv = OKAY;
  517 jleave:
  518    NYD2_LEAVE;
  519    return rv;
  520 }
  521 
  522 FL bool_t
  523 sopen(struct sock *sp, struct url *urlp){
  524    char const *cp;
  525    bool_t rv;
  526    NYD_ENTER;
  527 
  528    rv = FAL0;
  529 
  530    /* We may have a proxy configured */
  531    if((cp = xok_vlook(socks_proxy, urlp, OXM_ALL)) == NULL)
  532       rv = a_socket_open(sp, urlp);
  533    else{
  534       ui8_t pbuf[4 + 1 + 255 + 2];
  535       size_t i;
  536       char const *emsg;
  537       struct url url2;
  538 
  539       if(!url_parse(&url2, CPROTO_SOCKS, cp)){
  540          n_err(_("Failed to parse *socks-proxy*: %s\n"), cp);
  541          goto jleave;
  542       }
  543       if(urlp->url_host.l > 255){
  544          n_err(_("*socks-proxy*: hostname too long: %s\n"),
  545             urlp->url_input);
  546          goto jleave;
  547       }
  548 
  549       if (n_poption & n_PO_D_V)
  550          n_err(_("Connecting via *socks-proxy* to %s:%s ...\n"),
  551             urlp->url_host.s,
  552             (urlp->url_port != NULL ? urlp->url_port : urlp->url_proto));
  553 
  554       if(!a_socket_open(sp, &url2)){
  555          n_err(_("Failed to connect to *socks-proxy*: %s\n"), cp);
  556          goto jleave;
  557       }
  558 
  559       /* RFC 1928: version identifier/method selection message */
  560       pbuf[0] = 0x05; /* VER: protocol version: X'05' */
  561       pbuf[1] = 0x01; /* NMETHODS: 1 */
  562       pbuf[2] = 0x00; /* METHOD: X'00' NO AUTHENTICATION REQUIRED */
  563       if(write(sp->s_fd, pbuf, 3) != 3){
  564 jerrsocks:
  565          n_perr("*socks-proxy*", 0);
  566 jesocks:
  567          sclose(sp);
  568          goto jleave;
  569       }
  570 
  571       /* Receive greeting */
  572       if(read(sp->s_fd, pbuf, 2) != 2)
  573          goto jerrsocks;
  574       if(pbuf[0] != 0x05 || pbuf[1] != 0x00){
  575 jesocksreply:
  576          emsg = N_("unexpected reply\n");
  577 jesocksreplymsg:
  578          /* I18N: error message and failing URL */
  579          n_err(_("*socks-proxy*: %s: %s\n"), V_(emsg), cp);
  580          goto jesocks;
  581       }
  582 
  583       /* RFC 1928: CONNECT request */
  584       pbuf[0] = 0x05; /* VER: protocol version: X'05' */
  585       pbuf[1] = 0x01; /* CMD: CONNECT X'01' */
  586       pbuf[2] = 0x00; /* RESERVED */
  587       pbuf[3] = 0x03; /* ATYP: domain name */
  588       pbuf[4] = (ui8_t)urlp->url_host.l;
  589       memcpy(&pbuf[i = 5], urlp->url_host.s, urlp->url_host.l);
  590       /* C99 */{
  591          ui16_t x;
  592 
  593          x = htons(urlp->url_portno);
  594          memcpy(&pbuf[i += urlp->url_host.l], (ui8_t*)&x, sizeof x);
  595          i += sizeof x;
  596       }
  597       if(write(sp->s_fd, pbuf, i) != (ssize_t)i)
  598          goto jerrsocks;
  599 
  600       /* Connect result */
  601       if((i = read(sp->s_fd, pbuf, 4)) != 4)
  602          goto jerrsocks;
  603       /* Version 5, reserved must be 0 */
  604       if(pbuf[0] != 0x05 || pbuf[2] != 0x00)
  605          goto jesocksreply;
  606       /* Result */
  607       switch(pbuf[1]){
  608       case 0x00: emsg = NULL; break;
  609       case 0x01: emsg = N_("SOCKS server failure"); break;
  610       case 0x02: emsg = N_("connection not allowed by ruleset"); break;
  611       case 0x03: emsg = N_("network unreachable"); break;
  612       case 0x04: emsg = N_("host unreachable"); break;
  613       case 0x05: emsg = N_("connection refused"); break;
  614       case 0x06: emsg = N_("TTL expired"); break;
  615       case 0x07: emsg = N_("command not supported"); break;
  616       case 0x08: emsg = N_("address type not supported"); break;
  617       default: emsg = N_("unknown SOCKS error code"); break;
  618       }
  619       if(emsg != NULL)
  620          goto jesocksreplymsg;
  621 
  622       /* Address type variable; read the BND.PORT with it.
  623        * This is actually false since RFC 1928 says that the BND.ADDR reply to
  624        * CONNECT contains the IP address, so only 0x01 and 0x04 are allowed */
  625       switch(pbuf[3]){
  626       case 0x01: i = 4; break;
  627       case 0x03: i = 1; break;
  628       case 0x04: i = 16; break;
  629       default: goto jesocksreply;
  630       }
  631       i += sizeof(ui16_t);
  632       if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
  633          goto jerrsocks;
  634       if(i == 1 + sizeof(ui16_t)){
  635          i = pbuf[0];
  636          if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
  637             goto jerrsocks;
  638       }
  639       rv = TRU1;
  640    }
  641 jleave:
  642    NYD_LEAVE;
  643    return rv;
  644 }
  645 
  646 FL int
  647 (sgetline)(char **line, size_t *linesize, size_t *linelen, struct sock *sp
  648    n_MEMORY_DEBUG_ARGS)
  649 {
  650    int rv;
  651    size_t lsize;
  652    char *lp_base, *lp;
  653    NYD2_ENTER;
  654 
  655    lsize = *linesize;
  656    lp_base = *line;
  657    lp = lp_base;
  658 
  659    if (sp->s_rsz < 0) {
  660       sclose(sp);
  661       rv = sp->s_rsz;
  662       goto jleave;
  663    }
  664 
  665    do {
  666       if (lp_base == NULL || PTRCMP(lp, >, lp_base + lsize - 128)) {
  667          size_t diff = PTR2SIZE(lp - lp_base);
  668          *linesize = (lsize += 256); /* XXX magic */
  669          *line = lp_base = (n_realloc)(lp_base, lsize n_MEMORY_DEBUG_ARGSCALL);
  670          lp = lp_base + diff;
  671       }
  672 
  673       if (sp->s_rbufptr == NULL ||
  674             PTRCMP(sp->s_rbufptr, >=, sp->s_rbuf + sp->s_rsz)) {
  675 # ifdef HAVE_XSSL
  676          if (sp->s_use_ssl) {
  677 jssl_retry:
  678             sp->s_rsz = SSL_read(sp->s_ssl, sp->s_rbuf, sizeof sp->s_rbuf);
  679             if (sp->s_rsz <= 0) {
  680                if (sp->s_rsz < 0) {
  681                   char o[512];
  682 
  683                   switch(SSL_get_error(sp->s_ssl, sp->s_rsz)) {
  684                   case SSL_ERROR_WANT_READ:
  685                   case SSL_ERROR_WANT_WRITE:
  686                      goto jssl_retry;
  687                   }
  688                   snprintf(o, sizeof o, "%s",
  689                      (sp->s_desc ?  sp->s_desc : "socket"));
  690                   ssl_gen_err("%s", o);
  691                }
  692                break;
  693             }
  694          } else
  695 # endif
  696          {
  697 jagain:
  698             sp->s_rsz = read(sp->s_fd, sp->s_rbuf, sizeof sp->s_rbuf);
  699             if (sp->s_rsz <= 0) {
  700                if (sp->s_rsz < 0) {
  701                   char o[512];
  702 
  703                   if (n_err_no == n_ERR_INTR)
  704                      goto jagain;
  705                   snprintf(o, sizeof o, "%s",
  706                      (sp->s_desc ?  sp->s_desc : "socket"));
  707                   n_perr(o, 0);
  708                }
  709                break;
  710             }
  711          }
  712          sp->s_rbufptr = sp->s_rbuf;
  713       }
  714    } while ((*lp++ = *sp->s_rbufptr++) != '\n');
  715    *lp = '\0';
  716    lsize = PTR2SIZE(lp - lp_base);
  717 
  718    if (linelen)
  719       *linelen = lsize;
  720    rv = (int)lsize;
  721 jleave:
  722    NYD2_LEAVE;
  723    return rv;
  724 }
  725 #endif /* HAVE_SOCKETS */
  726 
  727 /* s-it-mode */