quoteflt_dummy() usage: FIX usage without preceeding _reset() (Jürgen Bruckner)
[s-mailx.git] / socket.c
bloba9fd1ab475dc237a3cdf229c48c3a71e234ab42e
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 - 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.
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 # 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;
107 n_UNINIT(errval, 0);
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;
116 if (n_poption & n_PO_D_V)
117 n_err(_("Resolving host %s:%s ... "), urlp->url_host.s, serv);
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;
133 goto jjumped;
135 rele_sigs();
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;
147 __sopen_sig = 0;
148 if (errval == 0)
149 break;
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));
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;
168 if (serv != urlp->url_port)
169 n_err(_(" Including a port number in the URL may "
170 "circumvent this problem\n"));
172 assert(sofd == -1);
173 errval = 0;
174 goto jjumped;
176 if (n_poption & n_PO_D_V)
177 n_err(_("done\n"));
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);
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;
201 jjumped:
202 if (res0 != NULL) {
203 freeaddrinfo(res0);
204 res0 = NULL;
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;
229 __sopen_sig = -1;
230 hp = gethostbyname(urlp->url_host.s);
231 if (__sopen_sig != -1) {
232 __sopen_sig = SIGINT;
233 goto jpseudo_jump;
235 __sopen_sig = 0;
237 if (hp == NULL) {
238 char const *emsg;
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;
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"));
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;
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;
277 jjumped:
278 # endif /* !HAVE_GETADDRINFO */
280 hold_sigs();
281 safe_signal(SIGINT, oint);
282 safe_signal(SIGHUP, ohup);
283 rele_sigs();
285 if (sofd < 0) {
286 if (errval != 0) {
287 n_err_no = errval;
288 n_perr(_("Could not connect"), 0);
290 goto jleave;
293 if (n_poption & n_PO_D_V)
294 n_err(_("connected.\n"));
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
309 memset(sp, 0, sizeof *sp);
310 sp->s_fd = sofd;
312 /* SSL/TLS upgrade? */
313 # ifdef HAVE_SSL
314 hold_sigs();
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;
328 # endif
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;
338 rele_sigs();
340 if (ssl_open(urlp, sp) != OKAY) {
341 jsclose:
342 sclose(sp);
343 sofd = -1;
346 hold_sigs();
347 safe_signal(SIGINT, oint);
348 safe_signal(SIGHUP, ohup);
351 rele_sigs();
352 # endif /* HAVE_SSL */
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);
363 NYD2_LEAVE;
364 return (sofd >= 0);
367 static long
368 a_socket_xwrite(int fd, char const *data, size_t sz)
370 long rv = -1, wo;
371 size_t wt = 0;
372 NYD_ENTER;
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;
381 wt += wo;
382 } while (wt < sz);
383 rv = (long)sz;
384 jleave:
385 NYD_LEAVE;
386 return rv;
389 FL int
390 sclose(struct sock *sp)
392 int i;
393 NYD_ENTER;
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;
411 sp->s_ssl = NULL;
412 sp->s_use_ssl = 0;
413 while (!SSL_shutdown(s_ssl)) /* XXX proper error handling;signals! */
415 SSL_free(s_ssl);
417 # endif
418 i = close(i);
420 NYD_LEAVE;
421 return i;
424 FL enum okay
425 swrite(struct sock *sp, char const *data)
427 enum okay rv;
428 NYD2_ENTER;
430 rv = swrite1(sp, data, strlen(data), 0);
431 NYD2_LEAVE;
432 return rv;
435 FL enum okay
436 swrite1(struct sock *sp, char const *data, int sz, int use_buffer)
438 enum okay rv = STOP;
439 int x;
440 NYD2_ENTER;
442 if (use_buffer > 0) {
443 int di;
445 if (sp->s_wbuf == NULL) {
446 sp->s_wbufsize = 4096;
447 sp->s_wbuf = smalloc(sp->s_wbufsize);
448 sp->s_wbufpos = 0;
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;
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;
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;
479 if (sz == 0) {
480 rv = OKAY;
481 goto jleave;
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;
495 } else
496 # endif
498 x = a_socket_xwrite(sp->s_fd, data, sz);
500 if (x != sz) {
501 char o[512];
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;
516 rv = OKAY;
517 jleave:
518 NYD2_LEAVE;
519 return rv;
522 FL bool_t
523 sopen(struct sock *sp, struct url *urlp){
524 char const *cp;
525 bool_t rv;
526 NYD_ENTER;
528 rv = FAL0;
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;
539 if(!url_parse(&url2, CPROTO_SOCKS, cp)){
540 n_err(_("Failed to parse *socks-proxy*: %s\n"), cp);
541 goto jleave;
543 if(urlp->url_host.l > 255){
544 n_err(_("*socks-proxy*: hostname too long: %s\n"),
545 urlp->url_input);
546 goto jleave;
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));
554 if(!a_socket_open(sp, &url2)){
555 n_err(_("Failed to connect to *socks-proxy*: %s\n"), cp);
556 goto jleave;
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;
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;
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;
593 x = htons(urlp->url_portno);
594 memcpy(&pbuf[i += urlp->url_host.l], (ui8_t*)&x, sizeof x);
595 i += sizeof x;
597 if(write(sp->s_fd, pbuf, i) != (ssize_t)i)
598 goto jerrsocks;
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;
619 if(emsg != NULL)
620 goto jesocksreplymsg;
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;
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;
639 rv = TRU1;
641 jleave:
642 NYD_LEAVE;
643 return rv;
646 FL int
647 (sgetline)(char **line, size_t *linesize, size_t *linelen, struct sock *sp
648 n_MEMORY_DEBUG_ARGS)
650 int rv;
651 size_t lsize;
652 char *lp_base, *lp;
653 NYD2_ENTER;
655 lsize = *linesize;
656 lp_base = *line;
657 lp = lp_base;
659 if (sp->s_rsz < 0) {
660 sclose(sp);
661 rv = sp->s_rsz;
662 goto jleave;
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;
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];
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;
688 snprintf(o, sizeof o, "%s",
689 (sp->s_desc ? sp->s_desc : "socket"));
690 ssl_gen_err("%s", o);
692 break;
694 } else
695 # endif
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];
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);
709 break;
712 sp->s_rbufptr = sp->s_rbuf;
714 } while ((*lp++ = *sp->s_rbufptr++) != '\n');
715 *lp = '\0';
716 lsize = PTR2SIZE(lp - lp_base);
718 if (linelen)
719 *linelen = lsize;
720 rv = (int)lsize;
721 jleave:
722 NYD2_LEAVE;
723 return rv;
725 #endif /* HAVE_SOCKETS */
727 /* s-it-mode */