This is Unofficial EPICS BASE Doxygen Site
osdNetIntf.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /*
11  * WIN32 specific initialisation for bsd sockets,
12  * based on Chris Timossi's base/src/ca/windows_depend.c,
13  * and also further additions by Kay Kasemir when this was in
14  * dllmain.cc
15  *
16  * 7-1-97 -joh-
17  *
18  */
19 
20 /*
21  * ANSI C
22  */
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 /*
27  * WIN32 specific
28  */
29 #define VC_EXTRALEAN
30 #define STRICT
31 #include <winsock2.h>
32 #include <ws2tcpip.h>
33 
34 /*
35  * EPICS
36  */
37 #include "osiSock.h"
38 #include "errlog.h"
39 #include "epicsThread.h"
40 #include "epicsVersion.h"
41 
42 static osiSockAddr osiLocalAddrResult;
43 static epicsThreadOnceId osiLocalAddrId = EPICS_THREAD_ONCE_INIT;
44 
45 /*
46  * osiLocalAddr ()
47  */
48 static void osiLocalAddrOnce ( void *raw )
49 {
50  SOCKET *psocket = raw;
51  osiSockAddr addr;
52  int status;
53  INTERFACE_INFO *pIfinfo;
54  INTERFACE_INFO *pIfinfoList = NULL;
55  unsigned nelem;
56  DWORD numifs;
57  DWORD cbBytesReturned;
58 
59  memset ( (void *) &addr, '\0', sizeof ( addr ) );
60  addr.sa.sa_family = AF_UNSPEC;
61 
62  /* only valid for winsock 2 and above */
63  if ( wsaMajorVersion() < 2 ) {
64  goto fail;
65  }
66 
67  nelem = 100;
68  pIfinfoList = (INTERFACE_INFO *) calloc ( nelem, sizeof (INTERFACE_INFO) );
69  if (!pIfinfoList) {
70  errlogPrintf ("calloc failed\n");
71  goto fail;
72  }
73 
74  status = WSAIoctl (*psocket, SIO_GET_INTERFACE_LIST, NULL, 0,
75  (LPVOID)pIfinfoList, nelem*sizeof(INTERFACE_INFO),
76  &cbBytesReturned, NULL, NULL);
77 
78  if (status != 0 || cbBytesReturned == 0) {
79  errlogPrintf ("WSAIoctl SIO_GET_INTERFACE_LIST failed %d\n",WSAGetLastError());
80  goto fail;
81  }
82 
83  numifs = cbBytesReturned / sizeof(INTERFACE_INFO);
84  for (pIfinfo = pIfinfoList; pIfinfo < (pIfinfoList+numifs); pIfinfo++){
85 
86  /*
87  * dont use interfaces that have been disabled
88  */
89  if (!(pIfinfo->iiFlags & IFF_UP)) {
90  continue;
91  }
92 
93  /*
94  * dont use the loop back interface
95  */
96  if (pIfinfo->iiFlags & IFF_LOOPBACK) {
97  continue;
98  }
99 
100  addr.sa = pIfinfo->iiAddress.Address;
101 
102  /* Work around MS Winsock2 bugs */
103  if (addr.sa.sa_family == 0) {
104  addr.sa.sa_family = AF_INET;
105  }
106 
107  osiLocalAddrResult = addr;
108  free ( pIfinfoList );
109  return;
110  }
111 
112  errlogPrintf (
113  "osiLocalAddr(): only loopback found\n");
114 fail:
115  /* fallback to loopback */
116  memset ( (void *) &addr, '\0', sizeof ( addr ) );
117  addr.ia.sin_family = AF_INET;
118  addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
119  osiLocalAddrResult = addr;
120 
121  free ( pIfinfoList );
122 }
123 
124 LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr (SOCKET socket)
125 {
126  epicsThreadOnce(&osiLocalAddrId, osiLocalAddrOnce, (void*)&socket);
127  return osiLocalAddrResult;
128 }
129 
130 /*
131  * osiSockDiscoverBroadcastAddresses ()
132  */
133 LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses
134  (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr)
135 {
136  int status;
137  INTERFACE_INFO *pIfinfo;
138  INTERFACE_INFO *pIfinfoList;
139  unsigned nelem;
140  int numifs;
141  DWORD cbBytesReturned;
142  osiSockAddrNode *pNewNode;
143 
144  if ( pMatchAddr->sa.sa_family == AF_INET ) {
145  if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) {
146  pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) );
147  if ( pNewNode == NULL ) {
148  return;
149  }
150  pNewNode->addr.ia.sin_family = AF_INET;
151  pNewNode->addr.ia.sin_port = htons ( 0 );
152  pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
153  ellAdd ( pList, &pNewNode->node );
154  return;
155  }
156  }
157 
158  /* only valid for winsock 2 and above */
159  if (wsaMajorVersion() < 2 ) {
160  fprintf(stderr, "Need to set EPICS_CA_AUTO_ADDR_LIST=NO for winsock 1\n");
161  return;
162  }
163 
164  nelem = 100;
165  pIfinfoList = (INTERFACE_INFO *) calloc(nelem, sizeof(INTERFACE_INFO));
166  if(!pIfinfoList){
167  return;
168  }
169 
170  status = WSAIoctl (socket, SIO_GET_INTERFACE_LIST,
171  NULL, 0,
172  (LPVOID)pIfinfoList, nelem*sizeof(INTERFACE_INFO),
173  &cbBytesReturned, NULL, NULL);
174 
175  if (status != 0 || cbBytesReturned == 0) {
176  fprintf(stderr, "WSAIoctl SIO_GET_INTERFACE_LIST failed %d\n",WSAGetLastError());
177  free(pIfinfoList);
178  return;
179  }
180 
181  numifs = cbBytesReturned/sizeof(INTERFACE_INFO);
182  for (pIfinfo = pIfinfoList; pIfinfo < (pIfinfoList+numifs); pIfinfo++){
183 
184  /*
185  * dont bother with interfaces that have been disabled
186  */
187  if (!(pIfinfo->iiFlags & IFF_UP)) {
188  continue;
189  }
190 
191  if (pIfinfo->iiFlags & IFF_LOOPBACK) {
192  continue;
193  }
194 
195  /*
196  * work around WS2 bug
197  */
198  if (pIfinfo->iiAddress.Address.sa_family != AF_INET) {
199  if (pIfinfo->iiAddress.Address.sa_family == 0) {
200  pIfinfo->iiAddress.Address.sa_family = AF_INET;
201  }
202  }
203 
204  /*
205  * if it isnt a wildcarded interface then look for
206  * an exact match
207  */
208  if (pMatchAddr->sa.sa_family != AF_UNSPEC) {
209  if (pIfinfo->iiAddress.Address.sa_family != pMatchAddr->sa.sa_family) {
210  continue;
211  }
212  if (pIfinfo->iiAddress.Address.sa_family != AF_INET) {
213  continue;
214  }
215  if (pMatchAddr->sa.sa_family != AF_INET) {
216  continue;
217  }
218  if (pMatchAddr->ia.sin_addr.s_addr != htonl(INADDR_ANY)) {
219  if (pIfinfo->iiAddress.AddressIn.sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr) {
220  continue;
221  }
222  }
223  }
224 
225  pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
226  if (pNewNode==NULL) {
227  errlogPrintf ("osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n");
228  return;
229  }
230 
231  if (pIfinfo->iiAddress.Address.sa_family == AF_INET &&
232  pIfinfo->iiFlags & IFF_BROADCAST) {
233  const unsigned mask = pIfinfo->iiNetmask.AddressIn.sin_addr.s_addr;
234  const unsigned bcast = pIfinfo->iiBroadcastAddress.AddressIn.sin_addr.s_addr;
235  const unsigned addr = pIfinfo->iiAddress.AddressIn.sin_addr.s_addr;
236  unsigned result = (addr & mask) | (bcast &~mask);
237  pNewNode->addr.ia.sin_family = AF_INET;
238  pNewNode->addr.ia.sin_addr.s_addr = result;
239  pNewNode->addr.ia.sin_port = htons ( 0 );
240  }
241  else {
242  pNewNode->addr.sa = pIfinfo->iiBroadcastAddress.Address;
243  }
244 
245  /*
246  * LOCK applied externally
247  */
248  ellAdd (pList, &pNewNode->node);
249  }
250 
251  free (pIfinfoList);
252 }
LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses(ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr)
Definition: osdNetIntf.c:68
#define INADDR_LOOPBACK
Definition: osdSock.h:76
pvac::PutEvent result
Definition: clientSync.cpp:117
osiSockAddr addr
Definition: osiSock.h:163
pvd::Status status
struct sockaddr sa
Definition: osiSock.h:158
struct sockaddr_in ia
Definition: osiSock.h:157
#define NULL
Definition: catime.c:38
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr(SOCKET socket)
Definition: osdNetIntf.c:347
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
LIBCOM_API unsigned epicsStdCall wsaMajorVersion()
Definition: osdSock.c:41
int SOCKET
Definition: osdSock.h:31
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
ELLNODE node
Definition: osiSock.h:162
#define stderr
Definition: epicsStdio.h:32
List header type.
Definition: ellLib.h:56
C++ and C descriptions for a thread.