source: trunk/minix/lib/ip/res_send.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 19.7 KB
Line 
1/*
2 * Copyright (c) 1985, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
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.
20 *
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.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
36#endif /* LIBC_SCCS and not lint */
37
38/*
39 * Send query to name server and wait for reply.
40 */
41
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>
54
55#else /* _MINIX */
56
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>
68
69#include <net/hton.h>
70
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>
82
83static int tcp_connect _ARGS(( ipaddr_t host, Tcpport_t port, int *terrno ));
84static int tcpip_writeall _ARGS(( int fd, const char *buf, size_t siz ));
85static int udp_connect _ARGS(( void ));
86static int udp_sendto _ARGS(( int fd, const char *buf, unsigned buflen,
87 ipaddr_t addr, Udpport_t port ));
88static int udp_receive _ARGS(( int fd, char *buf, unsigned buflen,
89 time_t timeout ));
90static void alarm_handler _ARGS(( int sig ));
91
92#endif /* !_MINIX */
93
94static int s = -1; /* socket used for communications */
95#if !_MINIX
96static struct sockaddr no_addr;
97
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 */
107
108res_send(buf, buflen, answer, anslen)
109 const char *buf;
110 int buflen;
111 char *answer;
112 int anslen;
113{
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];
137
138#ifdef DEBUG
139 if (_res.options & RES_DEBUG) {
140 printf("res_send()\n");
141 __p_query(buf);
142 }
143#endif /* DEBUG */
144 if (!(_res.options & RES_INIT))
145 if (res_init() == -1) {
146 return(-1);
147 }
148
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 */
155 /*
156 * Send request, RETRY times, or until successful
157 */
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;
175
176 /*
177 * Use virtual circuit;
178 * at most one attempt per server.
179 */
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;
190 }
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;
202 }
203 }
204 /*
205 * Send length & message
206 */
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;
221 }
222 /*
223 * Receive length & response
224 */
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;
231 }
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;
240 /*
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.
248 */
249 if (terrno == ECONNRESET && !connreset) {
250 connreset = 1;
251 ns--;
252 }
253 continue;
254 }
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;
269 }
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;
279 }
280 if (truncated) {
281 /*
282 * Flush rest of answer
283 * so connection stays in synch.
284 */
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;
294 }
295 }
296#else /* _MINIX */
297 int truncated = 0;
298 int nbytes;
299
300 /*
301 * Use virtual circuit;
302 * at most one attempt per server.
303 */
304 try = _res.retry;
305 if (s < 0)
306 {
307 s= tcp_connect(_res.nsaddr_list[ns],
308 _res.nsport_list[ns], &terrno);
309 if (s == -1)
310 continue;
311 }
312 /*
313 * Send length & message
314 */
315 len = htons((u_short)buflen);
316 nbytes= tcpip_writeall(s, (char *)&len,
317 sizeof(len));
318 if (nbytes != sizeof(len))
319 {
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;
329 }
330 nbytes= tcpip_writeall(s, buf, buflen);
331 if (nbytes != buflen)
332 {
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;
342 }
343 /*
344 * Receive length & response
345 */
346 cp = answer;
347 len = sizeof(short);
348 while (len != 0)
349 {
350 n = read(s, (char *)cp, (int)len);
351 if (n <= 0)
352 break;
353 cp += n;
354 assert(len >= n);
355 len -= n;
356 }
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;
366 /*
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.
374 */
375 if (terrno == ECONNRESET && !connreset) {
376 connreset = 1;
377 ns--;
378 }
379 continue;
380 }
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)
392 {
393 n= read(s, (char *)cp, (int)len);
394 if (n <= 0)
395 break;
396 cp += n;
397 assert(len >= n);
398 len -= n;
399 }
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;
410 }
411 if (truncated) {
412 /*
413 * Flush rest of answer
414 * so connection stays in synch.
415 */
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)
423 {
424 assert(len >= n);
425 len -= n;
426 }
427 else
428 break;
429 }
430 }
431#endif /* _MINIX */
432 } else {
433#if !_MINIX
434 /*
435 * Use datagrams.
436 */
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;
446 }
447 }
448#if BSD >= 43
449 /*
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.
464 */
465 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
466 /*
467 * Don't use connect if we might
468 * still receive a response
469 * from another server.
470 */
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;
479 }
480 connected = 1;
481 }
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;
488 }
489 } else {
490 /*
491 * Disconnect if we want to listen
492 * for responses from more than one server.
493 */
494 if (connected) {
495 (void) connect(s, &no_addr,
496 sizeof(no_addr));
497 connected = 0;
498 }
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;
508 }
509#if BSD >= 43
510 }
511#endif /* BSD */
512
513 /*
514 * Wait for reply
515 */
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;
522wait:
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;
533 }
534 if (n == 0) {
535 /*
536 * timeout
537 */
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;
546 }
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;
553 }
554 gotsomewhere = 1;
555 if (id != anhp->id) {
556 /*
557 * response from old query, ignore it
558 */
559#ifdef DEBUG
560 if (_res.options & RES_DEBUG) {
561 printf("old answer:\n");
562 __p_query(answer);
563 }
564#endif /* DEBUG */
565 goto wait;
566 }
567 if (!(_res.options & RES_IGNTC) && anhp->tc) {
568 /*
569 * get rest of answer;
570 * use TCP with same server.
571 */
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;
580 }
581#else /* _MINIX */
582 /*
583 * Use datagrams.
584 */
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;
594 }
595 }
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;
603 }
604
605 /*
606 * Wait for reply
607 */
608 timeout= (_res.retrans << try);
609 if (try > 0)
610 timeout /= _res.nscount;
611 if (timeout <= 0)
612 timeout= 1;
613wait:
614 if ((resplen= udp_receive(s, answer, anslen, timeout))
615 == -1)
616 {
617 if (errno == EINTR)
618 {
619 /*
620 * timeout
621 */
622#ifdef DEBUG
623 if (_res.options & RES_DEBUG)
624 printf("timeout\n");
625#endif /* DEBUG */
626 gotsomewhere = 1;
627 }
628 else
629 {
630#ifdef DEBUG
631 if (_res.options & RES_DEBUG)
632 perror("udp_receive");
633#endif /* DEBUG */
634 }
635 continue;
636 }
637 gotsomewhere = 1;
638 if (id != anhp->dh_id) {
639 /*
640 * response from old query, ignore it
641 */
642#ifdef DEBUG
643 if (_res.options & RES_DEBUG) {
644 printf("old answer:\n");
645 __p_query(answer);
646 }
647#endif /* DEBUG */
648 goto wait;
649 }
650 if (!(_res.options & RES_IGNTC) &&
651 (anhp->dh_flag1 & DHF_TC)) {
652 /*
653 * get rest of answer;
654 * use TCP with same server.
655 */
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;
664 }
665#endif /* !_MINIX */
666 }
667#ifdef DEBUG
668 if (_res.options & RES_DEBUG) {
669 printf("got answer:\n");
670 __p_query(answer);
671 }
672#endif /* DEBUG */
673 /*
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.
680 */
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;
686 }
687 return (resplen);
688 }
689 }
690 if (s >= 0) {
691 (void) close(s);
692 s = -1;
693 }
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);
702}
703
704/*
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.
708 *
709 * This routine is not expected to be user visible.
710 */
711void
712_res_close()
713{
714 if (s != -1) {
715 (void) close(s);
716 s = -1;
717 }
718}
719
720#if _MINIX
721static int tcp_connect(host, port, terrno)
722ipaddr_t host;
723tcpport_t port;
724int *terrno;
725{
726 char *dev_name;
727 int fd;
728 int error;
729 nwio_tcpconf_t tcpconf;
730 nwio_tcpcl_t clopt;
731
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)
737 {
738 *terrno= errno;
739 return -1;
740 }
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)
746 {
747 *terrno= errno;
748 close(fd);
749 return -1;
750 }
751 clopt.nwtcl_flags= 0;
752 error= ioctl(fd, NWIOTCPCONN, &clopt);
753 if (error == -1)
754 {
755 *terrno= errno;
756 close(fd);
757 return -1;
758 }
759 *terrno= 0;
760 return fd;
761}
762
763static int tcpip_writeall(fd, buf, siz)
764int fd;
765const char *buf;
766size_t siz;
767{
768 size_t siz_org;
769 int nbytes;
770
771 siz_org= siz;
772
773 while (siz)
774 {
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;
781 }
782 return siz_org;
783}
784
785
786static int udp_connect()
787{
788 nwio_udpopt_t udpopt;
789 char *dev_name;
790 int fd, r, terrno;
791
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;
798
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)
804 {
805 terrno= errno;
806 close(fd);
807 errno= terrno;
808 return -1;
809 }
810 return fd;
811}
812
813static int udp_sendto(fd, buf, buflen, addr, port)
814int fd;
815const char *buf;
816unsigned buflen;
817ipaddr_t addr;
818udpport_t port;
819{
820 char *newbuf;
821 udp_io_hdr_t *udp_io_hdr;
822 int r, terrno;
823
824 newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
825 if (newbuf == NULL)
826 {
827 errno= ENOMEM;
828 return -1;
829 }
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;
835
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;
844}
845
846static void alarm_handler(sig)
847int sig;
848{
849 signal(SIGALRM, alarm_handler);
850 alarm(1);
851}
852
853static int udp_receive(fd, buf, buflen, timeout)
854int fd;
855char *buf;
856unsigned buflen;
857time_t timeout;
858{
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;
864
865 newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
866 if (newbuf == NULL)
867 {
868 errno= ENOMEM;
869 return -1;
870 }
871
872 u_handler= signal(SIGALRM, alarm_handler);
873 u_timeout= alarm(timeout);
874
875 r= read(fd, newbuf, sizeof(*udp_io_hdr) + buflen);
876 terrno= errno;
877
878 if (r < 0 || r <= sizeof(*udp_io_hdr))
879 {
880 if (r > 0)
881 r= 0;
882 free(newbuf);
883
884
885 alarm(0);
886 signal(SIGALRM, u_handler);
887 alarm(u_timeout);
888
889 errno= terrno;
890 return r;
891 }
892
893 memcpy(buf, newbuf + sizeof(*udp_io_hdr), r - sizeof(*udp_io_hdr));
894 free(newbuf);
895
896 alarm(0);
897 signal(SIGALRM, u_handler);
898 alarm(u_timeout);
899
900 return r-sizeof(*udp_io_hdr);
901}
902
903#endif
Note: See TracBrowser for help on using the repository browser.