Branch data Line data Source code
1 : :
2 : : #include "gwrl/socket.h"
3 : :
4 : : #ifdef __cplusplus
5 : : extern "C" {
6 : : #endif
7 : :
8 : 0 : socklen_t gwsk_sockaddr_size(struct sockaddr_storage * addr) {
9 : 0 : sa_family_t fam = addr->ss_family;
10 : 0 : if(fam == AF_INET) return sizeof(struct sockaddr_in);
11 [ # # ]: 0 : else if(fam == AF_INET6) return sizeof(struct sockaddr_in6);
12 : 0 : return 0;
13 : 0 : }
14 : :
15 : 0 : int gwsk_sockaddr_port(struct sockaddr_storage * addr) {
16 : 0 : sa_family_t fam = addr->ss_family;
17 : 0 : if(fam == AF_INET) return ntohs(((struct sockaddr_in *)addr)->sin_port);
18 [ # # ]: 0 : else if(fam == AF_INET6) return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
19 : 0 : return 0;
20 : 0 : }
21 : :
22 : 0 : void gwsk_sockaddr_print(struct sockaddr_storage * addr) {
23 : 0 : void * naddr = NULL;
24 : 0 : char buf[INET6_ADDRSTRLEN];
25 : 0 : sa_family_t fam = addr->ss_family;
26 : 0 : if(fam == AF_INET) naddr = &(((struct sockaddr_in *)addr)->sin_addr);
27 [ # # ]: 0 : else if(fam == AF_INET6) naddr = &(((struct sockaddr_in6 *)addr)->sin6_addr);
28 : 0 : inet_ntop(fam,naddr,buf,INET6_ADDRSTRLEN);
29 : 0 : fprintf(stdout,"gwsk_sockaddr_print: %s:%i\n",buf,gwsk_sockaddr_port(addr));
30 : 0 : }
31 : :
32 : 0 : void gwsk_addrinfo_print(struct addrinfo * addr) {
33 : 0 : gwsk_sockaddr_print((struct sockaddr_storage *)addr->ai_addr);
34 : 0 : }
35 : :
36 : : bool gwsk_startup() {
37 : : #if defined(PLATFORM_WINDOWS)
38 : : WSADATA WsaData;
39 : : return (WSAStartup(MAKEWORD(2,2),&WsaData) == 0);
40 : : #endif
41 : 0 : return true;
42 : : }
43 : :
44 : : bool gwsk_cleanup() {
45 : : #if defined(PLATFORM_WINDOWS)
46 : : return (WSACleanup() == 0);
47 : : #endif
48 : 0 : return true;
49 : : }
50 : :
51 : 0 : int gwsk_connect(sockid_t sockfd, struct sockaddr_storage * addr) {
52 : 0 : int res = 0;
53 : :
54 : : #if defined(PLATFORM_WINDOWS)
55 : : int errnm = 0;
56 : : #endif
57 : :
58 : 0 : while(1) {
59 : 0 : errno = 0;
60 : 0 : res = connect(sockfd,(struct sockaddr *)addr,gwsk_sockaddr_size(addr));
61 [ # # ]: 0 : if(res == 0) break;
62 : : #if defined(PLATFORM_WINDOWS)
63 : : if(res == SOCKET_ERROR) {
64 : : res = -1;
65 : : errnm = WSAGetLastError();
66 : : if(errnm == WSAEWOULDBLOCK) break;
67 : : if(errnm == WSAEINTR) continue;
68 : : }
69 : : #else
70 [ # # ]: 0 : if(errno == EINTR) continue;
71 [ # # ]: 0 : if(errno == EINPROGRESS) break;
72 : : #endif
73 : 0 : };
74 : :
75 : 0 : return res;
76 : : }
77 : :
78 : 0 : sockid_t gwsk_accept(sockid_t sockfd, struct sockaddr_storage * addr, socklen_t * asize) {
79 : 0 : sockid_t res = 0;
80 : :
81 : : #if defined(PLATFORM_WINDOWS)
82 : : int errnm = 0;
83 : : #endif
84 : :
85 : 0 : while(1) {
86 : 0 : errno = 0;
87 : 0 : res = accept(sockfd,(struct sockaddr *)addr,asize);
88 [ # # ]: 0 : if(res == 0) break;
89 : :
90 : : #if defined(PLATFORM_WINDOWS)
91 : : if(res == INVALID_SOCKET) {
92 : : res = -1;
93 : : errnm = WSAGetLastError();
94 : : if(errnm == WSAEINTR) continue;
95 : : }
96 : : #else
97 [ # # ]: 0 : if(errno == EINTR) continue;
98 : : #endif
99 : 0 : }
100 : :
101 : 0 : return res;
102 : : }
103 : :
104 : 0 : void gwsk_close(sockid_t sockfd) {
105 : : #if defined(PLATFORM_WINDOWS)
106 : : closesocket(sockfd);
107 : : #else
108 : 0 : close(sockfd);
109 : : #endif
110 : 0 : }
111 : :
112 : 0 : int gwsk_nonblock(sockid_t sockfd, int onoff) {
113 : : #if defined(PLATFORM_WINDOWS)
114 : : DWORD nonBlocking = 1;
115 : : return ioctlsocket(sockfd,FIONBIO,&nonBlocking);
116 : : #else
117 : 0 : return fcntl(sockfd,F_SETFL,O_NONBLOCK,&onoff);
118 : : #endif
119 : : }
120 : :
121 : 0 : int gwsk_reuseaddr(sockid_t sockfd, int onoff) {
122 : : #if defined(PLATFORM_WINDOWS)
123 : : return setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&onoff,sizeof(onoff));
124 : : #else
125 : 0 : return setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&onoff,sizeof(onoff));
126 : : #endif
127 : : }
128 : :
129 : 0 : void skctlinfo_free(skctlinfo * info, bool freeinfo) {
130 : 0 : if(info->list) freeaddrinfo(info->list);
131 : 0 : info->list = NULL;
132 [ # # ]: 0 : if(freeinfo) free(info);
133 : 0 : }
134 : :
135 : 0 : char * skctl_str_for_flag(int flag) {
136 : 0 : if(flag == SKCTL_GETADDRINFO) {
137 : 0 : return "SKCTL_GETADDRINFO";
138 [ # # ]: 0 : } else if(flag == SKCTL_SOCKET) {
139 : 0 : return "SKCTL_SOCKET";
140 [ # # ]: 0 : } else if(flag == SKCTL_CONNECT) {
141 : 0 : return "SKCTL_CONNECT";
142 [ # # ]: 0 : } else if(flag == SKCTL_BIND) {
143 : 0 : return "SKCTL_BIND";
144 [ # # ]: 0 : } else if(flag == SKCTL_LISTEN) {
145 : 0 : return "SOCKCNTL_LIST";
146 [ # # ]: 0 : } else if(flag == SKCTL_REUSE_ADDR) {
147 : 0 : return "SKCTL_REUSE_ADDR";
148 [ # # ]: 0 : } else if(flag == SKCTL_PRINTADDR) {
149 : 0 : return "SKCTL_PRINTADDR";
150 [ # # ]: 0 : } else if(flag == SKCTL_NOBLOCK) {
151 : 0 : return "SKCTL_NOBLOCK";
152 : : }
153 : 0 : return "Unknown flag";
154 : 0 : }
155 : :
156 : 0 : int skctl(skctlinfo * arg) {
157 : 0 : bool addr_existed = false;
158 : 0 : int res = 0;
159 : 0 : struct addrinfo * ap = NULL;
160 : 0 : struct addrinfo * info = NULL;
161 : :
162 : 0 : if(arg->flags == 0) {
163 : 0 : arg->serrno = 0;
164 : 0 : fprintf(stderr,"skctl error: arg->flags is 0.\n");
165 : 0 : return -1;
166 : : }
167 : :
168 [ # # ]: 0 : if(arg->backlog <= 0) arg->backlog = 25;
169 : :
170 [ # # ]: 0 : if(arg->used) {
171 : 0 : ap = arg->used;
172 : 0 : addr_existed = true;
173 : 0 : }
174 : :
175 [ # # ][ # # ]: 0 : if(!addr_existed && (arg->flags & SKCTL_GETADDRINFO)) {
176 : 0 : while(1) {
177 : 0 : arg->serrnoflag = 0;
178 : 0 : arg->serrno = 0;
179 : 0 : res = getaddrinfo(arg->node,arg->service,&(arg->hints),&info);
180 [ # # ]: 0 : if(res == 0) break;
181 : :
182 : : #if defined(PLATFORM_WINDOWS)
183 : : if(res == WSATRY_AGAIN) continue;
184 : : #else
185 [ # # ]: 0 : if(res == EAI_AGAIN) continue;
186 [ # # ][ # # ]: 0 : if(res == EAI_SYSTEM && errno == EINTR) continue;
187 : : #endif
188 : :
189 : 0 : fprintf(stderr,"skctl: getaddrinfo error: %s\n",gai_strerror(res));
190 : 0 : arg->serrno = res;
191 : 0 : arg->serrnoflag = SKCTL_GETADDRINFO;
192 : 0 : return -1;
193 : : }
194 : 0 : arg->list = info;
195 : 0 : }
196 : :
197 [ # # ]: 0 : if(!arg->list) {
198 : 0 : fprintf(stderr,"skctl error: no addrinfo list.");
199 : 0 : return -1;
200 : : }
201 : :
202 [ # # ]: 0 : if(!ap) ap = info;
203 : :
204 : : #if !defined(PLATFORM_WINDOWS)
205 : : #define LOOP_ENTRY_CLOSE(flag)\
206 : : if(res < 0) {\
207 : : gwsk_close(arg->sockfd);\
208 : : arg->sockfd = -1;\
209 : : arg->serrno = errno;\
210 : : arg->serrnoflag = flag;\
211 : : goto nextap;\
212 : : }\
213 : :
214 : : #endif
215 : :
216 : : #if defined(PLATFORM_WINDOWS)
217 : : #define LOOP_ENTRY_CLOSE_WINDOWS(flag)\
218 : : if(res == SOCKET_ERROR) {\
219 : : gwsk_close(arg->sockfd);\
220 : : arg->sockfd = 0;\
221 : : arg->serrno = WSAGetLastError();\
222 : : arg->serrnoflag = flag;\
223 : : res = -1;\
224 : : goto nextap;\
225 : : }\
226 : :
227 : : #endif
228 : :
229 [ # # ]: 0 : while(ap != NULL) {
230 : : //res = 0;
231 : 0 : arg->serrnoflag = 0;
232 : 0 : arg->serrno = 0;
233 : 0 : arg->used = NULL;
234 : :
235 [ # # ]: 0 : if(arg->flags & SKCTL_PRINTADDR) {
236 : 0 : gwsk_addrinfo_print(ap);
237 : 0 : }
238 : :
239 [ # # ]: 0 : if(arg->flags & SKCTL_SOCKET) {
240 : : #if defined(PLATFORM_WINDOWS)
241 : : if(arg->flags & SKCTL_NOBLOCK) {
242 : : //socket() by default on windows creates non-blocking sockets.
243 : : arg->sockfd = socket(ap->ai_family,ap->ai_socktype,ap->ai_protocol);
244 : : } else {
245 : : //have to use WSASocket() to get a blocking socket.
246 : : arg->sockfd = WSASocket(ap->ai_family,ap->ai_socktype,ap->ai_protocol,NULL,0,0);
247 : : }
248 : : #else
249 : 0 : arg->sockfd = socket(ap->ai_family,ap->ai_socktype,ap->ai_protocol);
250 : : #endif
251 : :
252 : : #if defined(PLATFORM_WINDOWS)
253 : : if(arg->sockfd == INVALID_SOCKET) {
254 : : res = -1;
255 : : arg->serrno = WSAGetLastError();
256 : : arg->serrnoflag = SKCTL_SOCKET;
257 : : goto nextap;
258 : : }
259 : : #else
260 [ # # ]: 0 : if(arg->sockfd < 0) {
261 : 0 : res = -1;
262 : 0 : arg->serrno = errno;
263 : 0 : arg->serrnoflag = SKCTL_SOCKET;
264 : 0 : goto nextap;
265 : : }
266 : : #endif
267 : 0 : }
268 : :
269 [ # # ]: 0 : if(arg->flags & SKCTL_NOBLOCK) {
270 : : #if !defined(PLATFORM_WINDOWS)
271 : 0 : res = gwsk_nonblock(arg->sockfd,1);
272 : : #if !defined(PLATFORM_WINDOWS)
273 [ # # ]: 0 : LOOP_ENTRY_CLOSE(SKCTL_NOBLOCK);
274 : : #endif
275 : : #endif
276 : 0 : }
277 : :
278 [ # # ]: 0 : if(arg->flags & SKCTL_REUSE_ADDR) {
279 : 0 : res = gwsk_reuseaddr(arg->sockfd,1);
280 : : #if defined(PLATFORM_WINDOWS)
281 : : LOOP_ENTRY_CLOSE_WINDOWS(SKCTL_REUSE_ADDR)
282 : : #else
283 [ # # ]: 0 : LOOP_ENTRY_CLOSE(SKCTL_REUSE_ADDR);
284 : : #endif
285 : 0 : }
286 : :
287 [ # # ]: 0 : if(arg->flags & SKCTL_BIND) {
288 : 0 : res = bind(arg->sockfd,ap->ai_addr,gwsk_sockaddr_size((struct sockaddr_storage *)ap->ai_addr));
289 : : #if defined(PLATFORM_WINDOWS)
290 : : LOOP_ENTRY_CLOSE_WINDOWS(SKCTL_BIND);
291 : : #else
292 [ # # ]: 0 : LOOP_ENTRY_CLOSE(SKCTL_BIND);
293 : : #endif
294 : 0 : }
295 : :
296 [ # # ]: 0 : if(arg->flags & SKCTL_LISTEN) {
297 : 0 : res = listen(arg->sockfd,arg->backlog);
298 : : #if defined(PLATFORM_WINDOWS)
299 : : LOOP_ENTRY_CLOSE_WINDOWS(SKCTL_LISTEN);
300 : : #else
301 [ # # ]: 0 : LOOP_ENTRY_CLOSE(SKCTL_LISTEN);
302 : : #endif
303 : 0 : }
304 : :
305 [ # # ]: 0 : if(arg->flags & SKCTL_CONNECT) {
306 : 0 : res = gwsk_connect(arg->sockfd,(struct sockaddr_storage *)ap->ai_addr);
307 : : #if defined(PLATFORM_WINDOWS)
308 : : if(res == SOCKET_ERROR) {
309 : : int errnm = WSAGetLastError();
310 : : if(errnm != WSAEWOULDBLOCK) {
311 : : LOOP_ENTRY_CLOSE_WINDOWS(SKCTL_CONNECT);
312 : : }
313 : : }
314 : : #else
315 [ # # ][ # # ]: 0 : if(res < 0 && errno != EINPROGRESS) {
316 [ # # ]: 0 : LOOP_ENTRY_CLOSE(SKCTL_CONNECT);
317 : 0 : }
318 : : #endif
319 : 0 : }
320 : :
321 : 0 : res = 0;
322 : 0 : arg->used = ap;
323 : 0 : break;
324 : :
325 : : nextap:
326 [ # # ]: 0 : if(addr_existed) {
327 : 0 : arg->used = ap;
328 : 0 : break;
329 : : }
330 : 0 : ap = ap->ai_next;
331 : 0 : }
332 : :
333 [ # # ]: 0 : if(res < 0) {
334 : : #if defined(PLATFORM_WINDOWS)
335 : : gwprintsyserr("skctl error",arg->serrno);
336 : : #else
337 : 0 : gwprintsyserr("skctl error",arg->serrno);
338 : : #endif
339 : 0 : fprintf(stderr,"skctlinfo flag that caused the error: %s\n",skctl_str_for_flag(arg->serrnoflag));
340 : 0 : }
341 : :
342 : 0 : return res;
343 : 0 : }
344 : :
345 : 0 : int skctl_tcp_server(skctlinfo * info, char * node, char * service, int ipfamily, bool noblock) {
346 : 0 : info->node = node;
347 : 0 : info->service = service;
348 : 0 : info->hints.ai_family = ipfamily;
349 : 0 : info->hints.ai_protocol = IPPROTO_TCP;
350 : 0 : info->hints.ai_flags = AI_PASSIVE;
351 : 0 : info->hints.ai_socktype = SOCK_STREAM;
352 : 0 : info->flags = SKCTL_TCP_SERVER;
353 : 0 : if(noblock) info->flags |= SKCTL_NOBLOCK;
354 : 0 : return skctl(info);
355 : : }
356 : :
357 : 0 : int skctl_udp_server(skctlinfo * info, char * node, char * service, int ipfamily, bool noblock) {
358 : 0 : info->node = node;
359 : 0 : info->service = service;
360 : 0 : info->hints.ai_family = ipfamily;
361 : 0 : info->hints.ai_protocol = IPPROTO_UDP;
362 : 0 : info->hints.ai_flags = AI_PASSIVE;
363 : 0 : info->hints.ai_socktype = SOCK_DGRAM;
364 : 0 : info->flags = SKCTL_UDP_SERVER;
365 : 0 : if(noblock) info->flags |= SKCTL_NOBLOCK;
366 : 0 : return skctl(info);
367 : : }
368 : :
369 : 0 : int skctl_tcp_client(skctlinfo * info, char * node, char * service, int ipfamily, bool noblock) {
370 : 0 : info->node = node;
371 : 0 : info->service = service;
372 : 0 : info->hints.ai_family = ipfamily;
373 : 0 : info->hints.ai_protocol = IPPROTO_TCP;
374 : 0 : info->hints.ai_socktype = SOCK_STREAM;
375 : 0 : info->flags = SKCTL_TCP_CLIENT;
376 : 0 : if(noblock) info->flags |= SKCTL_NOBLOCK;
377 : 0 : return skctl(info);
378 : : }
379 : :
380 : 0 : int skctl_udp_client(skctlinfo * info, char * node, char * service, int ipfamily, bool noblock) {
381 : 0 : info->node = node;
382 : 0 : info->service = service;
383 : 0 : info->hints.ai_family = ipfamily;
384 : 0 : info->hints.ai_protocol = IPPROTO_UDP;
385 : 0 : info->hints.ai_socktype = SOCK_DGRAM;
386 : 0 : info->flags = SKCTL_UDP_CLIENT;
387 : 0 : if(noblock) info->flags |= SKCTL_NOBLOCK;
388 : 0 : return skctl(info);
389 : : }
390 : :
391 : 0 : int skctl_udp_connected_client(skctlinfo * info, char * node, char * service, int ipfamily, bool noblock) {
392 : 0 : info->node = node;
393 : 0 : info->service = service;
394 : 0 : info->hints.ai_family = ipfamily;
395 : 0 : info->hints.ai_protocol = IPPROTO_UDP;
396 : 0 : info->hints.ai_socktype = SOCK_DGRAM;
397 : 0 : info->flags = SKCTL_UDP_CONNECTED_CLIENT;
398 : 0 : if(noblock) info->flags |= SKCTL_NOBLOCK;
399 : 0 : return skctl(info);
400 : : }
401 : :
402 : : #ifdef __cplusplus
403 : : }
404 : : #endif
|