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