FreeWRL / FreeX3D 4.3.0
socketutils.c
1
2
3/* socket bind can be over-ridden by pthread.h bind if you include that.
4 which was happening for me.
5 So isolating the socket stuff means I can use simpler sockets-only includes.
6*/
7#include <memory.h>
8#include <stdio.h>
9#include <string.h>
10#include "Component_DIS.h" //for dis_socket
11
12
13
14
15#ifdef WIN32
16 #ifndef WIN32_LEAN_AND_MEAN
17 #define WIN32_LEAN_AND_MEAN
18 #endif
19 #define strdup _strdup
20 #include <winsock2.h>
21 #include <ws2tcpip.h> /* for TCPIP - are we using tcp? */
22 #define SHUT_RDWR SD_BOTH
23 #include <windows.h>
24 #define snprintf _snprintf
25 //#define sscanf sscanf_s
26 #define STRTOK_S strtok_s
27
28
29char* ErrorString(DWORD err)
30{
31 //don't free the resulting string
32 char * Error;
33 LPTSTR s;
34 if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
35 FORMAT_MESSAGE_FROM_SYSTEM,
36 NULL,
37 err,
38 0,
39 (LPTSTR)&s,
40 0,
41 NULL) == 0)
42 { // failed
43 // Unknown error code %08x (%d)
44 static char * unk = "unknown error";
45 Error = (char *)unk;
46 } /* failed */
47 else
48 { /* success */
49 char* p = strchr(s, '\r');
50 if(p != NULL)
51 { /* lose CRLF */
52 *p = '\0';
53 } /* lose CRLF */
54 Error = s;
55 } /* success */
56 return Error;
57} // ErrorString
58
59void print_socket_error(char *message, int error){
60 int lasterror = WSAGetLastError();
61 printf("%s %d ",message,lasterror);
62 printf(" %s \n",ErrorString(lasterror));
63}
64
65#else
66 #include <sys/ioctl.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <errno.h>
71 #include <netdb.h>
72 #include <unistd.h>
73 #define ioctlsocket ioctl
74 #define SOCKET int
75 #define SOCKET_ERROR SO_ERROR
76 #define STRTOK_S strtok_r
77void print_socket_error(char *message, int error){
78 printf("%s %d \n",message,error);
79}
80#endif
81
82#ifdef _MSC_VER
83#include <direct.h>
84#define chdir _chdir
85#define strcasecmp _stricmp
86WSADATA wsaData;
87void initialize_sockets(){
88 int iResult;
89 // Initialize Winsock
90 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
91 if (iResult != 0) {
92 printf("WSAStartup failed: %d\n", iResult);
93 }
94}
95#else
96void initialize_sockets(){}
97#endif
98
99
100
102 int port;
103 char *address;
104 SOCKET socket;
105 struct sockaddr_in saddr;
106 int multicastRelayPort;
107 char *multicastRelayHost;
108 int idir; //0 = receive, 1 = send
109 struct Vector *registered;
110 double lasttime;
111};
112
113
114
115
116
117#ifdef WIN32
118int sockwrite(SOCKET s, char *buf, int len){
119 return send(s,buf,len,0);
120}
121int sockread(SOCKET s, char *buf, int len){
122 return recv(s,buf,len,0);
123}
124
125int socksendto(struct dis_socket *dsock, char *buf, int len){
126 int iret;
127 if( iret = sendto(dsock->socket, buf, len, 0,
128 (struct sockaddr *)&dsock->saddr, sizeof(struct sockaddr)) == SOCKET_ERROR){
129 printf("sendto failed with error %d\n", WSAGetLastError());
130 }
131 return iret;
132}
133
134int sockrecvfrom(struct dis_socket *dsock, char *buf, int len){
135 // receive packet from socket
136 int status, fromlen;
137 fromlen = sizeof(struct sockaddr);
138 status = recvfrom(dsock->socket, buf, len, 0,
139 (struct sockaddr *)&dsock->saddr, &fromlen );
140 // I think -1 is normal for non-blocking when no data
141 // if(status < 0) print_socket_error("recvfrom ",status);
142 return status;
143}
144
145#else
146int sockwrite(SOCKET s, const char *buf, int len){
147 return write(s,buf,len);
148}
149int sockread(SOCKET s, char *buf, int len){
150 return recv(s,buf,len,0);
151}
152
153int socksendto(struct dis_socket *dsock, char *buf, int len){
154 int iret;
155 if( iret = sendto(dsock->socket, buf, len, 0,
156 (struct sockaddr *)&dsock->saddr, sizeof(struct sockaddr)) == SOCKET_ERROR){
157 printf("sendto failed with error %d\n", errno);
158 }
159 return iret;
160}
161
162int sockrecvfrom(struct dis_socket *dsock, char *buf, int len){
163 // receive packet from socket
164 int status, fromlen;
165 fromlen = sizeof(struct sockaddr);
166 status = recvfrom(dsock->socket, buf, len, 0,
167 (struct sockaddr *)&dsock->saddr, (socklen_t *)&fromlen );
168 // I think -1 is normal for non-blocking when no data
169 // if(status < 0) print_socket_error("recvfrom ",status);
170 return status;
171}
172
173#endif
174
175
176
177void socket_open(struct dis_socket *dsock)
178{
179 //multicast socket
180 int nbytes, npdus, addrlen, on=1;
181 SOCKET sock;
182
183 initialize_sockets();
184 if(dsock->idir == 1){
185 //struct sockaddr_in addr;
186 int ier;
187 struct ip_mreq mreq;
188 //RECEIVE
189 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
190 // FIONBIO
191 setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, (const char *)&on, sizeof(int));
192 if( ier = ioctlsocket(sock, FIONBIO, (unsigned long *)&on) < 0)
193 {
194 print_socket_error("setting to nonblock failed",ier);
195 close(sock);
196 }
197 memset(&dsock->saddr,0,sizeof(struct sockaddr_in));
198 dsock->saddr.sin_family=AF_INET;
199 dsock->saddr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
200 dsock->saddr.sin_port=htons(dsock->port);
201
202 /* bind to receive address */
203 if (bind(sock,(struct sockaddr *) &dsock->saddr,sizeof(struct sockaddr_in)) < 0) {
204 printf("bind");
205 #ifdef _MSC_VER
206 printf("wsagetlasterror= %d\n",WSAGetLastError());
207 #endif
208 //goto exit;
209 }
210 mreq.imr_multiaddr.s_addr=inet_addr(dsock->address);
211 mreq.imr_interface.s_addr=htonl(INADDR_ANY);
212 if (setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mreq,sizeof(mreq)) < 0) {
213 char *errstr;
214 printf("setsockopt0 ");
215 #ifdef _MSC_VER
216 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
217 printf("wsagetlasterror= %d\n",WSAGetLastError());
218 errstr = ErrorString(WSAGetLastError());
219 printf("%s",errstr);
220 #endif
221
222 //goto exit;
223 }
224 printf("opened recv port\n");
225 dsock->socket = sock;
226 } else if(dsock->idir == 2){
227 //SEND
228 //http://www.tack.ch/multicast/
229 SOCKET sockout;
230
231 //struct sockaddr_in saddr;
232 struct in_addr iaddr;
233 unsigned char ttl = 3;
234 unsigned char one = 1;
235
236 // set content of struct saddr and imreq to zero
237 memset(&dsock->saddr, 0, sizeof(struct sockaddr_in));
238 memset(&iaddr, 0, sizeof(struct in_addr));
239
240 // open a UDP socket
241 sockout = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); //0
242 if ( sockout < 0 ){
243 printf("Error creating socket");
244 #ifdef _MSC_VER
245 printf( "%d\n",WSAGetLastError());
246 #endif
247
248 }
249
250 dsock->saddr.sin_family = PF_INET;
251 dsock->saddr.sin_port = htons(0); // Use the first free port
252 dsock->saddr.sin_addr.s_addr = htonl(INADDR_ANY); // bind socket to any interface
253 if(0)
254 if( bind(sockout, (struct sockaddr *)&dsock->saddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR){
255 printf("Error binding socket to interface");
256 #ifdef _MSC_VER
257 printf( "%d\n",WSAGetLastError());
258 #endif
259
260 }
261
262 iaddr.s_addr = INADDR_ANY; // use DEFAULT interface
263
264 // Set the outgoing interface to DEFAULT
265 if( setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_IF, (const char*) &iaddr,
266 sizeof(struct in_addr)) == SOCKET_ERROR){
267 printf("sockopt1 erro");
268 #ifdef _MSC_VER
269 printf( "%d\n",WSAGetLastError());
270 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
271 #endif
272 }
273
274 // Set multicast packet TTL to 3; default TTL is 1
275 if( setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
276 sizeof(unsigned char)) == SOCKET_ERROR){
277 printf("sockopt2 error");
278 #ifdef _MSC_VER
279 printf( "%d\n",WSAGetLastError());
280 #endif
281 }
282 // send multicast traffic to myself too
283 if( setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_LOOP,
284 &one, sizeof(unsigned char)) == SOCKET_ERROR){
285 printf("sockopt3 error");
286 #ifdef _MSC_VER
287 printf( "%d\n",WSAGetLastError());
288 #endif
289 }
290 if(1)
291 if( bind(sockout, (struct sockaddr *)&dsock->saddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR){
292 printf("Error binding socket to interface");
293 #ifdef _MSC_VER
294 printf( "%d\n",WSAGetLastError());
295 #endif
296 }
297
298 // set destination multicast address
299 dsock->saddr.sin_family = PF_INET;
300 dsock->saddr.sin_addr.s_addr = inet_addr(dsock->address);
301 dsock->saddr.sin_port = htons(dsock->port);
302 if(0)
303 if( bind(sockout, (struct sockaddr *)&dsock->saddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR){
304 printf("Error binding socket to interface");
305 #ifdef _MSC_VER
306 printf( "%d\n",WSAGetLastError());
307 #endif
308 }
309 dsock->socket = sockout;
310 printf("opened send port\n");
311
312 }
313}