1/*  Copyright (C) 1996, 2000 N.M. Maclaren
2    Copyright (C) 1996, 2000 The University of Cambridge
3
4This includes all of the code needed to handle Berkeley sockets.  It is way
5outside current POSIX, unfortunately.  It should be easy to convert to a system
6that uses another mechanism.  It does not currently use socklen_t, because
7the 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
24functions. */
25
26static int initial = 1,
27    descriptors[MAX_SOCKETS];
28
29#ifdef HAVE_IPV6
30static struct sockaddr_storage here[MAX_SOCKETS], there[MAX_SOCKETS];
31#else
32static struct sockaddr_in here[MAX_SOCKETS], there[MAX_SOCKETS];
33#endif
34
35void display_in_hex(const void *, int);
36#ifdef HAVE_IPV6
37void display_sock_in_hex(struct sockaddr_storage *);
38#else
39void display_sock_in_hex (struct sockaddr_in *);
40#endif
41
42/* There needs to be some disgusting grobble for handling timeouts, that is
43identical to the grobble in internet.c. */
44
45static jmp_buf jump_buffer;
46
47static void jump_handler (int sig) {
48    longjmp(jump_buffer,1);
49}
50
51static 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
64void 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
73void 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
97void 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
113extern int unprivport;
114
115#ifdef HAVE_IPV6
116
117void open_socket (int which, char *hostname, int timespan) {
118
119/* Locate the specified NTP server, set up a couple of addresses and open a
120socket. */
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
126number 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
146be 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
185void open_socket (int which, char *hostname, int timespan) {
186
187/* Locate the specified NTP server, set up a couple of addresses and open a
188socket. */
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
194number 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
244extern void write_socket (int which, void *packet, int length) {
245
246/* Any errors in doing this are fatal - including blocking.  Yes, this leaves a
247server 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
274extern 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
277length 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
328extern int flush_socket (int which) {
329
330/* Get rid of any outstanding input, because it may have been hanging around
331for a while.  Ignore packet length oddities and return the number of packets
332skipped. */
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
374extern void close_socket (int which) {
375
376/* There is little point in shielding this with a timeout, because any hangs
377are unlikely to be interruptible.  It can get called when the sockets haven't
378been 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}
386