]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/sntp/socket.c
This commit was generated by cvs2svn to compensate for changes in r159764,
[FreeBSD/FreeBSD.git] / contrib / ntp / sntp / socket.c
1 /*  Copyright (C) 1996, 2000 N.M. Maclaren
2     Copyright (C) 1996, 2000 The University of Cambridge
3
4 This includes all of the code needed to handle Berkeley sockets.  It is way
5 outside current POSIX, unfortunately.  It should be easy to convert to a system
6 that uses another mechanism.  It does not currently use socklen_t, because
7 the only system that the author uses that has it is Linux. */
8
9
10
11 #include "header.h"
12 #include "internet.h"
13 #include <fcntl.h>
14
15 #define SOCKET
16 #include "kludges.h"
17 #undef SOCKET
18
19
20
21 /* The code needs to set some variables during the open, for use by later
22 functions. */
23
24 static int initial = 1,
25     descriptors[MAX_SOCKETS];
26
27 #ifdef HAVE_IPV6
28 static struct sockaddr_storage here[MAX_SOCKETS], there[MAX_SOCKETS];
29 #else
30 static struct sockaddr_in here[MAX_SOCKETS], there[MAX_SOCKETS];
31 #endif
32
33
34 /* There needs to be some disgusting grobble for handling timeouts, that is
35 identical to the grobble in internet.c. */
36
37 static jmp_buf jump_buffer;
38
39 static void jump_handler (int sig) {
40     longjmp(jump_buffer,1);
41 }
42
43 static void clear_alarm (void) {
44     int k;
45
46     k = errno;
47     alarm(0);
48     errno = 0;
49     if (signal(SIGALRM,SIG_DFL) == SIG_ERR)
50         fatal(1,"unable to reset signal handler",NULL);
51     errno = k;
52 }
53
54
55
56 void display_in_hex (const void *data, int length) {
57     int i;
58
59     for (i = 0; i < length; ++i)
60         fprintf(stderr,"%.2x",((const unsigned char *)data)[i]);
61 }
62
63 #ifdef HAVE_IPV6
64
65 void display_sock_in_hex (struct sockaddr_storage *sock) {
66     int family, len;
67     struct sockaddr_in *sin;
68     struct sockaddr_in6 *sin6;
69
70     family = sock->ss_family;
71     switch(family) {
72     case AF_INET:
73         sin = (struct sockaddr_in *)sock;
74         display_in_hex(&sin->sin_addr, sizeof(struct in_addr));
75         fprintf(stderr,"/");
76         display_in_hex(&sin->sin_port, 2);
77         break;
78     case AF_INET6:
79         sin6 = (struct sockaddr_in6 *)sock;
80         display_in_hex(&sin6->sin6_addr, sizeof(struct in6_addr));
81         fprintf(stderr,"/");
82         display_in_hex(&sin6->sin6_port, 2);
83         break;
84     }
85 }
86
87 #else
88
89 void display_sock_in_hex (struct sockaddr_in *sock) {
90     int family, len;
91     struct sockaddr_in *sin;
92
93     family = sock->sin_family;
94     switch(family) {
95     case AF_INET:
96         sin = (struct sockaddr_in *)sock;
97         display_in_hex(&sin->sin_addr, sizeof(struct in_addr));
98         fprintf(stderr,"/");
99         display_in_hex(&sin->sin_port, 2);
100         break;
101     }
102 }
103 #endif
104
105 #ifdef HAVE_IPV6
106
107 void open_socket (int which, char *hostname, int timespan) {
108
109 /* Locate the specified NTP server, set up a couple of addresses and open a
110 socket. */
111
112     int port, k, sl;
113     struct sockaddr_storage address, anywhere, everywhere;
114
115 /* Initialise and find out the server and port number.  Note that the port
116 number is in network format. */
117
118     if (initial)
119         for (k = 0; k < MAX_SOCKETS; ++k)
120             descriptors[k] = -1;
121     initial = 0;
122     if (which < 0 || which >= MAX_SOCKETS || descriptors[which] >= 0)
123         fatal(0,"socket index out of range or already open",NULL);
124     if (verbose > 2)
125         fprintf(stderr,"Looking for the socket addresses\n");
126     find_address(&address,&anywhere,&everywhere,&port,hostname,timespan);
127     if (verbose > 2) {
128         fprintf(stderr,"Internet address: address=");
129         display_sock_in_hex(&address);
130         fprintf(stderr," anywhere=");
131         display_sock_in_hex(&anywhere);
132         fprintf(stderr," everywhere=");
133         display_sock_in_hex(&everywhere);
134         fputc('\n',stderr);
135     }
136
137 /* Set up our own and the target addresses.  Note that the target address will
138 be reset before use in server mode. */
139
140     memset(&here[which], 0, sizeof(struct sockaddr_storage));
141     here[which] = anywhere;
142     if (!(operation == op_listen || operation == op_server))
143         ((struct sockaddr_in6 *)&here[which])->sin6_port = 0;
144     memset(&there[which], 0, sizeof(struct sockaddr_storage));
145     there[which] = (operation == op_broadcast ? everywhere : address);
146     if (verbose > 2) {
147         fprintf(stderr,"Initial sockets: here=");
148         display_sock_in_hex(&here[which]);
149         fprintf(stderr," there=");
150         display_sock_in_hex(&there[which]);
151         fputc('\n',stderr);
152     }
153
154 /* Allocate a local UDP socket and configure it. */
155
156     switch(((struct sockaddr_in *)&there[which])->sin_family) {
157     case AF_INET:
158         sl = sizeof(struct sockaddr_in);
159         break;
160 #ifdef HAVE_IPV6
161     case AF_INET6:
162         sl = sizeof(struct sockaddr_in6);
163         break;
164 #endif
165     default:
166         sl = 0;
167         break;
168     }
169     errno = 0;
170     if ((descriptors[which] = socket(here[which].ss_family,SOCK_DGRAM,0)) < 0
171         || bind(descriptors[which],(struct sockaddr *)&here[which], sl) < 0)
172         fatal(1,"unable to allocate socket for NTP",NULL);
173     if (operation == op_broadcast) {
174         errno = 0;
175         k = setsockopt(descriptors[which],SOL_SOCKET,SO_BROADCAST,
176                 (void *)&k,sizeof(k));
177         if (k != 0) fatal(1,"unable to set permission to broadcast",NULL);
178     }
179 }
180
181 #else
182
183 void open_socket (int which, char *hostname, int timespan) {
184
185 /* Locate the specified NTP server, set up a couple of addresses and open a
186 socket. */
187
188     int port, k;
189     struct in_addr address, anywhere, everywhere;
190
191 /* Initialise and find out the server and port number.  Note that the port
192 number is in network format. */
193
194     if (initial) for (k = 0; k < MAX_SOCKETS; ++k) descriptors[k] = -1;
195     initial = 0;
196     if (which < 0 || which >= MAX_SOCKETS || descriptors[which] >= 0)
197         fatal(0,"socket index out of range or already open",NULL);
198     if (verbose > 2) fprintf(stderr,"Looking for the socket addresses\n");
199     find_address(&address,&anywhere,&everywhere,&port,hostname,timespan);
200     if (verbose > 2) {
201         fprintf(stderr,"Internet address: address=");
202         display_in_hex(&address,sizeof(struct in_addr));
203         fprintf(stderr," anywhere=");
204         display_in_hex(&anywhere,sizeof(struct in_addr));
205         fprintf(stderr," everywhere=");
206         display_in_hex(&everywhere,sizeof(struct in_addr));
207         fputc('\n',stderr);
208     }
209
210 /* Set up our own and the target addresses.  Note that the target address will
211 be reset before use in server mode. */
212
213     memset(&here[which],0,sizeof(struct sockaddr_in));
214     here[which].sin_family = AF_INET;
215     here[which].sin_port =
216         (operation == op_listen || operation == op_server ? port : 0);
217     here[which].sin_addr = anywhere;
218     memset(&there[which],0,sizeof(struct sockaddr_in));
219     there[which].sin_family = AF_INET;
220     there[which].sin_port = port;
221     there[which].sin_addr = (operation == op_broadcast ? everywhere : address);
222     if (verbose > 2) {
223         fprintf(stderr,"Initial sockets: here=");
224         display_in_hex(&here[which].sin_addr,sizeof(struct in_addr));
225         fputc('/',stderr);
226         display_in_hex(&here[which].sin_port,sizeof(here[which].sin_port));
227         fprintf(stderr," there=");
228         display_in_hex(&there[which].sin_addr,sizeof(struct in_addr));
229         fputc('/',stderr);
230         display_in_hex(&there[which].sin_port,sizeof(there[which].sin_port));
231         fputc('\n',stderr);
232     }
233
234 /* Allocate a local UDP socket and configure it. */
235
236     errno = 0;
237     if ((descriptors[which] = socket(AF_INET,SOCK_DGRAM,0)) < 0 ||
238             bind(descriptors[which],(struct sockaddr *)&here[which],
239                     sizeof(here[which]))  < 0)
240         fatal(1,"unable to allocate socket for NTP",NULL);
241     if (operation == op_broadcast) {
242         errno = 0;
243         k = setsockopt(descriptors[which],SOL_SOCKET,SO_BROADCAST,
244                 (void *)&k,sizeof(k));
245         if (k != 0) fatal(1,"unable to set permission to broadcast",NULL);
246     }
247 }
248
249 #endif
250
251 extern void write_socket (int which, void *packet, int length) {
252
253 /* Any errors in doing this are fatal - including blocking.  Yes, this leaves a
254 server vulnerable to a denial of service attack. */
255
256     int k, sl;
257
258     switch(((struct sockaddr_in *)&there[which])->sin_family) {
259     case AF_INET:
260         sl = sizeof(struct sockaddr_in);
261         break;
262 #ifdef HAVE_IPV6
263     case AF_INET6:
264         sl = sizeof(struct sockaddr_in6);
265         break;
266 #endif
267     default:
268         sl = 0;
269         break;
270     }
271     if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
272         fatal(0,"socket index out of range or not open",NULL);
273     errno = 0;
274     k = sendto(descriptors[which],packet,(size_t)length,0,
275             (struct sockaddr *)&there[which],sl);
276     if (k != length) fatal(1,"unable to send NTP packet",NULL);
277 }
278
279
280
281 extern int read_socket (int which, void *packet, int length, int waiting) {
282
283 /* Read a packet and return its length or -1 for failure.  Only incorrect
284 length and timeout are not fatal. */
285
286 #ifdef HAVE_IPV6
287     struct sockaddr_storage scratch, *ptr;
288 #else
289     struct sockaddr_in scratch, *ptr;
290 #endif
291     int n;
292     int k;
293
294 /* Under normal circumstances, set up a timeout. */
295
296     if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
297         fatal(0,"socket index out of range or not open",NULL);
298     if (waiting > 0) {
299         if (setjmp(jump_buffer)) {
300             if (verbose > 2)
301                 fprintf(stderr,"Receive timed out\n");
302             else if (verbose > 1)
303                 fprintf(stderr,"%s: receive timed out after %d seconds\n",
304                     argv0,waiting);
305             return -1;
306         }
307         errno = 0;
308         if (signal(SIGALRM,jump_handler) == SIG_ERR)
309             fatal(1,"unable to set up signal handler",NULL);
310         alarm((unsigned int)waiting);
311     }
312
313 /* Get the packet and clear the timeout, if any.  */
314
315     if (operation == op_server)
316         memcpy(ptr = &there[which],&here[which],sizeof(scratch));
317     else
318         memcpy(ptr = &scratch,&there[which],sizeof(scratch));
319     n = sizeof(scratch);
320     errno = 0;
321     k = recvfrom(descriptors[which],packet,(size_t)length,0,
322         (struct sockaddr *)ptr,&n);
323     if (waiting > 0) clear_alarm();
324
325 /* Now issue some low-level diagnostics. */
326
327     if (k <= 0) fatal(1,"unable to receive NTP packet from server",NULL);
328     if (verbose > 2) {
329         fprintf(stderr,"Packet of length %d received from ",k);
330         display_sock_in_hex(ptr);
331         fputc('\n',stderr);
332     }
333     return k;
334 }
335
336
337
338 extern int flush_socket (int which) {
339
340 /* Get rid of any outstanding input, because it may have been hanging around
341 for a while.  Ignore packet length oddities and return the number of packets
342 skipped. */
343
344 #ifdef HAVE_IPV6
345     struct sockaddr_storage scratch;
346 #else
347     struct sockaddr_in scratch;
348 #endif
349     int n;
350     char buffer[256];
351     int flags, count = 0, total = 0, k;
352
353 /* The code is the obvious. */
354
355     if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
356         fatal(0,"socket index out of range or not open",NULL);
357     if (verbose > 2) fprintf(stderr,"Flushing outstanding packets\n");
358     errno = 0;
359     if ((flags = fcntl(descriptors[which],F_GETFL,0)) < 0 ||
360             fcntl(descriptors[which],F_SETFL,flags|O_NONBLOCK) == -1)
361         fatal(1,"unable to set non-blocking mode",NULL);
362     while (1) {
363         n = sizeof(scratch);
364         errno = 0;
365         k = recvfrom(descriptors[which],buffer,256,0,
366             (struct sockaddr *)&scratch,&n);
367         if (k < 0) {
368             if (errno == EAGAIN || errno == EWOULDBLOCK) break;
369             fatal(1,"unable to flush socket",NULL);
370         }
371         ++count;
372         total += k;
373     }
374     errno = 0;
375     if (fcntl(descriptors[which],F_SETFL,flags) == -1)
376         fatal(1,"unable to restore blocking mode",NULL);
377     if (verbose > 2)
378         fprintf(stderr,"Flushed %d packets totalling %d bytes\n",count,total);
379     return count;
380 }
381
382
383
384 extern void close_socket (int which) {
385
386 /* There is little point in shielding this with a timeout, because any hangs
387 are unlikely to be interruptible.  It can get called when the sockets haven't
388 been opened, so ignore that case. */
389
390     if (which < 0 || which >= MAX_SOCKETS)
391         fatal(0,"socket index out of range",NULL);
392     if (descriptors[which] < 0) return;
393     errno = 0;
394     if (close(descriptors[which])) fatal(1,"unable to close NTP socket",NULL);
395 }