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