gen-okeys.h: regenerate
[s-mailx.git] / socket.c
blob7d25ac9a59bc1cc7186b164d61cfcadc088643ee
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Socket operations.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 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.
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.
32 #undef n_FILE
33 #define n_FILE socket
35 #ifndef HAVE_AMALGAMATION
36 # include "nail.h"
37 #endif
39 EMPTY_FILE()
40 #ifdef HAVE_SOCKETS
41 #include <sys/socket.h>
43 #include <netdb.h>
45 #include <netinet/in.h>
47 #ifdef HAVE_ARPA_INET_H
48 # include <arpa/inet.h>
49 #endif
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
59 /* */
60 static bool_t a_socket_open(struct sock *sp, struct url *urlp);
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);
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 */
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);
81 static bool_t
82 a_socket_open(struct sock *sp, struct url *urlp) /* TODO sigstuff; refactor */
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 char hbuf[NI_MAXHOST];
92 struct addrinfo hints, *res0 = NULL, *res;
93 # else
94 struct sockaddr_in servaddr;
95 struct in_addr **pptr;
96 struct hostent *hp;
97 struct servent *ep;
98 # endif
99 sighandler_type volatile ohup, oint;
100 char const * volatile serv;
101 int volatile sofd = -1, errval;
102 NYD2_ENTER;
104 n_UNINIT(errval, 0);
106 /* Connect timeouts after 30 seconds XXX configurable */
107 # ifdef HAVE_SO_SNDTIMEO
108 tv.tv_sec = 30;
109 tv.tv_usec = 0;
110 # endif
111 serv = (urlp->url_port != NULL) ? urlp->url_port : urlp->url_proto;
113 if (n_poption & n_PO_D_V)
114 n_err(_("Resolving host %s:%s ... "), urlp->url_host.s, serv);
116 /* Signal handling (in respect to __sopen_sig dealing) is heavy, but no
117 * healing until v15.0 and i want to end up with that functionality */
118 hold_sigs();
119 __sopen_sig = 0;
120 ohup = safe_signal(SIGHUP, &__sopen_onsig);
121 oint = safe_signal(SIGINT, &__sopen_onsig);
122 if (sigsetjmp(__sopen_actjmp, 0)) {
123 jpseudo_jump:
124 n_err("%s\n",
125 (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
126 if (sofd >= 0) {
127 close(sofd);
128 sofd = -1;
130 goto jjumped;
132 rele_sigs();
134 # ifdef HAVE_GETADDRINFO
135 for (;;) {
136 memset(&hints, 0, sizeof hints);
137 hints.ai_socktype = SOCK_STREAM;
138 __sopen_sig = -1;
139 errval = getaddrinfo(urlp->url_host.s, serv, &hints, &res0);
140 if (__sopen_sig != -1) {
141 __sopen_sig = SIGINT;
142 goto jpseudo_jump;
144 __sopen_sig = 0;
145 if (errval == 0)
146 break;
148 if (n_poption & n_PO_D_V)
149 n_err(_("failed\n"));
150 n_err(_("Lookup of %s:%s failed: %s\n"),
151 urlp->url_host.s, serv, gai_strerror(errval));
153 /* Error seems to depend on how "smart" the /etc/service code is: is it
154 * "able" to state whether the service as such is NONAME or does it only
155 * check for the given ai_socktype.. */
156 if (errval == EAI_NONAME || errval == EAI_SERVICE) {
157 if (serv == urlp->url_proto &&
158 (serv = n_servbyname(urlp->url_proto, NULL)) != NULL &&
159 *serv != '\0') {
160 n_err(_(" Trying standard protocol port %s\n"), serv);
161 n_err(_(" If that succeeds consider including the "
162 "port in the URL!\n"));
163 continue;
165 if (serv != urlp->url_port)
166 n_err(_(" Including a port number in the URL may "
167 "circumvent this problem\n"));
169 assert(sofd == -1);
170 errval = 0;
171 goto jjumped;
173 if (n_poption & n_PO_D_V)
174 n_err(_("done\n"));
176 for (res = res0; res != NULL && sofd < 0; res = res->ai_next) {
177 if (n_poption & n_PO_D_V) {
178 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf,
179 NULL, 0, NI_NUMERICHOST))
180 memcpy(hbuf, "unknown host", sizeof("unknown host"));
181 n_err(_("%sConnecting to %s:%s ... "),
182 (res == res0 ? n_empty : "\n"), hbuf, serv);
185 sofd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
186 if (sofd >= 0) {
187 # ifdef HAVE_SO_SNDTIMEO
188 (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
189 # endif
190 if (connect(sofd, res->ai_addr, res->ai_addrlen)) {
191 errval = n_err_no;
192 close(sofd);
193 sofd = -1;
198 jjumped:
199 if (res0 != NULL) {
200 freeaddrinfo(res0);
201 res0 = NULL;
204 # else /* HAVE_GETADDRINFO */
205 if (serv == urlp->url_proto) {
206 if ((ep = getservbyname(n_UNCONST(serv), "tcp")) != NULL)
207 urlp->url_portno = ntohs(ep->s_port);
208 else {
209 if (n_poption & n_PO_D_V)
210 n_err(_("failed\n"));
211 if ((serv = n_servbyname(urlp->url_proto, &urlp->url_portno)) != NULL)
212 n_err(_(" Unknown service: %s\n"), urlp->url_proto);
213 n_err(_(" Trying standard protocol port %s\n"), serv);
214 n_err(_(" If that succeeds consider including the "
215 "port in the URL!\n"));
216 else {
217 n_err(_(" Unknown service: %s\n"), urlp->url_proto);
218 n_err(_(" Including a port number in the URL may "
219 "circumvent this problem\n"));
220 assert(sofd == -1 && errval == 0);
221 goto jjumped;
226 __sopen_sig = -1;
227 hp = gethostbyname(urlp->url_host.s);
228 if (__sopen_sig != -1) {
229 __sopen_sig = SIGINT;
230 goto jpseudo_jump;
232 __sopen_sig = 0;
234 if (hp == NULL) {
235 char const *emsg;
237 if (n_poption & n_PO_D_V)
238 n_err(_("failed\n"));
239 switch (h_errno) {
240 case HOST_NOT_FOUND: emsg = N_("host not found"); break;
241 default:
242 case TRY_AGAIN: emsg = N_("(maybe) try again later"); break;
243 case NO_RECOVERY: emsg = N_("non-recoverable server error"); break;
244 case NO_DATA: emsg = N_("valid name without IP address"); break;
246 n_err(_("Lookup of %s:%s failed: %s\n"),
247 urlp->url_host.s, serv, V_(emsg));
248 goto jjumped;
249 } else if (n_poption & n_PO_D_V)
250 n_err(_("done\n"));
252 pptr = (struct in_addr**)hp->h_addr_list;
253 if ((sofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
254 n_perr(_("could not create socket"), 0);
255 assert(sofd == -1 && errval == 0);
256 goto jjumped;
259 memset(&servaddr, 0, sizeof servaddr);
260 servaddr.sin_family = AF_INET;
261 servaddr.sin_port = htons(urlp->url_portno);
262 memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
263 if (n_poption & n_PO_D_V)
264 n_err(_("%sConnecting to %s:%d ... "),
265 n_empty, inet_ntoa(**pptr), (int)urlp->url_portno);
266 # ifdef HAVE_SO_SNDTIMEO
267 (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
268 # endif
269 if (connect(sofd, (struct sockaddr*)&servaddr, sizeof servaddr)) {
270 errval = n_err_no;
271 close(sofd);
272 sofd = -1;
274 jjumped:
275 # endif /* !HAVE_GETADDRINFO */
277 hold_sigs();
278 safe_signal(SIGINT, oint);
279 safe_signal(SIGHUP, ohup);
280 rele_sigs();
282 if (sofd < 0) {
283 if (errval != 0) {
284 n_err_no = errval;
285 n_perr(_("Could not connect"), 0);
287 goto jleave;
290 if (n_poption & n_PO_D_V)
291 n_err(_("connected.\n"));
293 /* And the regular timeouts XXX configurable */
294 # ifdef HAVE_SO_SNDTIMEO
295 tv.tv_sec = 42;
296 tv.tv_usec = 0;
297 (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
298 (void)setsockopt(sofd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
299 # endif
300 # ifdef HAVE_SO_LINGER
301 li.l_onoff = 1;
302 li.l_linger = 42;
303 (void)setsockopt(sofd, SOL_SOCKET, SO_LINGER, &li, sizeof li);
304 # endif
306 memset(sp, 0, sizeof *sp);
307 sp->s_fd = sofd;
309 /* SSL/TLS upgrade? */
310 # ifdef HAVE_SSL
311 hold_sigs();
313 # if defined HAVE_GETADDRINFO && defined SSL_CTRL_SET_TLSEXT_HOSTNAME /* TODO
314 * TODO the SSL_ def check should NOT be here */
315 if(urlp->url_flags & n_URL_TLS_MASK){
316 memset(&hints, 0, sizeof hints);
317 hints.ai_family = AF_UNSPEC;
318 hints.ai_flags = AI_NUMERICHOST;
319 res0 = NULL;
320 if(getaddrinfo(urlp->url_host.s, NULL, &hints, &res0) == 0)
321 freeaddrinfo(res0);
322 else
323 urlp->url_flags |= n_URL_HOST_IS_NAME;
325 # endif
327 if (urlp->url_flags & n_URL_TLS_REQUIRED) {
328 ohup = safe_signal(SIGHUP, &__sopen_onsig);
329 oint = safe_signal(SIGINT, &__sopen_onsig);
330 if (sigsetjmp(__sopen_actjmp, 0)) {
331 n_err(_("%s during SSL/TLS handshake\n"),
332 (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
333 goto jsclose;
335 rele_sigs();
337 if (ssl_open(urlp, sp) != OKAY) {
338 jsclose:
339 sclose(sp);
340 sofd = -1;
343 hold_sigs();
344 safe_signal(SIGINT, oint);
345 safe_signal(SIGHUP, ohup);
348 rele_sigs();
349 # endif /* HAVE_SSL */
351 jleave:
352 /* May need to bounce the signal to the go.c trampoline (or wherever) */
353 if (__sopen_sig != 0) {
354 sigset_t cset;
355 sigemptyset(&cset);
356 sigaddset(&cset, __sopen_sig);
357 sigprocmask(SIG_UNBLOCK, &cset, NULL);
358 n_raise(__sopen_sig);
360 NYD2_LEAVE;
361 return (sofd >= 0);
364 static long
365 a_socket_xwrite(int fd, char const *data, size_t sz)
367 long rv = -1, wo;
368 size_t wt = 0;
369 NYD_ENTER;
371 do {
372 if ((wo = write(fd, data + wt, sz - wt)) < 0) {
373 if (n_err_no == n_ERR_INTR)
374 continue;
375 else
376 goto jleave;
378 wt += wo;
379 } while (wt < sz);
380 rv = (long)sz;
381 jleave:
382 NYD_LEAVE;
383 return rv;
386 FL int
387 sclose(struct sock *sp)
389 int i;
390 NYD_ENTER;
392 i = sp->s_fd;
393 sp->s_fd = -1;
394 /* TODO NOTE: we MUST NOT close the descriptor 0 here...
395 * TODO of course this should be handled in a VMAILFS->open() .s_fd=-1,
396 * TODO but unfortunately it isn't yet */
397 if (i <= 0)
398 i = 0;
399 else {
400 if (sp->s_onclose != NULL)
401 (*sp->s_onclose)();
402 if (sp->s_wbuf != NULL)
403 free(sp->s_wbuf);
404 # ifdef HAVE_XSSL
405 if (sp->s_use_ssl) {
406 void *s_ssl = sp->s_ssl;
408 sp->s_ssl = NULL;
409 sp->s_use_ssl = 0;
410 while (!SSL_shutdown(s_ssl)) /* XXX proper error handling;signals! */
412 SSL_free(s_ssl);
414 # endif
415 i = close(i);
417 NYD_LEAVE;
418 return i;
421 FL enum okay
422 swrite(struct sock *sp, char const *data)
424 enum okay rv;
425 NYD2_ENTER;
427 rv = swrite1(sp, data, strlen(data), 0);
428 NYD2_LEAVE;
429 return rv;
432 FL enum okay
433 swrite1(struct sock *sp, char const *data, int sz, int use_buffer)
435 enum okay rv = STOP;
436 int x;
437 NYD2_ENTER;
439 if (use_buffer > 0) {
440 int di;
442 if (sp->s_wbuf == NULL) {
443 sp->s_wbufsize = 4096;
444 sp->s_wbuf = smalloc(sp->s_wbufsize);
445 sp->s_wbufpos = 0;
447 while (sp->s_wbufpos + sz > sp->s_wbufsize) {
448 di = sp->s_wbufsize - sp->s_wbufpos;
449 sz -= di;
450 if (sp->s_wbufpos > 0) {
451 memcpy(sp->s_wbuf + sp->s_wbufpos, data, di);
452 rv = swrite1(sp, sp->s_wbuf, sp->s_wbufsize, -1);
453 } else
454 rv = swrite1(sp, data, sp->s_wbufsize, -1);
455 if (rv != OKAY)
456 goto jleave;
457 data += di;
458 sp->s_wbufpos = 0;
460 if (sz == sp->s_wbufsize) {
461 rv = swrite1(sp, data, sp->s_wbufsize, -1);
462 if (rv != OKAY)
463 goto jleave;
464 } else if (sz) {
465 memcpy(sp->s_wbuf+ sp->s_wbufpos, data, sz);
466 sp->s_wbufpos += sz;
468 rv = OKAY;
469 goto jleave;
470 } else if (use_buffer == 0 && sp->s_wbuf != NULL && sp->s_wbufpos > 0) {
471 x = sp->s_wbufpos;
472 sp->s_wbufpos = 0;
473 if ((rv = swrite1(sp, sp->s_wbuf, x, -1)) != OKAY)
474 goto jleave;
476 if (sz == 0) {
477 rv = OKAY;
478 goto jleave;
481 # ifdef HAVE_XSSL
482 if (sp->s_use_ssl) {
483 jssl_retry:
484 x = SSL_write(sp->s_ssl, data, sz);
485 if (x < 0) {
486 switch (SSL_get_error(sp->s_ssl, x)) {
487 case SSL_ERROR_WANT_READ:
488 case SSL_ERROR_WANT_WRITE:
489 goto jssl_retry;
492 } else
493 # endif
495 x = a_socket_xwrite(sp->s_fd, data, sz);
497 if (x != sz) {
498 char o[512];
500 snprintf(o, sizeof o, "%s write error",
501 (sp->s_desc ? sp->s_desc : "socket"));
502 # ifdef HAVE_XSSL
503 if (sp->s_use_ssl)
504 ssl_gen_err("%s", o);
505 else
506 # endif
507 n_perr(o, 0);
508 if (x < 0)
509 sclose(sp);
510 rv = STOP;
511 goto jleave;
513 rv = OKAY;
514 jleave:
515 NYD2_LEAVE;
516 return rv;
519 FL bool_t
520 sopen(struct sock *sp, struct url *urlp){
521 char const *cp;
522 bool_t rv;
523 NYD_ENTER;
525 rv = FAL0;
527 /* We may have a proxy configured */
528 if((cp = xok_vlook(socks_proxy, urlp, OXM_ALL)) == NULL)
529 rv = a_socket_open(sp, urlp);
530 else{
531 ui8_t pbuf[4 + 1 + 255 + 2];
532 size_t i;
533 char const *emsg;
534 struct url url2;
536 if(!url_parse(&url2, CPROTO_SOCKS, cp)){
537 n_err(_("Failed to parse *socks-proxy*: %s\n"), cp);
538 goto jleave;
540 if(urlp->url_host.l > 255){
541 n_err(_("*socks-proxy*: hostname too long: %s\n"),
542 urlp->url_input);
543 goto jleave;
546 if (n_poption & n_PO_D_V)
547 n_err(_("Connecting via *socks-proxy* to %s:%s ...\n"),
548 urlp->url_host.s,
549 (urlp->url_port != NULL ? urlp->url_port : urlp->url_proto));
551 if(!a_socket_open(sp, &url2)){
552 n_err(_("Failed to connect to *socks-proxy*: %s\n"), cp);
553 goto jleave;
556 /* RFC 1928: version identifier/method selection message */
557 pbuf[0] = 0x05; /* VER: protocol version: X'05' */
558 pbuf[1] = 0x01; /* NMETHODS: 1 */
559 pbuf[2] = 0x00; /* METHOD: X'00' NO AUTHENTICATION REQUIRED */
560 if(write(sp->s_fd, pbuf, 3) != 3){
561 jerrsocks:
562 n_perr("*socks-proxy*", 0);
563 jesocks:
564 sclose(sp);
565 goto jleave;
568 /* Receive greeting */
569 if(read(sp->s_fd, pbuf, 2) != 2)
570 goto jerrsocks;
571 if(pbuf[0] != 0x05 || pbuf[1] != 0x00){
572 jesocksreply:
573 emsg = N_("unexpected reply\n");
574 jesocksreplymsg:
575 /* I18N: error message and failing URL */
576 n_err(_("*socks-proxy*: %s: %s\n"), V_(emsg), cp);
577 goto jesocks;
580 /* RFC 1928: CONNECT request */
581 pbuf[0] = 0x05; /* VER: protocol version: X'05' */
582 pbuf[1] = 0x01; /* CMD: CONNECT X'01' */
583 pbuf[2] = 0x00; /* RESERVED */
584 pbuf[3] = 0x03; /* ATYP: domain name */
585 pbuf[4] = (ui8_t)urlp->url_host.l;
586 memcpy(&pbuf[i = 5], urlp->url_host.s, urlp->url_host.l);
587 /* C99 */{
588 ui16_t x;
590 x = htons(urlp->url_portno);
591 memcpy(&pbuf[i += urlp->url_host.l], (ui8_t*)&x, sizeof x);
592 i += sizeof x;
594 if(write(sp->s_fd, pbuf, i) != (ssize_t)i)
595 goto jerrsocks;
597 /* Connect result */
598 if((i = read(sp->s_fd, pbuf, 4)) != 4)
599 goto jerrsocks;
600 /* Version 5, reserved must be 0 */
601 if(pbuf[0] != 0x05 || pbuf[2] != 0x00)
602 goto jesocksreply;
603 /* Result */
604 switch(pbuf[1]){
605 case 0x00: emsg = NULL; break;
606 case 0x01: emsg = N_("SOCKS server failure"); break;
607 case 0x02: emsg = N_("connection not allowed by ruleset"); break;
608 case 0x03: emsg = N_("network unreachable"); break;
609 case 0x04: emsg = N_("host unreachable"); break;
610 case 0x05: emsg = N_("connection refused"); break;
611 case 0x06: emsg = N_("TTL expired"); break;
612 case 0x07: emsg = N_("command not supported"); break;
613 case 0x08: emsg = N_("address type not supported"); break;
614 default: emsg = N_("unknown SOCKS error code"); break;
616 if(emsg != NULL)
617 goto jesocksreplymsg;
619 /* Address type variable; read the BND.PORT with it.
620 * This is actually false since RFC 1928 says that the BND.ADDR reply to
621 * CONNECT contains the IP address, so only 0x01 and 0x04 are allowed */
622 switch(pbuf[3]){
623 case 0x01: i = 4; break;
624 case 0x03: i = 1; break;
625 case 0x04: i = 16; break;
626 default: goto jesocksreply;
628 i += sizeof(ui16_t);
629 if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
630 goto jerrsocks;
631 if(i == 1 + sizeof(ui16_t)){
632 i = pbuf[0];
633 if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
634 goto jerrsocks;
636 rv = TRU1;
638 jleave:
639 NYD_LEAVE;
640 return rv;
643 FL int
644 (sgetline)(char **line, size_t *linesize, size_t *linelen, struct sock *sp
645 n_MEMORY_DEBUG_ARGS)
647 int rv;
648 size_t lsize;
649 char *lp_base, *lp;
650 NYD2_ENTER;
652 lsize = *linesize;
653 lp_base = *line;
654 lp = lp_base;
656 if (sp->s_rsz < 0) {
657 sclose(sp);
658 rv = sp->s_rsz;
659 goto jleave;
662 do {
663 if (lp_base == NULL || PTRCMP(lp, >, lp_base + lsize - 128)) {
664 size_t diff = PTR2SIZE(lp - lp_base);
665 *linesize = (lsize += 256); /* XXX magic */
666 *line = lp_base = (n_realloc)(lp_base, lsize n_MEMORY_DEBUG_ARGSCALL);
667 lp = lp_base + diff;
670 if (sp->s_rbufptr == NULL ||
671 PTRCMP(sp->s_rbufptr, >=, sp->s_rbuf + sp->s_rsz)) {
672 # ifdef HAVE_XSSL
673 if (sp->s_use_ssl) {
674 jssl_retry:
675 sp->s_rsz = SSL_read(sp->s_ssl, sp->s_rbuf, sizeof sp->s_rbuf);
676 if (sp->s_rsz <= 0) {
677 if (sp->s_rsz < 0) {
678 char o[512];
680 switch(SSL_get_error(sp->s_ssl, sp->s_rsz)) {
681 case SSL_ERROR_WANT_READ:
682 case SSL_ERROR_WANT_WRITE:
683 goto jssl_retry;
685 snprintf(o, sizeof o, "%s",
686 (sp->s_desc ? sp->s_desc : "socket"));
687 ssl_gen_err("%s", o);
689 break;
691 } else
692 # endif
694 jagain:
695 sp->s_rsz = read(sp->s_fd, sp->s_rbuf, sizeof sp->s_rbuf);
696 if (sp->s_rsz <= 0) {
697 if (sp->s_rsz < 0) {
698 char o[512];
700 if (n_err_no == n_ERR_INTR)
701 goto jagain;
702 snprintf(o, sizeof o, "%s",
703 (sp->s_desc ? sp->s_desc : "socket"));
704 n_perr(o, 0);
706 break;
709 sp->s_rbufptr = sp->s_rbuf;
711 } while ((*lp++ = *sp->s_rbufptr++) != '\n');
712 *lp = '\0';
713 lsize = PTR2SIZE(lp - lp_base);
715 if (linelen)
716 *linelen = lsize;
717 rv = (int)lsize;
718 jleave:
719 NYD2_LEAVE;
720 return rv;
722 #endif /* HAVE_SOCKETS */
724 /* s-it-mode */