1 /* $NetBSD: socket.c,v 1.7 2006/07/29 10:21:37 kardel Exp $ */
3 /* Copyright (C) 1996, 2000 N.M. Maclaren
4 Copyright (C) 1996, 2000 The University of Cambridge
6 This includes all of the code needed to handle Berkeley sockets. It is way
7 outside current POSIX, unfortunately. It should be easy to convert to a system
8 that uses another mechanism. It does not currently use socklen_t, because
9 the only system that the author uses that has it is Linux. */
23 /* The code needs to set some variables during the open, for use by later
26 static int initial
= 1,
27 descriptors
[MAX_SOCKETS
];
30 static struct sockaddr_storage here
[MAX_SOCKETS
], there
[MAX_SOCKETS
];
32 static struct sockaddr_in here
[MAX_SOCKETS
], there
[MAX_SOCKETS
];
35 void display_in_hex(const void *, int);
37 void display_sock_in_hex(struct sockaddr_storage
*);
39 void display_sock_in_hex (struct sockaddr_in
*);
42 /* There needs to be some disgusting grobble for handling timeouts, that is
43 identical to the grobble in internet.c. */
45 static jmp_buf jump_buffer
;
47 static void jump_handler (int sig
) {
48 longjmp(jump_buffer
,1);
51 static void clear_alarm (void) {
57 if (signal(SIGALRM
,SIG_DFL
) == SIG_ERR
)
58 fatal(1,"unable to reset signal handler",NULL
);
64 void display_in_hex (const void *data
, int length
) {
67 for (i
= 0; i
< length
; ++i
)
68 fprintf(stderr
,"%.2x",((const unsigned char *)data
)[i
]);
73 void display_sock_in_hex (struct sockaddr_storage
*sock
) {
75 struct sockaddr_in
*sin
;
76 struct sockaddr_in6
*sin6
;
78 family
= sock
->ss_family
;
81 sin
= (struct sockaddr_in
*)sock
;
82 display_in_hex(&sin
->sin_addr
, sizeof(struct in_addr
));
84 display_in_hex(&sin
->sin_port
, 2);
87 sin6
= (struct sockaddr_in6
*)sock
;
88 display_in_hex(&sin6
->sin6_addr
, sizeof(struct in6_addr
));
90 display_in_hex(&sin6
->sin6_port
, 2);
97 void display_sock_in_hex (struct sockaddr_in
*sock
) {
99 struct sockaddr_in
*sin
;
101 family
= sock
->sin_family
;
104 sin
= (struct sockaddr_in
*)sock
;
105 display_in_hex(&sin
->sin_addr
, sizeof(struct in_addr
));
107 display_in_hex(&sin
->sin_port
, 2);
113 extern int unprivport
;
117 void open_socket (int which
, char *hostname
, int timespan
) {
119 /* Locate the specified NTP server, set up a couple of addresses and open a
123 struct sockaddr_storage address
, anywhere
;
125 /* Initialise and find out the server and port number. Note that the port
126 number is in network format. */
129 for (k
= 0; k
< MAX_SOCKETS
; ++k
)
132 if (which
< 0 || which
>= MAX_SOCKETS
|| descriptors
[which
] >= 0)
133 fatal(0,"socket index out of range or already open",NULL
);
135 fprintf(stderr
,"Looking for the socket addresses\n");
136 find_address(&address
,&anywhere
,&port
,hostname
,timespan
);
138 fprintf(stderr
,"Internet address: address=");
139 display_sock_in_hex(&address
);
140 fprintf(stderr
," anywhere=");
141 display_sock_in_hex(&anywhere
);
145 /* Set up our own and the target addresses. Note that the target address will
146 be reset before use in server mode. */
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
;
155 fprintf(stderr
,"Initial sockets: here=");
156 display_sock_in_hex(&here
[which
]);
157 fprintf(stderr
," there=");
158 display_sock_in_hex(&there
[which
]);
162 /* Allocate a local UDP socket and configure it. */
164 switch(((struct sockaddr_in
*)&there
[which
])->sin_family
) {
166 sl
= sizeof(struct sockaddr_in
);
170 sl
= sizeof(struct sockaddr_in6
);
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
);
185 void open_socket (int which
, char *hostname
, int timespan
) {
187 /* Locate the specified NTP server, set up a couple of addresses and open a
191 struct in_addr address
, anywhere
;
193 /* Initialise and find out the server and port number. Note that the port
194 number is in network format. */
196 if (initial
) for (k
= 0; k
< MAX_SOCKETS
; ++k
) descriptors
[k
] = -1;
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
);
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
));
210 /* Set up our own and the target addresses. */
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
;
222 fprintf(stderr
,"Initial sockets: here=");
223 display_in_hex(&here
[which
].sin_addr
,sizeof(struct in_addr
));
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
));
229 display_in_hex(&there
[which
].sin_port
,sizeof(there
[which
].sin_port
));
233 /* Allocate a local UDP socket and configure it. */
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
);
244 extern void write_socket (int which
, void *packet
, int length
) {
246 /* Any errors in doing this are fatal - including blocking. Yes, this leaves a
247 server vulnerable to a denial of service attack. */
251 switch(((struct sockaddr_in
*)&there
[which
])->sin_family
) {
253 sl
= sizeof(struct sockaddr_in
);
257 sl
= sizeof(struct sockaddr_in6
);
264 if (which
< 0 || which
>= MAX_SOCKETS
|| descriptors
[which
] < 0)
265 fatal(0,"socket index out of range or not open",NULL
);
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
);
274 extern int read_socket (int which
, void *packet
, int length
, int waiting
) {
276 /* Read a packet and return its length or -1 for failure. Only incorrect
277 length and timeout are not fatal. */
280 struct sockaddr_storage scratch
, *ptr
;
282 struct sockaddr_in scratch
, *ptr
;
287 /* Under normal circumstances, set up a timeout. */
289 if (which
< 0 || which
>= MAX_SOCKETS
|| descriptors
[which
] < 0)
290 fatal(0,"socket index out of range or not open",NULL
);
292 if (setjmp(jump_buffer
)) {
294 fprintf(stderr
,"Receive timed out\n");
295 else if (verbose
> 1)
296 fprintf(stderr
,"%s: receive timed out after %d seconds\n",
301 if (signal(SIGALRM
,jump_handler
) == SIG_ERR
)
302 fatal(1,"unable to set up signal handler",NULL
);
303 alarm((unsigned int)waiting
);
306 /* Get the packet and clear the timeout, if any. */
308 memcpy(ptr
= &scratch
,&there
[which
],sizeof(scratch
));
311 k
= recvfrom(descriptors
[which
],packet
,(size_t)length
,0,
312 (struct sockaddr
*)ptr
,&n
);
313 if (waiting
> 0) clear_alarm();
315 /* Now issue some low-level diagnostics. */
317 if (k
<= 0) fatal(1,"unable to receive NTP packet from server",NULL
);
319 fprintf(stderr
,"Packet of length %d received from ",k
);
320 display_sock_in_hex(ptr
);
328 extern int flush_socket (int which
) {
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
335 struct sockaddr_storage scratch
;
337 struct sockaddr_in scratch
;
341 int flags
, count
= 0, total
= 0, k
;
343 /* The code is the obvious. */
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");
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
);
355 k
= recvfrom(descriptors
[which
],buffer
,256,0,
356 (struct sockaddr
*)&scratch
,&n
);
358 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) break;
359 fatal(1,"unable to flush socket",NULL
);
365 if (fcntl(descriptors
[which
],F_SETFL
,flags
) == -1)
366 fatal(1,"unable to restore blocking mode",NULL
);
368 fprintf(stderr
,"Flushed %d packets totalling %d bytes\n",count
,total
);
374 extern void close_socket (int which
) {
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. */
380 if (which
< 0 || which
>= MAX_SOCKETS
)
381 fatal(0,"socket index out of range",NULL
);
382 if (descriptors
[which
] < 0) return;
384 if (close(descriptors
[which
])) fatal(1,"unable to close NTP socket",NULL
);