reindent-20030715
[openafs.git] / src / ntp / ntp_sock.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #ifdef  AFS_SUN5_ENV
19 #define BSD_COMP
20 #endif
21 #include <sys/ioctl.h>
22 #ifdef  AFS_SUN5_ENV
23 #include <fcntl.h>
24 #endif
25 #include <sys/file.h>
26 #include <sys/time.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <net/if.h>
30 #include <errno.h>
31 #include <syslog.h>
32 #include <stdio.h>
33 #include "ntp.h"
34
35 #define MAX_INTF        10
36 struct intf addrs[MAX_INTF];
37 int nintf;
38
39 #ifdef  TEST
40 extern int errno;
41
42 #include "AFS_component_version_number.c"
43
44 main()
45 {
46     int i, cc, val;
47     char foo[10];
48
49     syslog(LOG_ERR, "ifconfig test");
50     create_sockets(htons(43242));
51     for (i = 0; i < nintf; i++) {
52         printf("%d: %s fd %d  addr %s  mask %x ", i, addrs[i].name,
53                addrs[i].fd, inet_ntoa(addrs[i].sin.sin_addr.s_addr),
54                ntohl(addrs[i].mask.sin_addr.s_addr));
55         cc = sizeof(val);
56         if (getsockopt
57             (addrs[0].fd, SOL_SOCKET, SO_BROADCAST, (char *)&val, &cc)) {
58             perror("getsockopt");
59             exit(1);
60         }
61         printf("BCAST opt %d", val);
62         cc = sizeof(val);
63         if (getsockopt(addrs[0].fd, SOL_SOCKET, SO_RCVBUF, (char *)&val, &cc)) {
64             perror("getsockopt");
65             exit(1);
66         }
67         printf("sockbuf size = %d ", val);
68         putchar('\n');
69     }
70
71     for (i = 0; i < nintf; i++) {
72         fprintf(stderr, "Read fd %d.. ", addrs[i].fd);
73         cc = read(addrs[i].fd, foo, 10);
74         fprintf(stderr, " returns %d ", cc);
75         perror("read errno");
76     }
77 }
78 #endif
79
80 #ifndef SIOCGIFCONF
81 /*
82  *  If we can't determine the interface configuration, just listen with one
83  *  socket at the INADDR_ANY address.
84  */
85 create_sockets(port)
86      unsigned int port;
87 {
88     addrs[0].sin.sin_family = AF_INET;
89     addrs[0].sin.sin_port = 0;
90     addrs[0].sin.sin_addr.s_addr = INADDR_ANY;
91     addrs[0].sin.sin_mask.s_addr = htonl(~0);
92     addrs[0].name = "wildcard";
93
94     if ((addrs[0].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
95         syslog(LOG_ERR, "socket() failed: %m");
96 #ifdef  TEST
97         perror("socket() failed");
98 #endif
99         exit(1);
100      /*NOTREACHED*/}
101
102     if (fcntl(addrs[i].fd, F_SETFL, FNDELAY) < 0) {
103         syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
104 #ifdef  TEST
105         perror("fcntl(FNDELAY) fails");
106 #endif
107         exit(1);
108      /*NOTREACHED*/}
109     addrs[0].sin.sin_family = AF_INET;
110     addrs[0].sin.sin_port = port;
111     addrs[0].if_flags = 0;
112     if (bind
113         (addrs[0].fd, (struct sockaddr *)&addrs[0].sin,
114          sizeof(addrs[0].sin)) < 0) {
115         syslog(LOG_ERR, "bind() fails: %m");
116 #ifdef  TEST
117         perror("bind fails\n");
118 #endif
119         exit(1);
120     }
121     nintf = 1;
122     return nintf;
123 }
124 #else
125 /*
126  *  Grab interface configuration, and create a socket for each interface
127  *  address.
128  */
129 create_sockets(port)
130      unsigned int port;
131 {
132     char buf[1024];
133     struct ifconf ifc;
134     struct ifreq ifreq, *ifr;
135     int on = 1, off = 0;
136     int n, i, vs;
137     extern char *malloc();
138
139     /*
140      * create pseudo-interface with wildcard address
141      */
142     addrs[nintf].sin.sin_family = AF_INET;
143     addrs[nintf].sin.sin_port = 0;
144     addrs[nintf].sin.sin_addr.s_addr = INADDR_ANY;
145     addrs[nintf].name = "wild";
146     addrs[nintf].mask.sin_addr.s_addr = htonl(~0);
147
148     nintf = 1;
149
150     if ((vs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
151         syslog(LOG_ERR, "vs=socket(AF_INET, SOCK_DGRAM) %m");
152 #ifdef  TEST
153         perror("vs=socket(AF_INET, SOCK_DGRAM)");
154 #endif
155         exit(1);
156     }
157     ifc.ifc_len = sizeof(buf);
158     ifc.ifc_buf = buf;
159     if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
160         syslog(LOG_ERR, "get interface configuration: %m");
161 #ifdef  TEST
162         perror("ioctl(SIOCGIFCONF) fails");
163 #endif
164         exit(1);
165     }
166     n = ifc.ifc_len / sizeof(struct ifreq);
167
168     for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
169         if (ifr->ifr_addr.sa_family != AF_INET)
170             continue;
171         ifreq = *ifr;
172         if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
173             syslog(LOG_ERR, "get interface flags: %m");
174 #ifdef  TEST
175             perror("SIOCGIFFFLAGS fails");
176 #endif
177             continue;
178         }
179         if ((ifreq.ifr_flags & IFF_UP) == 0)
180             continue;
181         addrs[nintf].if_flags = ifreq.ifr_flags;
182
183         if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
184             syslog(LOG_ERR, "get interface addr: %m");
185 #ifdef  TEST
186             perror("SIOCGIFADDR fails");
187 #endif
188             continue;
189         }
190         if ((addrs[nintf].name = malloc(strlen(ifreq.ifr_name) + 1))
191             == NULL) {
192             syslog(LOG_ERR, "malloc failed");
193             exit(1);
194         }
195         strcpy(addrs[nintf].name, ifreq.ifr_name);
196         addrs[nintf].sin = *(struct sockaddr_in *)&ifreq.ifr_addr;
197
198 #ifdef SIOCGIFBRDADDR
199         if (addrs[nintf].if_flags & IFF_BROADCAST) {
200             if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
201                 syslog(LOG_ERR, "SIOCGIFBRDADDR fails");
202 #ifdef  TEST
203                 perror("SIOCGIFBRDADDR fails");
204 #endif
205                 exit(1);
206             }
207 #ifdef ifr_broadaddr
208             addrs[nintf].bcast = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
209 #else
210             addrs[nintf].bcast = *(struct sockaddr_in *)&ifreq.ifr_addr;
211 #endif
212         }
213 #endif /* SIOCGIFBRDADDR */
214 #ifdef SIOCGIFNETMASK
215         if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
216             syslog(LOG_ERR, "SIOCGIFNETMASK fails");
217 #ifdef  TEST
218             perror("SIOCGIFNETMASK fails");
219 #endif
220             exit(1);
221         }
222         addrs[nintf].mask = *(struct sockaddr_in *)&ifreq.ifr_addr;
223 #endif /* SIOCGIFNETMASK */
224
225         /* 
226          * look for an already existing source interface address.  If
227          * the machine has multiple point to point interfaces, then 
228          * the local address may appear more than once.
229          */
230         for (i = 0; i < nintf; i++)
231             if (addrs[i].sin.sin_addr.s_addr ==
232                 addrs[nintf].sin.sin_addr.s_addr) {
233 #ifdef TEST
234                 printf("dup interface address %s on %s\n",
235                        inet_ntoa(addrs[nintf].sin.sin_addr.s_addr),
236                        ifreq.ifr_name);
237 #endif
238                 goto next;
239             }
240         nintf++;
241       next:;
242     }
243     close(vs);
244
245     for (i = 0; i < nintf; i++) {
246         /* create a datagram (UDP) socket */
247         if ((addrs[i].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
248             syslog(LOG_ERR, "socket() failed: %m");
249 #ifdef  TEST
250             perror("socket(AF_INET, SOCK_DGRAM) fails");
251 #endif
252             exit(1);
253          /*NOTREACHED*/}
254
255         /* set SO_REUSEADDR since we will be binding the same port
256          * number on each interface */
257         if (setsockopt
258             (addrs[i].fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
259              sizeof(on))) {
260 #ifdef  TEST
261             perror("setsockopt SO_REUSEADDR on");
262 #endif
263             syslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m");
264         }
265
266         /*
267          * set non-blocking I/O on the descriptor
268          */
269         if (fcntl(addrs[i].fd, F_SETFL, FNDELAY) < 0) {
270             syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
271 #ifdef  TEST
272             perror("fcntl(F_SETFL, FNDELAY) fails");
273 #endif
274             exit(1);
275          /*NOTREACHED*/}
276
277         /*
278          * finally, bind the local address address.
279          */
280         addrs[i].sin.sin_family = AF_INET;
281         addrs[i].sin.sin_port = port;
282         if (bind
283             (addrs[i].fd, (struct sockaddr *)&addrs[i].sin,
284              sizeof(addrs[i].sin)) < 0) {
285             syslog(LOG_ERR, "bind() fails: %m");
286 #ifdef  TEST
287             perror("bind fails");
288 #endif
289             exit(1);
290         }
291
292         /*
293          *  Turn off the SO_REUSEADDR socket option.  It apparently
294          *  causes heartburn on systems with multicast IP installed.
295          *  On normal systems it only gets looked at when the address
296          *  is being bound anyway..
297          */
298         if (setsockopt
299             (addrs[i].fd, SOL_SOCKET, SO_REUSEADDR, (char *)&off,
300              sizeof(off))) {
301             syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m");
302 #ifdef  TEST
303             perror("setsockopt SO_REUSEADDR off");
304 #endif
305         }
306 #ifdef SO_BROADCAST
307         /* if this interface can support broadcast, set SO_BROADCAST */
308         if (addrs[i].if_flags & IFF_BROADCAST) {
309             if (setsockopt
310                 (addrs[i].fd, SOL_SOCKET, SO_BROADCAST, (char *)&on,
311                  sizeof(on))) {
312                 syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
313 #ifdef  TEST
314                 perror("setsockopt(SO_BROADCAST) on");
315 #endif
316             }
317         }
318 #endif /* SO_BROADCAST */
319     }
320     return nintf;
321 }
322
323 #endif