For /dev/mem, map in memory to be copied to memory's own address space
[minix3.git] / lib / ip / res_send.c
blob1c6dbe4c1f2eefbc86bd79750dc8bea9a57798a4
1 /*
2 * Copyright (c) 1985, 1989 Regents of the University of California.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
36 #endif /* LIBC_SCCS and not lint */
39 * Send query to name server and wait for reply.
42 #if !_MINIX
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <sys/uio.h>
47 #include <netinet/in.h>
48 #include <arpa/nameser.h>
49 #include <stdio.h>
50 #include <errno.h>
51 #include <resolv.h>
52 #include <unistd.h>
53 #include <string.h>
55 #else /* _MINIX */
57 #include <sys/types.h>
58 #include <sys/ioctl.h>
59 #include <sys/stat.h>
60 #include <assert.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
69 #include <net/hton.h>
71 #include <net/netlib.h>
72 #include <net/gen/in.h>
73 #include <net/gen/inet.h>
74 #include <net/gen/netdb.h>
75 #include <net/gen/nameser.h>
76 #include <net/gen/resolv.h>
77 #include <net/gen/tcp.h>
78 #include <net/gen/tcp_io.h>
79 #include <net/gen/udp.h>
80 #include <net/gen/udp_hdr.h>
81 #include <net/gen/udp_io.h>
83 static int tcp_connect _ARGS(( ipaddr_t host, Tcpport_t port, int *terrno ));
84 static int tcpip_writeall _ARGS(( int fd, const char *buf, size_t siz ));
85 static int udp_connect _ARGS(( void ));
86 static int udp_sendto _ARGS(( int fd, const char *buf, unsigned buflen,
87 ipaddr_t addr, Udpport_t port ));
88 static int udp_receive _ARGS(( int fd, char *buf, unsigned buflen,
89 time_t timeout ));
90 static void alarm_handler _ARGS(( int sig ));
92 #endif /* !_MINIX */
94 static int s = -1; /* socket used for communications */
95 #if !_MINIX
96 static struct sockaddr no_addr;
98 #ifndef FD_SET
99 #define NFDBITS 32
100 #define FD_SETSIZE 32
101 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
102 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
103 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
104 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
105 #endif /* FD_SET */
106 #endif /* _MINIX */
108 res_send(buf, buflen, answer, anslen)
109 const char *buf;
110 int buflen;
111 char *answer;
112 int anslen;
114 register int n;
115 int try, v_circuit, resplen, ns;
116 int gotsomewhere = 0, connected = 0;
117 int connreset = 0;
118 #if !_MINIX
119 u_short id, len;
120 #else /* _MINIX */
121 u16_t id, len;
122 #endif /* !_MINIX */
123 char *cp;
124 #if !_MINIX
125 fd_set dsmask;
126 struct timeval timeout;
127 HEADER *hp = (HEADER *) buf;
128 HEADER *anhp = (HEADER *) answer;
129 struct iovec iov[2];
130 #else /* _MINIX */
131 time_t timeout;
132 dns_hdr_t *hp = (dns_hdr_t *) buf;
133 dns_hdr_t *anhp = (dns_hdr_t *) answer;
134 #endif /* !_MINIX */
135 int terrno = ETIMEDOUT;
136 char junk[512];
138 #ifdef DEBUG
139 if (_res.options & RES_DEBUG) {
140 printf("res_send()\n");
141 __p_query(buf);
143 #endif /* DEBUG */
144 if (!(_res.options & RES_INIT))
145 if (res_init() == -1) {
146 return(-1);
149 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
150 #if !_MINIX
151 id = hp->id;
152 #else /* _MINIX */
153 id = hp->dh_id;
154 #endif /* !_MINIX */
156 * Send request, RETRY times, or until successful
158 for (try = 0; try < _res.retry; try++) {
159 for (ns = 0; ns < _res.nscount; ns++) {
160 #ifdef DEBUG
161 #if !_MINIX
162 if (_res.options & RES_DEBUG)
163 printf("Querying server (# %d) address = %s\n", ns+1,
164 inet_ntoa(_res.nsaddr_list[ns].sin_addr));
165 #else /* _MINIX */
166 if (_res.options & RES_DEBUG)
167 printf("Querying server (# %d) address = %s\n", ns+1,
168 inet_ntoa(_res.nsaddr_list[ns]));
169 #endif /* !_MINIX */
170 #endif /* DEBUG */
171 usevc:
172 if (v_circuit) {
173 #if !_MINIX
174 int truncated = 0;
177 * Use virtual circuit;
178 * at most one attempt per server.
180 try = _res.retry;
181 if (s < 0) {
182 s = socket(AF_INET, SOCK_STREAM, 0);
183 if (s < 0) {
184 terrno = errno;
185 #ifdef DEBUG
186 if (_res.options & RES_DEBUG)
187 perror("socket (vc) failed");
188 #endif /* DEBUG */
189 continue;
191 if (connect(s,
192 (struct sockaddr *)&(_res.nsaddr_list[ns]),
193 sizeof(struct sockaddr)) < 0) {
194 terrno = errno;
195 #ifdef DEBUG
196 if (_res.options & RES_DEBUG)
197 perror("connect failed");
198 #endif /* DEBUG */
199 (void) close(s);
200 s = -1;
201 continue;
205 * Send length & message
207 len = htons((u_short)buflen);
208 iov[0].iov_base = (caddr_t)&len;
209 iov[0].iov_len = sizeof(len);
210 iov[1].iov_base = (char *)buf;
211 iov[1].iov_len = buflen;
212 if (writev(s, iov, 2) != sizeof(len) + buflen) {
213 terrno = errno;
214 #ifdef DEBUG
215 if (_res.options & RES_DEBUG)
216 perror("write failed");
217 #endif /* DEBUG */
218 (void) close(s);
219 s = -1;
220 continue;
223 * Receive length & response
225 cp = answer;
226 len = sizeof(short);
227 while (len != 0 &&
228 (n = read(s, (char *)cp, (int)len)) > 0) {
229 cp += n;
230 len -= n;
232 if (n <= 0) {
233 terrno = errno;
234 #ifdef DEBUG
235 if (_res.options & RES_DEBUG)
236 perror("read failed");
237 #endif /* DEBUG */
238 (void) close(s);
239 s = -1;
241 * A long running process might get its TCP
242 * connection reset if the remote server was
243 * restarted. Requery the server instead of
244 * trying a new one. When there is only one
245 * server, this means that a query might work
246 * instead of failing. We only allow one reset
247 * per query to prevent looping.
249 if (terrno == ECONNRESET && !connreset) {
250 connreset = 1;
251 ns--;
253 continue;
255 cp = answer;
256 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
257 #ifdef DEBUG
258 if (_res.options & RES_DEBUG)
259 fprintf(stderr, "response truncated\n");
260 #endif /* DEBUG */
261 len = anslen;
262 truncated = 1;
263 } else
264 len = resplen;
265 while (len != 0 &&
266 (n = read(s, (char *)cp, (int)len)) > 0) {
267 cp += n;
268 len -= n;
270 if (n <= 0) {
271 terrno = errno;
272 #ifdef DEBUG
273 if (_res.options & RES_DEBUG)
274 perror("read failed");
275 #endif /* DEBUG */
276 (void) close(s);
277 s = -1;
278 continue;
280 if (truncated) {
282 * Flush rest of answer
283 * so connection stays in synch.
285 anhp->tc = 1;
286 len = resplen - anslen;
287 while (len != 0) {
288 n = (len > sizeof(junk) ?
289 sizeof(junk) : len);
290 if ((n = read(s, junk, n)) > 0)
291 len -= n;
292 else
293 break;
296 #else /* _MINIX */
297 int truncated = 0;
298 int nbytes;
301 * Use virtual circuit;
302 * at most one attempt per server.
304 try = _res.retry;
305 if (s < 0)
307 s= tcp_connect(_res.nsaddr_list[ns],
308 _res.nsport_list[ns], &terrno);
309 if (s == -1)
310 continue;
313 * Send length & message
315 len = htons((u_short)buflen);
316 nbytes= tcpip_writeall(s, (char *)&len,
317 sizeof(len));
318 if (nbytes != sizeof(len))
320 terrno= errno;
321 #ifdef DEBUG
322 if (_res.options & RES_DEBUG)
323 fprintf(stderr, "write failed: %s\n",
324 strerror(terrno));
325 #endif /* DEBUG */
326 close(s);
327 s= -1;
328 continue;
330 nbytes= tcpip_writeall(s, buf, buflen);
331 if (nbytes != buflen)
333 terrno= errno;
334 #ifdef DEBUG
335 if (_res.options & RES_DEBUG)
336 fprintf(stderr, "write failed: %s\n",
337 strerror(terrno));
338 #endif /* DEBUG */
339 close(s);
340 s= -1;
341 continue;
344 * Receive length & response
346 cp = answer;
347 len = sizeof(short);
348 while (len != 0)
350 n = read(s, (char *)cp, (int)len);
351 if (n <= 0)
352 break;
353 cp += n;
354 assert(len >= n);
355 len -= n;
357 if (len) {
358 terrno = errno;
359 #ifdef DEBUG
360 if (_res.options & RES_DEBUG)
361 fprintf(stderr, "read failed: %s\n",
362 strerror(terrno));
363 #endif /* DEBUG */
364 close(s);
365 s= -1;
367 * A long running process might get its TCP
368 * connection reset if the remote server was
369 * restarted. Requery the server instead of
370 * trying a new one. When there is only one
371 * server, this means that a query might work
372 * instead of failing. We only allow one reset
373 * per query to prevent looping.
375 if (terrno == ECONNRESET && !connreset) {
376 connreset = 1;
377 ns--;
379 continue;
381 cp = answer;
382 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
383 #ifdef DEBUG
384 if (_res.options & RES_DEBUG)
385 fprintf(stderr, "response truncated\n");
386 #endif /* DEBUG */
387 len = anslen;
388 truncated = 1;
389 } else
390 len = resplen;
391 while (len != 0)
393 n= read(s, (char *)cp, (int)len);
394 if (n <= 0)
395 break;
396 cp += n;
397 assert(len >= n);
398 len -= n;
400 if (len) {
401 terrno = errno;
402 #ifdef DEBUG
403 if (_res.options & RES_DEBUG)
404 fprintf(stderr, "read failed: %s\n",
405 strerror(terrno));
406 #endif /* DEBUG */
407 close(s);
408 s= -1;
409 continue;
411 if (truncated) {
413 * Flush rest of answer
414 * so connection stays in synch.
416 anhp->dh_flag1 |= DHF_TC;
417 len = resplen - anslen;
418 while (len != 0) {
419 n = (len > sizeof(junk) ?
420 sizeof(junk) : len);
421 n = read(s, junk, n);
422 if (n <= 0)
424 assert(len >= n);
425 len -= n;
427 else
428 break;
431 #endif /* _MINIX */
432 } else {
433 #if !_MINIX
435 * Use datagrams.
437 if (s < 0) {
438 s = socket(AF_INET, SOCK_DGRAM, 0);
439 if (s < 0) {
440 terrno = errno;
441 #ifdef DEBUG
442 if (_res.options & RES_DEBUG)
443 perror("socket (dg) failed");
444 #endif /* DEBUG */
445 continue;
448 #if BSD >= 43
450 * I'm tired of answering this question, so:
451 * On a 4.3BSD+ machine (client and server,
452 * actually), sending to a nameserver datagram
453 * port with no nameserver will cause an
454 * ICMP port unreachable message to be returned.
455 * If our datagram socket is "connected" to the
456 * server, we get an ECONNREFUSED error on the next
457 * socket operation, and select returns if the
458 * error message is received. We can thus detect
459 * the absence of a nameserver without timing out.
460 * If we have sent queries to at least two servers,
461 * however, we don't want to remain connected,
462 * as we wish to receive answers from the first
463 * server to respond.
465 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
467 * Don't use connect if we might
468 * still receive a response
469 * from another server.
471 if (connected == 0) {
472 if (connect(s, (struct sockaddr *)&_res.nsaddr_list[ns],
473 sizeof(struct sockaddr)) < 0) {
474 #ifdef DEBUG
475 if (_res.options & RES_DEBUG)
476 perror("connect");
477 #endif /* DEBUG */
478 continue;
480 connected = 1;
482 if (send(s, buf, buflen, 0) != buflen) {
483 #ifdef DEBUG
484 if (_res.options & RES_DEBUG)
485 perror("send");
486 #endif /* DEBUG */
487 continue;
489 } else {
491 * Disconnect if we want to listen
492 * for responses from more than one server.
494 if (connected) {
495 (void) connect(s, &no_addr,
496 sizeof(no_addr));
497 connected = 0;
499 #endif /* BSD */
500 if (sendto(s, buf, buflen, 0,
501 (struct sockaddr *)&_res.nsaddr_list[ns],
502 sizeof(struct sockaddr)) != buflen) {
503 #ifdef DEBUG
504 if (_res.options & RES_DEBUG)
505 perror("sendto");
506 #endif /* DEBUG */
507 continue;
509 #if BSD >= 43
511 #endif /* BSD */
514 * Wait for reply
516 timeout.tv_sec = (_res.retrans << try);
517 if (try > 0)
518 timeout.tv_sec /= _res.nscount;
519 if (timeout.tv_sec <= 0)
520 timeout.tv_sec = 1;
521 timeout.tv_usec = 0;
522 wait:
523 FD_ZERO(&dsmask);
524 FD_SET(s, &dsmask);
525 n = select(s+1, &dsmask, (fd_set *)NULL,
526 (fd_set *)NULL, &timeout);
527 if (n < 0) {
528 #ifdef DEBUG
529 if (_res.options & RES_DEBUG)
530 perror("select");
531 #endif /* DEBUG */
532 continue;
534 if (n == 0) {
536 * timeout
538 #ifdef DEBUG
539 if (_res.options & RES_DEBUG)
540 printf("timeout\n");
541 #endif /* DEBUG */
542 #if BSD >= 43
543 gotsomewhere = 1;
544 #endif
545 continue;
547 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
548 #ifdef DEBUG
549 if (_res.options & RES_DEBUG)
550 perror("recvfrom");
551 #endif /* DEBUG */
552 continue;
554 gotsomewhere = 1;
555 if (id != anhp->id) {
557 * response from old query, ignore it
559 #ifdef DEBUG
560 if (_res.options & RES_DEBUG) {
561 printf("old answer:\n");
562 __p_query(answer);
564 #endif /* DEBUG */
565 goto wait;
567 if (!(_res.options & RES_IGNTC) && anhp->tc) {
569 * get rest of answer;
570 * use TCP with same server.
572 #ifdef DEBUG
573 if (_res.options & RES_DEBUG)
574 printf("truncated answer\n");
575 #endif /* DEBUG */
576 (void) close(s);
577 s = -1;
578 v_circuit = 1;
579 goto usevc;
581 #else /* _MINIX */
583 * Use datagrams.
585 if (s < 0) {
586 s = udp_connect();
587 if (s < 0) {
588 terrno = errno;
589 #ifdef DEBUG
590 if (_res.options & RES_DEBUG)
591 perror("udp_connect failed");
592 #endif /* DEBUG */
593 continue;
596 if (udp_sendto(s, buf, buflen, _res.nsaddr_list[ns],
597 _res.nsport_list[ns]) != buflen) {
598 #ifdef DEBUG
599 if (_res.options & RES_DEBUG)
600 perror("sendto");
601 #endif /* DEBUG */
602 continue;
606 * Wait for reply
608 timeout= (_res.retrans << try);
609 if (try > 0)
610 timeout /= _res.nscount;
611 if (timeout <= 0)
612 timeout= 1;
613 wait:
614 if ((resplen= udp_receive(s, answer, anslen, timeout))
615 == -1)
617 if (errno == EINTR)
620 * timeout
622 #ifdef DEBUG
623 if (_res.options & RES_DEBUG)
624 printf("timeout\n");
625 #endif /* DEBUG */
626 gotsomewhere = 1;
628 else
630 #ifdef DEBUG
631 if (_res.options & RES_DEBUG)
632 perror("udp_receive");
633 #endif /* DEBUG */
635 continue;
637 gotsomewhere = 1;
638 if (id != anhp->dh_id) {
640 * response from old query, ignore it
642 #ifdef DEBUG
643 if (_res.options & RES_DEBUG) {
644 printf("old answer:\n");
645 __p_query(answer);
647 #endif /* DEBUG */
648 goto wait;
650 if (!(_res.options & RES_IGNTC) &&
651 (anhp->dh_flag1 & DHF_TC)) {
653 * get rest of answer;
654 * use TCP with same server.
656 #ifdef DEBUG
657 if (_res.options & RES_DEBUG)
658 printf("truncated answer\n");
659 #endif /* DEBUG */
660 (void) close(s);
661 s = -1;
662 v_circuit = 1;
663 goto usevc;
665 #endif /* !_MINIX */
667 #ifdef DEBUG
668 if (_res.options & RES_DEBUG) {
669 printf("got answer:\n");
670 __p_query(answer);
672 #endif /* DEBUG */
674 * If using virtual circuits, we assume that the first server
675 * is preferred * over the rest (i.e. it is on the local
676 * machine) and only keep that one open.
677 * If we have temporarily opened a virtual circuit,
678 * or if we haven't been asked to keep a socket open,
679 * close the socket.
681 if ((v_circuit &&
682 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
683 (_res.options & RES_STAYOPEN) == 0) {
684 (void) close(s);
685 s = -1;
687 return (resplen);
690 if (s >= 0) {
691 (void) close(s);
692 s = -1;
694 if (v_circuit == 0)
695 if (gotsomewhere == 0)
696 errno = ECONNREFUSED; /* no nameservers found */
697 else
698 errno = ETIMEDOUT; /* no answer obtained */
699 else
700 errno = terrno;
701 return (-1);
705 * This routine is for closing the socket if a virtual circuit is used and
706 * the program wants to close it. This provides support for endhostent()
707 * which expects to close the socket.
709 * This routine is not expected to be user visible.
711 void
712 _res_close()
714 if (s != -1) {
715 (void) close(s);
716 s = -1;
720 #if _MINIX
721 static int tcp_connect(host, port, terrno)
722 ipaddr_t host;
723 tcpport_t port;
724 int *terrno;
726 char *dev_name;
727 int fd;
728 int error;
729 nwio_tcpconf_t tcpconf;
730 nwio_tcpcl_t clopt;
732 dev_name= getenv("TCP_DEVICE");
733 if (!dev_name)
734 dev_name= TCP_DEVICE;
735 fd= open(dev_name, O_RDWR);
736 if (fd == -1)
738 *terrno= errno;
739 return -1;
741 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
742 tcpconf.nwtc_remaddr= host;
743 tcpconf.nwtc_remport= port;
744 error= ioctl(fd, NWIOSTCPCONF, &tcpconf);
745 if (error == -1)
747 *terrno= errno;
748 close(fd);
749 return -1;
751 clopt.nwtcl_flags= 0;
752 error= ioctl(fd, NWIOTCPCONN, &clopt);
753 if (error == -1)
755 *terrno= errno;
756 close(fd);
757 return -1;
759 *terrno= 0;
760 return fd;
763 static int tcpip_writeall(fd, buf, siz)
764 int fd;
765 const char *buf;
766 size_t siz;
768 size_t siz_org;
769 int nbytes;
771 siz_org= siz;
773 while (siz)
775 nbytes= write(fd, buf, siz);
776 if (nbytes <= 0)
777 return siz_org-siz;
778 assert(siz >= nbytes);
779 buf += nbytes;
780 siz -= nbytes;
782 return siz_org;
786 static int udp_connect()
788 nwio_udpopt_t udpopt;
789 char *dev_name;
790 int fd, r, terrno;
792 dev_name= getenv("UDP_DEVICE");
793 if (!dev_name)
794 dev_name= UDP_DEVICE;
795 fd= open(dev_name, O_RDWR);
796 if (fd == -1)
797 return -1;
799 udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC |
800 NWUO_EN_BROAD | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL |
801 NWUO_DI_IPOPT;
802 r= ioctl(fd, NWIOSUDPOPT, &udpopt);
803 if (r == -1)
805 terrno= errno;
806 close(fd);
807 errno= terrno;
808 return -1;
810 return fd;
813 static int udp_sendto(fd, buf, buflen, addr, port)
814 int fd;
815 const char *buf;
816 unsigned buflen;
817 ipaddr_t addr;
818 udpport_t port;
820 char *newbuf;
821 udp_io_hdr_t *udp_io_hdr;
822 int r, terrno;
824 newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
825 if (newbuf == NULL)
827 errno= ENOMEM;
828 return -1;
830 udp_io_hdr= (udp_io_hdr_t *)newbuf;
831 udp_io_hdr->uih_dst_addr= addr;
832 udp_io_hdr->uih_dst_port= port;
833 udp_io_hdr->uih_ip_opt_len= 0;
834 udp_io_hdr->uih_data_len= buflen;
836 memcpy(newbuf + sizeof(*udp_io_hdr), buf, buflen);
837 r= write(fd, newbuf, sizeof(*udp_io_hdr) + buflen);
838 terrno= errno;
839 free(newbuf);
840 if (r >= sizeof(*udp_io_hdr))
841 r -= sizeof(*udp_io_hdr);
842 errno= terrno;
843 return r;
846 static void alarm_handler(sig)
847 int sig;
849 signal(SIGALRM, alarm_handler);
850 alarm(1);
853 static int udp_receive(fd, buf, buflen, timeout)
854 int fd;
855 char *buf;
856 unsigned buflen;
857 time_t timeout;
859 char *newbuf;
860 udp_io_hdr_t *udp_io_hdr;
861 int r, terrno;
862 void (*u_handler) _ARGS(( int sig ));
863 time_t u_timeout;
865 newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
866 if (newbuf == NULL)
868 errno= ENOMEM;
869 return -1;
872 u_handler= signal(SIGALRM, alarm_handler);
873 u_timeout= alarm(timeout);
875 r= read(fd, newbuf, sizeof(*udp_io_hdr) + buflen);
876 terrno= errno;
878 if (r < 0 || r <= sizeof(*udp_io_hdr))
880 if (r > 0)
881 r= 0;
882 free(newbuf);
885 alarm(0);
886 signal(SIGALRM, u_handler);
887 alarm(u_timeout);
889 errno= terrno;
890 return r;
893 memcpy(buf, newbuf + sizeof(*udp_io_hdr), r - sizeof(*udp_io_hdr));
894 free(newbuf);
896 alarm(0);
897 signal(SIGALRM, u_handler);
898 alarm(u_timeout);
900 return r-sizeof(*udp_io_hdr);
903 #endif