Merge branch 'vendor/OPENSSL'
[dragonfly.git] / lib / libstand / net.c
1 /*      $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $  */
2
3 /*
4  * Copyright (c) 1992 Regents of the University of California.
5  * All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL)
36  * $FreeBSD: src/lib/libstand/net.c,v 1.1.1.1.6.1 2000/04/15 03:09:28 ps Exp $
37  * $DragonFly: src/lib/libstand/net.c,v 1.5 2005/12/11 02:27:26 swildner Exp $
38  */
39
40 #include <sys/param.h>
41 #include <sys/socket.h>
42
43 #include <string.h>
44
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <netinet/if_ether.h>
48 #include <netinet/in_systm.h>
49
50 #include <netinet/ip.h>
51 #include <netinet/ip_var.h>
52 #include <netinet/udp.h>
53 #include <netinet/udp_var.h>
54
55 #include "stand.h"
56 #include "net.h"
57
58 /*
59  * Send a packet and wait for a reply, with exponential backoff.
60  *
61  * The send routine must return the actual number of bytes written,
62  * or -1 on error.
63  *
64  * The receive routine can indicate success by returning the number of
65  * bytes read; it can return 0 to indicate EOF; it can return -1 with a
66  * non-zero errno to indicate failure; finally, it can return -1 with a
67  * zero errno to indicate it isn't done yet.
68  */
69 ssize_t
70 sendrecv(struct iodesc *d, ssize_t (*sproc)(struct iodesc *, void *, size_t),
71          void *sbuf, size_t ssize,
72          ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t), void *rbuf,
73          size_t rsize)
74 {
75         ssize_t cc;
76         time_t t, tmo, tlast;
77         long tleft;
78
79 #ifdef NET_DEBUG
80         if (debug)
81                 printf("sendrecv: called\n");
82 #endif
83
84         tmo = MINTMO;
85         tlast = tleft = 0;
86         t = getsecs();
87         for (;;) {
88                 if (tleft <= 0) {
89                         if (tmo >= MAXTMO) {
90                                 errno = ETIMEDOUT;
91                                 return -1;
92                         }
93                         cc = (*sproc)(d, sbuf, ssize);
94                         if (cc != -1 && cc < ssize)
95                                 panic("sendrecv: short write! (%d < %d)",
96                                     cc, ssize);
97
98                         tleft = tmo;
99                         tmo <<= 1;
100                         if (tmo > MAXTMO)
101                                 tmo = MAXTMO;
102
103                         if (cc == -1) {
104                                 /* Error on transmit; wait before retrying */
105                                 while ((getsecs() - t) < tmo);
106                                 tleft = 0;
107                                 continue;
108                         }
109
110                         tlast = t;
111                 }
112
113                 /* Try to get a packet and process it. */
114                 cc = (*rproc)(d, rbuf, rsize, tleft);
115                 /* Return on data, EOF or real error. */
116                 if (cc != -1 || errno != 0)
117                         return (cc);
118
119                 /* Timed out or didn't get the packet we're waiting for */
120                 t = getsecs();
121                 tleft -= t - tlast;
122                 tlast = t;
123         }
124 }
125
126 /*
127  * Like inet_addr() in the C library, but we only accept base-10.
128  * Return values are in network order.
129  */
130 n_long
131 inet_addr(char *cp)
132 {
133         u_long val;
134         int n;
135         char c;
136         u_int parts[4];
137         u_int *pp = parts;
138
139         for (;;) {
140                 /*
141                  * Collect number up to ``.''.
142                  * Values are specified as for C:
143                  * 0x=hex, 0=octal, other=decimal.
144                  */
145                 val = 0;
146                 while ((c = *cp) != '\0') {
147                         if (c >= '0' && c <= '9') {
148                                 val = (val * 10) + (c - '0');
149                                 cp++;
150                                 continue;
151                         }
152                         break;
153                 }
154                 if (*cp == '.') {
155                         /*
156                          * Internet format:
157                          *      a.b.c.d
158                          *      a.b.c   (with c treated as 16-bits)
159                          *      a.b     (with b treated as 24 bits)
160                          */
161                         if (pp >= parts + 3 || val > 0xff)
162                                 goto bad;
163                         *pp++ = val, cp++;
164                 } else
165                         break;
166         }
167         /*
168          * Check for trailing characters.
169          */
170         if (*cp != '\0')
171                 goto bad;
172
173         /*
174          * Concoct the address according to
175          * the number of parts specified.
176          */
177         n = pp - parts + 1;
178         switch (n) {
179
180         case 1:                         /* a -- 32 bits */
181                 break;
182
183         case 2:                         /* a.b -- 8.24 bits */
184                 if (val > 0xffffff)
185                         goto bad;
186                 val |= parts[0] << 24;
187                 break;
188
189         case 3:                         /* a.b.c -- 8.8.16 bits */
190                 if (val > 0xffff)
191                         goto bad;
192                 val |= (parts[0] << 24) | (parts[1] << 16);
193                 break;
194
195         case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
196                 if (val > 0xff)
197                         goto bad;
198                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
199                 break;
200         }
201
202         return (htonl(val));
203  bad:
204         return (htonl(INADDR_NONE));
205 }
206
207 char *
208 inet_ntoa(struct in_addr ia)
209 {
210         return (intoa(ia.s_addr));
211 }
212
213 /* Similar to inet_ntoa() */
214 char *
215 intoa(n_long addr)
216 {
217         char *cp;
218         u_int byte;
219         int n;
220         static char buf[17];    /* strlen(".255.255.255.255") + 1 */
221
222         addr = ntohl(addr);
223         cp = &buf[sizeof buf];
224         *--cp = '\0';
225
226         n = 4;
227         do {
228                 byte = addr & 0xff;
229                 *--cp = byte % 10 + '0';
230                 byte /= 10;
231                 if (byte > 0) {
232                         *--cp = byte % 10 + '0';
233                         byte /= 10;
234                         if (byte > 0)
235                                 *--cp = byte + '0';
236                 }
237                 *--cp = '.';
238                 addr >>= 8;
239         } while (--n > 0);
240
241         return (cp+1);
242 }
243
244 static char *
245 number(char *s, int *n)
246 {
247         for (*n = 0; isdigit(*s); s++)
248                 *n = (*n * 10) + *s - '0';
249         return s;
250 }
251
252 n_long
253 ip_convertaddr(char *p)
254 {
255 #define IP_ANYADDR      0
256         n_long addr = 0, n;
257
258         if (p == NULL || *p == '\0')
259                 return IP_ANYADDR;
260         p = number(p, &n);
261         addr |= (n << 24) & 0xff000000;
262         if (*p == '\0' || *p++ != '.')
263                 return IP_ANYADDR;
264         p = number(p, &n);
265         addr |= (n << 16) & 0xff0000;
266         if (*p == '\0' || *p++ != '.')
267                 return IP_ANYADDR;
268         p = number(p, &n);
269         addr |= (n << 8) & 0xff00;
270         if (*p == '\0' || *p++ != '.')
271                 return IP_ANYADDR;
272         p = number(p, &n);
273         addr |= n & 0xff;
274         if (*p != '\0')
275                 return IP_ANYADDR;
276
277         return htonl(addr);
278 }