]>
Commit | Line | Data |
---|---|---|
a324a7bc GL |
1 | /* ------------------------------------------------------------------------- |
2 | * Project: GSocket (Generic Socket) for WX | |
3 | * Name: gsocket.c | |
4 | * Purpose: GSocket main Unix file | |
5 | * CVSID: $Id$ | |
a324a7bc GL |
6 | * ------------------------------------------------------------------------- |
7 | */ | |
8 | ||
9 | #include <assert.h> | |
10 | #include <sys/ioctl.h> | |
efee48a0 | 11 | #include <sys/types.h> |
a324a7bc GL |
12 | #ifdef vms |
13 | #include <socket.h> | |
14 | #else | |
15 | #include <sys/socket.h> | |
16 | #endif | |
17 | #include <sys/un.h> | |
a324a7bc GL |
18 | #include <sys/time.h> |
19 | #include <netinet/in.h> | |
20 | #include <arpa/inet.h> | |
21 | #include <netdb.h> | |
22 | ||
23 | #include <string.h> | |
24 | #include <unistd.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | ||
28 | #ifdef sun | |
5a96d2f4 | 29 | #include <sys/filio.h> |
a324a7bc GL |
30 | #endif |
31 | ||
32 | #ifdef sgi | |
33 | #include <bstring.h> | |
34 | #endif | |
35 | ||
36 | #include <signal.h> | |
5a96d2f4 GL |
37 | #include <features.h> |
38 | ||
efee48a0 | 39 | #include <wx/setup.h> |
a324a7bc GL |
40 | #include <wx/gsocket.h> |
41 | #include "gsockunx.h" | |
42 | ||
efee48a0 | 43 | #ifndef SOCKLEN_T |
5a96d2f4 GL |
44 | |
45 | #ifdef __GLIBC__ | |
46 | # if __GLIBC__ == 2 | |
47 | # define SOCKLEN_T socklen_t | |
48 | # endif | |
49 | #else | |
50 | # define SOCKLEN_T int | |
51 | #endif | |
52 | ||
efee48a0 KB |
53 | #endif |
54 | ||
a324a7bc GL |
55 | /* Constructors / Destructors */ |
56 | ||
57 | GSocket *GSocket_new() | |
58 | { | |
59 | int i; | |
60 | GSocket *socket; | |
61 | ||
62 | socket = (GSocket *)malloc(sizeof(GSocket)); | |
63 | ||
64 | socket->m_fd = -1; | |
65 | for (i=0;i<GSOCK_MAX_EVENT;i++) { | |
66 | socket->m_fbacks[i] = NULL; | |
67 | socket->m_iocalls[i] = FALSE; | |
68 | } | |
69 | socket->m_local = NULL; | |
70 | socket->m_peer = NULL; | |
71 | socket->m_error = GSOCK_NOERROR; | |
72 | socket->m_server = FALSE; | |
73 | socket->m_stream = TRUE; | |
74 | socket->m_gui_dependent = NULL; | |
75 | socket->m_blocking = FALSE; | |
76 | ||
77 | _GSocket_GUI_Init(socket); | |
78 | ||
79 | return socket; | |
80 | } | |
81 | ||
82 | void GSocket_destroy(GSocket *socket) | |
83 | { | |
84 | assert(socket != NULL); | |
85 | ||
a324a7bc GL |
86 | if (socket->m_fd != -1) |
87 | GSocket_Shutdown(socket); | |
88 | ||
dbd300df GL |
89 | _GSocket_GUI_Destroy(socket); |
90 | ||
a324a7bc GL |
91 | if (socket->m_local) |
92 | GAddress_destroy(socket->m_local); | |
93 | ||
94 | if (socket->m_peer) | |
95 | GAddress_destroy(socket->m_peer); | |
96 | ||
97 | free(socket); | |
98 | } | |
99 | ||
100 | void GSocket_Shutdown(GSocket *socket) | |
101 | { | |
102 | int evt; | |
103 | ||
104 | assert(socket != NULL); | |
105 | ||
106 | if (socket->m_fd != -1) { | |
107 | shutdown(socket->m_fd, 2); | |
108 | close(socket->m_fd); | |
109 | socket->m_fd = -1; | |
110 | } | |
111 | ||
112 | for (evt=0;evt<GSOCK_MAX_EVENT;evt++) | |
113 | _GSocket_Uninstall_Fallback(socket, evt); | |
114 | } | |
115 | ||
116 | /* Address handling */ | |
117 | ||
118 | GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address) | |
119 | { | |
5a96d2f4 GL |
120 | assert(socket != NULL); |
121 | ||
122 | if ((socket->m_fd != -1 && !socket->m_server)) | |
a324a7bc GL |
123 | return GSOCK_INVSOCK; |
124 | ||
125 | if (address == NULL || address->m_family == GSOCK_NOFAMILY) | |
126 | return GSOCK_INVADDR; | |
127 | ||
128 | if (socket->m_local) | |
129 | GAddress_destroy(socket->m_local); | |
130 | ||
131 | socket->m_local = GAddress_copy(address); | |
132 | ||
133 | return GSOCK_NOERROR; | |
134 | } | |
135 | ||
136 | GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address) | |
137 | { | |
5a96d2f4 | 138 | assert(socket != NULL); |
a324a7bc GL |
139 | |
140 | if (address == NULL || address->m_family == GSOCK_NOFAMILY) { | |
141 | socket->m_error = GSOCK_INVADDR; | |
142 | return GSOCK_INVADDR; | |
143 | } | |
144 | ||
145 | if (socket->m_peer) | |
146 | GAddress_destroy(socket->m_peer); | |
147 | ||
148 | socket->m_peer = GAddress_copy(address); | |
149 | ||
150 | return GSOCK_NOERROR; | |
151 | } | |
152 | ||
153 | GAddress *GSocket_GetLocal(GSocket *socket) | |
154 | { | |
155 | GAddress *address; | |
156 | struct sockaddr addr; | |
efee48a0 | 157 | SOCKLEN_T size; |
a324a7bc GL |
158 | |
159 | assert(socket != NULL); | |
160 | ||
161 | if (socket->m_local) | |
162 | return GAddress_copy(socket->m_local); | |
163 | ||
164 | if (socket->m_fd == -1) { | |
165 | socket->m_error = GSOCK_INVSOCK; | |
166 | return NULL; | |
167 | } | |
168 | ||
169 | size = sizeof(addr); | |
170 | ||
171 | if (getsockname(socket->m_fd, &addr, &size) < 0) { | |
172 | socket->m_error = GSOCK_IOERR; | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | address = GAddress_new(); | |
177 | _GAddress_translate_from(address, &addr, size); | |
178 | ||
179 | return address; | |
180 | } | |
181 | ||
182 | GAddress *GSocket_GetPeer(GSocket *socket) | |
183 | { | |
184 | assert(socket != NULL); | |
185 | ||
186 | if (socket->m_peer) | |
187 | return GAddress_copy(socket->m_peer); | |
188 | ||
189 | return NULL; | |
190 | } | |
191 | ||
192 | /* Server specific parts */ | |
193 | ||
194 | /* | |
195 | GSocket_SetServer() setup the socket as a server. It uses the "Local" field | |
196 | of GSocket. "Local" must be set by GSocket_SetLocal() before | |
197 | GSocket_SetServer() is called. GSOCK_INVSOCK if socket has been initialized. | |
5a96d2f4 GL |
198 | In case, you haven't yet defined the local address, it returns GSOCK_INVADDR. |
199 | In the other cases it returns GSOCK_IOERR. | |
a324a7bc GL |
200 | */ |
201 | GSocketError GSocket_SetServer(GSocket *sck) | |
202 | { | |
203 | int type; | |
204 | ||
205 | assert(sck != NULL); | |
206 | ||
207 | if (sck->m_fd != -1) { | |
208 | sck->m_error = GSOCK_INVSOCK; | |
209 | return GSOCK_INVSOCK; | |
210 | } | |
211 | ||
212 | if (!sck->m_local) { | |
213 | sck->m_error = GSOCK_INVADDR; | |
214 | return GSOCK_INVADDR; | |
215 | } | |
216 | ||
217 | if (sck->m_stream) | |
218 | type = SOCK_STREAM; | |
219 | else | |
220 | type = SOCK_DGRAM; | |
221 | ||
222 | sck->m_fd = socket(sck->m_local->m_realfamily, type, 0); | |
223 | ||
224 | if (sck->m_fd == -1) { | |
225 | sck->m_error = GSOCK_IOERR; | |
226 | return GSOCK_IOERR; | |
227 | } | |
228 | ||
229 | if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) { | |
230 | close(sck->m_fd); | |
231 | sck->m_fd = -1; | |
232 | sck->m_error = GSOCK_IOERR; | |
233 | return GSOCK_IOERR; | |
234 | } | |
235 | ||
236 | if (listen(sck->m_fd, 5) < 0) { | |
237 | close(sck->m_fd); | |
238 | sck->m_fd = -1; | |
239 | sck->m_error = GSOCK_IOERR; | |
240 | return GSOCK_IOERR; | |
241 | } | |
242 | ||
243 | sck->m_server = TRUE; | |
244 | ||
245 | return GSOCK_NOERROR; | |
246 | ||
247 | } | |
248 | ||
249 | /* | |
250 | GSocket_WaitConnection() waits for an incoming client connection. | |
251 | */ | |
252 | GSocket *GSocket_WaitConnection(GSocket *socket) | |
253 | { | |
254 | GSocket *connection; | |
255 | ||
256 | assert(socket != NULL); | |
257 | ||
258 | if (socket->m_fd == -1 || !socket->m_server) { | |
259 | socket->m_error = GSOCK_INVSOCK; | |
260 | return NULL; | |
261 | } | |
262 | ||
263 | _GSocket_Enable(socket, GSOCK_CONNECTION); | |
264 | ||
265 | connection = GSocket_new(); | |
266 | ||
267 | connection->m_fd = accept(socket->m_fd, NULL, NULL); | |
268 | if (connection->m_fd == -1) { | |
269 | GSocket_destroy(connection); | |
270 | socket->m_error = GSOCK_IOERR; | |
271 | return NULL; | |
272 | } | |
273 | ||
274 | connection->m_stream = TRUE; | |
275 | connection->m_server = FALSE; | |
276 | connection->m_oriented = TRUE; | |
277 | ||
278 | return connection; | |
279 | } | |
280 | ||
281 | /* Non oriented connections */ | |
282 | ||
283 | GSocketError GSocket_SetNonOriented(GSocket *sck) | |
284 | { | |
285 | assert(sck != NULL); | |
286 | ||
287 | if (sck->m_fd != -1) { | |
288 | sck->m_error = GSOCK_INVSOCK; | |
289 | return GSOCK_INVSOCK; | |
290 | } | |
291 | ||
292 | if (!sck->m_local) { | |
293 | sck->m_error = GSOCK_INVADDR; | |
294 | return GSOCK_INVADDR; | |
295 | } | |
296 | ||
297 | sck->m_stream = FALSE; | |
298 | sck->m_server = FALSE; | |
299 | sck->m_oriented = FALSE; | |
300 | ||
301 | sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0); | |
302 | ||
303 | if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) { | |
304 | close(sck->m_fd); | |
305 | sck->m_fd = -1; | |
306 | sck->m_error = GSOCK_IOERR; | |
307 | return GSOCK_IOERR; | |
308 | } | |
309 | ||
310 | return GSOCK_NOERROR; | |
311 | } | |
312 | ||
313 | /* Client specific parts */ | |
314 | ||
315 | /* | |
316 | GSocket_Connect() establishes a client connection to a server using the "Peer" | |
317 | field of GSocket. "Peer" must be set by GSocket_SetPeer() before | |
318 | GSocket_Connect() is called. In the other case, it returns GSOCK_INVADDR. | |
319 | */ | |
320 | GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) | |
321 | { | |
322 | int type; | |
323 | ||
324 | assert(sck != NULL); | |
325 | ||
326 | if (sck->m_fd != -1) { | |
327 | sck->m_error = GSOCK_INVSOCK; | |
328 | return GSOCK_INVSOCK; | |
329 | } | |
330 | ||
331 | if (!sck->m_peer) { | |
332 | sck->m_error = GSOCK_INVADDR; | |
333 | return GSOCK_INVADDR; | |
334 | } | |
335 | ||
336 | sck->m_stream = (stream == GSOCK_STREAMED); | |
337 | sck->m_oriented = TRUE; | |
338 | ||
339 | if (sck->m_stream) | |
340 | type = SOCK_STREAM; | |
341 | else | |
342 | type = SOCK_DGRAM; | |
343 | ||
344 | sck->m_fd = socket(sck->m_peer->m_realfamily, type, 0); | |
345 | ||
346 | if (sck->m_fd == -1) { | |
347 | sck->m_error = GSOCK_IOERR; | |
348 | return GSOCK_IOERR; | |
349 | } | |
350 | ||
351 | if (connect(sck->m_fd, sck->m_peer->m_addr, | |
352 | sck->m_peer->m_len) != 0) { | |
353 | close(sck->m_fd); | |
354 | sck->m_fd = -1; | |
355 | sck->m_error = GSOCK_IOERR; | |
356 | return GSOCK_IOERR; | |
357 | } | |
358 | ||
359 | sck->m_server = FALSE; | |
360 | ||
361 | return GSOCK_NOERROR; | |
362 | } | |
363 | ||
364 | /* Generic IO */ | |
365 | ||
366 | /* Like recv(), send(), ... */ | |
367 | int GSocket_Read(GSocket *socket, char *buffer, int size) | |
368 | { | |
369 | assert(socket != NULL); | |
370 | ||
371 | if (socket->m_fd == -1 || socket->m_server) { | |
372 | socket->m_error = GSOCK_INVSOCK; | |
373 | return -1; | |
374 | } | |
375 | ||
376 | _GSocket_Enable(socket, GSOCK_INPUT); | |
377 | ||
378 | if (socket->m_oriented) | |
379 | return _GSocket_Recv_Stream(socket, buffer, size); | |
380 | else | |
381 | return _GSocket_Recv_Dgram(socket, buffer, size); | |
382 | } | |
383 | ||
384 | int GSocket_Write(GSocket *socket, const char *buffer, | |
385 | int size) | |
386 | { | |
387 | assert(socket != NULL); | |
388 | ||
389 | if (socket->m_fd == -1 || socket->m_server) { | |
390 | socket->m_error = GSOCK_INVSOCK; | |
391 | return -1; | |
392 | } | |
393 | ||
394 | _GSocket_Enable(socket, GSOCK_OUTPUT); | |
395 | ||
396 | if (socket->m_oriented) | |
397 | return _GSocket_Send_Stream(socket, buffer, size); | |
398 | else | |
399 | return _GSocket_Send_Dgram(socket, buffer, size); | |
400 | } | |
401 | ||
402 | bool GSocket_DataAvailable(GSocket *socket) | |
403 | { | |
404 | fd_set read_set; | |
405 | struct timeval tv; | |
406 | ||
407 | assert(socket != NULL); | |
408 | ||
409 | if (socket->m_fd == -1 || socket->m_server) { | |
410 | socket->m_error = GSOCK_INVSOCK; | |
411 | return FALSE; | |
412 | } | |
413 | ||
414 | FD_ZERO(&read_set); | |
415 | FD_SET(socket->m_fd, &read_set); | |
416 | ||
417 | tv.tv_sec = 0; | |
418 | tv.tv_usec = 0; | |
419 | ||
420 | select(socket->m_fd+1, &read_set, NULL, NULL, &tv); | |
421 | ||
422 | return FD_ISSET(socket->m_fd, &read_set); | |
423 | } | |
424 | ||
425 | /* Flags */ | |
426 | ||
427 | /* | |
428 | GSocket_SetBlocking() puts the socket in non-blocking mode. This is useful | |
429 | if we don't want to wait. | |
430 | */ | |
431 | void GSocket_SetBlocking(GSocket *socket, bool block) | |
432 | { | |
433 | assert(socket != NULL); | |
434 | ||
435 | socket->m_blocking = block; | |
436 | ||
437 | if (socket->m_fd != -1) | |
438 | ioctl(socket->m_fd, FIONBIO, &block); | |
439 | } | |
440 | ||
441 | /* | |
442 | GSocket_GetError() returns the last error occured on the socket stream. | |
443 | */ | |
444 | ||
445 | GSocketError GSocket_GetError(GSocket *socket) | |
446 | { | |
447 | assert(socket != NULL); | |
448 | ||
449 | return socket->m_error; | |
450 | } | |
451 | ||
452 | /* Callbacks */ | |
453 | ||
454 | /* | |
455 | Only one fallback is possible for each event (INPUT, OUTPUT, CONNECTION) | |
456 | INPUT: The function is called when there is at least a byte in the | |
457 | input buffer | |
458 | OUTPUT: The function is called when the system is sure the next write call | |
459 | will not block | |
460 | CONNECTION: Two cases is possible: | |
461 | Client socket -> the connection is established | |
462 | Server socket -> a client request a connection | |
463 | LOST: the connection is lost | |
464 | ||
465 | SetFallback accepts a combination of these flags so a same callback can | |
466 | receive different events. | |
467 | ||
468 | An event is generated only once and its state is reseted when the relative | |
469 | IO call is requested. | |
470 | For example: INPUT -> GSocket_Read() | |
471 | CONNECTION -> GSocket_Accept() | |
472 | */ | |
473 | void GSocket_SetFallback(GSocket *socket, GSocketEventFlags event, | |
474 | GSocketFallback fallback, char *cdata) | |
475 | { | |
476 | int count; | |
477 | ||
478 | assert (socket != NULL); | |
479 | ||
480 | for (count=0;count<GSOCK_MAX_EVENT;count++) { | |
481 | if ((event & (1 << count)) != 0) { | |
482 | socket->m_fbacks[count] = fallback; | |
483 | socket->m_data[count] = cdata; | |
484 | ||
485 | _GSocket_Install_Fallback(socket, count); | |
486 | _GSocket_Enable(socket, count); | |
487 | } | |
488 | } | |
489 | } | |
490 | ||
491 | /* | |
492 | UnsetFallback will disables all fallbacks specified by "event". | |
493 | NOTE: event may be a combination of flags | |
494 | */ | |
495 | void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event) | |
496 | { | |
497 | int count = 0; | |
498 | ||
499 | assert(socket != NULL); | |
500 | ||
501 | for (count=0;count<GSOCK_MAX_EVENT;count++) { | |
502 | if ((event & (1 << count)) != 0) { | |
503 | _GSocket_Disable(socket, count); | |
504 | socket->m_fbacks[count] = NULL; | |
505 | _GSocket_Uninstall_Fallback(socket, count); | |
506 | } | |
507 | } | |
508 | } | |
509 | ||
510 | #define CALL_FALLBACK(socket, event) \ | |
511 | if (socket->m_iocalls[event] && \ | |
512 | socket->m_fbacks[event]) {\ | |
513 | _GSocket_Disable(socket, event); \ | |
514 | socket->m_fbacks[event](socket, event, \ | |
515 | socket->m_data[event]); \ | |
516 | } | |
517 | ||
518 | #define MASK_SIGNAL() \ | |
519 | { \ | |
520 | void (*old_handler)(int); \ | |
521 | \ | |
522 | old_handler = signal(SIGPIPE, SIG_IGN); | |
523 | ||
524 | #define UNMASK_SIGNAL() \ | |
525 | signal(SIGPIPE, old_handler); \ | |
526 | } | |
527 | ||
528 | void _GSocket_Enable(GSocket *socket, GSocketEvent event) | |
529 | { | |
530 | socket->m_iocalls[event] = TRUE; | |
531 | if (socket->m_fbacks[event]) | |
532 | _GSocket_Install_Fallback(socket, event); | |
533 | } | |
534 | ||
535 | void _GSocket_Disable(GSocket *socket, GSocketEvent event) | |
536 | { | |
537 | socket->m_iocalls[event] = FALSE; | |
538 | if (socket->m_fbacks[event]) | |
539 | _GSocket_Uninstall_Fallback(socket, event); | |
540 | } | |
541 | ||
542 | int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) | |
543 | { | |
544 | int ret; | |
545 | ||
546 | MASK_SIGNAL(); | |
547 | ret = recv(socket->m_fd, buffer, size, 0); | |
548 | UNMASK_SIGNAL(); | |
549 | if (ret == -1) { | |
550 | socket->m_error = GSOCK_IOERR; | |
551 | return -1; | |
552 | } | |
553 | return ret; | |
554 | } | |
555 | ||
556 | int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) | |
557 | { | |
558 | struct sockaddr from; | |
559 | int fromlen, ret; | |
560 | ||
561 | fromlen = sizeof(from); | |
562 | ||
563 | MASK_SIGNAL(); | |
564 | ret = recvfrom(socket->m_fd, buffer, size, 0, &from, &fromlen); | |
565 | UNMASK_SIGNAL(); | |
566 | if (ret == -1) { | |
567 | socket->m_error = GSOCK_IOERR; | |
568 | return -1; | |
569 | } | |
570 | ||
571 | if (!socket->m_peer) | |
572 | socket->m_peer = GAddress_new(); | |
573 | _GAddress_translate_from(socket->m_peer, &from, fromlen); | |
574 | ||
575 | return ret; | |
576 | } | |
577 | ||
578 | int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size) | |
579 | { | |
580 | int ret; | |
581 | ||
582 | MASK_SIGNAL(); | |
583 | ret = send(socket->m_fd, buffer, size, 0); | |
584 | UNMASK_SIGNAL(); | |
585 | if (ret == -1) { | |
586 | socket->m_error = GSOCK_IOERR; | |
587 | return -1; | |
588 | } | |
589 | return ret; | |
590 | } | |
591 | ||
592 | int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) | |
593 | { | |
594 | struct sockaddr *addr; | |
595 | int len, ret; | |
596 | ||
597 | if (!socket->m_peer) { | |
598 | socket->m_error = GSOCK_INVADDR; | |
599 | return -1; | |
600 | } | |
601 | ||
602 | _GAddress_translate_to(socket->m_peer, &addr, &len); | |
603 | ||
604 | MASK_SIGNAL(); | |
605 | ret = sendto(socket->m_fd, buffer, size, 0, addr, len); | |
606 | UNMASK_SIGNAL(); | |
607 | if (ret == -1) { | |
608 | socket->m_error = GSOCK_IOERR; | |
609 | return -1; | |
610 | } | |
611 | ||
612 | free(addr); | |
613 | ||
614 | return ret; | |
615 | } | |
616 | ||
617 | void _GSocket_Detected_Read(GSocket *socket) | |
618 | { | |
619 | char c; | |
620 | int ret; | |
621 | ||
622 | if (socket->m_stream) { | |
623 | ret = recv(socket->m_fd, &c, 1, MSG_PEEK); | |
624 | ||
625 | if (ret < 0 && socket->m_server) { | |
626 | CALL_FALLBACK(socket, GSOCK_CONNECTION); | |
627 | return; | |
628 | } | |
629 | ||
630 | if (ret > 0) { | |
631 | CALL_FALLBACK(socket, GSOCK_INPUT); | |
632 | } else { | |
633 | CALL_FALLBACK(socket, GSOCK_LOST); | |
634 | } | |
635 | } | |
636 | } | |
637 | ||
638 | void _GSocket_Detected_Write(GSocket *socket) | |
639 | { | |
640 | CALL_FALLBACK(socket, GSOCK_OUTPUT); | |
641 | } | |
642 | ||
643 | #undef CALL_FALLBACK | |
644 | #undef MASK_SIGNAL | |
645 | #undef UNMASK_SIGNAL | |
646 | ||
647 | /* | |
648 | * ------------------------------------------------------------------------- | |
649 | * GAddress | |
650 | * ------------------------------------------------------------------------- | |
651 | */ | |
652 | ||
653 | #define CHECK_ADDRESS(address, family, retval) \ | |
654 | { \ | |
655 | if (address->m_family == GSOCK_NOFAMILY) \ | |
656 | _GAddress_Init_##family(address); \ | |
657 | if (address->m_family != GSOCK_##family) {\ | |
658 | address->m_error = GSOCK_INVADDR; \ | |
659 | return retval; \ | |
660 | } \ | |
661 | } | |
662 | ||
663 | GAddress *GAddress_new() | |
664 | { | |
665 | GAddress *address; | |
666 | ||
667 | address = (GAddress *)malloc(sizeof(GAddress)); | |
668 | ||
669 | address->m_family = GSOCK_NOFAMILY; | |
670 | address->m_addr = NULL; | |
671 | address->m_len = 0; | |
672 | ||
673 | return address; | |
674 | } | |
675 | ||
676 | GAddress *GAddress_copy(GAddress *address) | |
677 | { | |
678 | GAddress *addr2; | |
679 | ||
680 | assert(address != NULL); | |
681 | ||
682 | addr2 = (GAddress *)malloc(sizeof(GAddress)); | |
683 | memcpy(addr2, address, sizeof(GAddress)); | |
684 | ||
685 | if (address->m_addr) { | |
686 | addr2->m_addr = (struct sockaddr *)malloc(addr2->m_len); | |
687 | memcpy(addr2->m_addr, address->m_addr, addr2->m_len); | |
688 | } | |
689 | ||
690 | return addr2; | |
691 | } | |
692 | ||
693 | void GAddress_destroy(GAddress *address) | |
694 | { | |
695 | assert(address != NULL); | |
696 | ||
697 | free(address); | |
698 | } | |
699 | ||
700 | void GAddress_SetFamily(GAddress *address, GAddressType type) | |
701 | { | |
702 | assert(address != NULL); | |
703 | ||
704 | address->m_family = type; | |
705 | } | |
706 | ||
707 | GAddressType GAddress_GetFamily(GAddress *address) | |
708 | { | |
709 | assert(address != NULL); | |
710 | ||
711 | return address->m_family; | |
712 | } | |
713 | ||
714 | void _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len){ | |
715 | address->m_realfamily = addr->sa_family; | |
716 | switch (addr->sa_family) { | |
717 | case AF_INET: | |
718 | address->m_family = GSOCK_INET; | |
719 | break; | |
720 | case AF_UNIX: | |
721 | address->m_family = GSOCK_UNIX; | |
722 | break; | |
efee48a0 | 723 | #ifdef AF_INET6 |
a324a7bc GL |
724 | case AF_INET6: |
725 | address->m_family = GSOCK_INET6; | |
726 | break; | |
efee48a0 | 727 | #endif |
a324a7bc | 728 | default: |
efee48a0 | 729 | |
a324a7bc GL |
730 | /* TODO error */ |
731 | } | |
732 | ||
733 | if (address->m_addr) | |
734 | free(address->m_addr); | |
735 | ||
736 | address->m_len = len; | |
737 | address->m_addr = (struct sockaddr *)malloc(len); | |
738 | memcpy(address->m_addr, addr, len); | |
739 | } | |
740 | ||
741 | void _GAddress_translate_to(GAddress *address, | |
742 | struct sockaddr **addr, int *len) | |
743 | { | |
744 | if (!address->m_addr) { | |
745 | /* TODO error */ | |
746 | return; | |
747 | } | |
748 | ||
749 | *len = address->m_len; | |
750 | *addr = (struct sockaddr *)malloc(address->m_len); | |
751 | memcpy(*addr, address->m_addr, address->m_len); | |
752 | } | |
753 | ||
754 | /* | |
755 | * ------------------------------------------------------------------------- | |
756 | * Internet address family | |
757 | * ------------------------------------------------------------------------- | |
758 | */ | |
759 | ||
760 | void _GAddress_Init_INET(GAddress *address) | |
761 | { | |
762 | address->m_len = sizeof(struct sockaddr_in); | |
763 | address->m_addr = (struct sockaddr *)malloc(address->m_len); | |
764 | address->m_family = GSOCK_INET; | |
765 | address->m_realfamily = PF_INET; | |
766 | ((struct sockaddr_in *)address->m_addr)->sin_family = AF_INET; | |
767 | ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr = INADDR_ANY; | |
768 | } | |
769 | ||
770 | GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) | |
771 | { | |
772 | struct hostent *he; | |
773 | struct in_addr *addr; | |
774 | ||
775 | assert(address != NULL); | |
776 | ||
777 | CHECK_ADDRESS(address, INET, GSOCK_INVADDR); | |
778 | ||
779 | addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr); | |
780 | ||
781 | /* only name for the moment */ | |
782 | if (inet_aton(hostname, addr) == 0) { | |
783 | struct in_addr *array_addr; | |
784 | ||
785 | if ((he = gethostbyname(hostname)) == NULL) { | |
786 | address->m_error = GSOCK_NOHOST; | |
787 | return GSOCK_NOHOST; | |
788 | } | |
789 | array_addr = (struct in_addr *) *(he->h_addr_list); | |
790 | addr->s_addr = array_addr[0].s_addr; | |
791 | } | |
792 | return GSOCK_NOERROR; | |
793 | } | |
794 | ||
795 | GSocketError GAddress_INET_SetHostAddress(GAddress *address, | |
796 | unsigned long hostaddr) | |
797 | { | |
798 | struct in_addr *addr; | |
799 | ||
800 | assert(address != NULL); | |
801 | ||
802 | CHECK_ADDRESS(address, INET, GSOCK_INVADDR); | |
803 | ||
804 | addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr); | |
805 | addr->s_addr = hostaddr; | |
806 | ||
807 | return GSOCK_NOERROR; | |
808 | } | |
809 | ||
5a96d2f4 GL |
810 | GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, |
811 | const char *protocol) | |
a324a7bc GL |
812 | { |
813 | struct servent *se; | |
814 | struct sockaddr_in *addr; | |
815 | ||
816 | assert(address != NULL); | |
817 | CHECK_ADDRESS(address, INET, GSOCK_INVADDR); | |
818 | ||
819 | if (!port) { | |
820 | address->m_error = GSOCK_INVPORT; | |
821 | return GSOCK_INVOP; | |
822 | } | |
823 | ||
824 | /* TODO: TCP or UDP */ | |
5a96d2f4 | 825 | se = getservbyname(port, protocol); |
a324a7bc GL |
826 | if (!se) { |
827 | if (isdigit(port[0])) { | |
828 | int port_int; | |
829 | ||
830 | port_int = atoi(port); | |
831 | addr = (struct sockaddr_in *)address->m_addr; | |
832 | addr->sin_port = htons(port_int); | |
833 | return GSOCK_NOERROR; | |
834 | } | |
835 | ||
836 | address->m_error = GSOCK_INVPORT; | |
837 | return GSOCK_INVPORT; | |
838 | } | |
839 | ||
840 | addr = (struct sockaddr_in *)address->m_addr; | |
841 | addr->sin_port = se->s_port; | |
842 | ||
843 | return GSOCK_NOERROR; | |
844 | } | |
845 | ||
846 | GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) | |
847 | { | |
848 | struct sockaddr_in *addr; | |
849 | ||
850 | assert(address != NULL); | |
851 | CHECK_ADDRESS(address, INET, GSOCK_INVADDR); | |
852 | ||
853 | addr = (struct sockaddr_in *)address->m_addr; | |
854 | addr->sin_port = htons(port); | |
855 | ||
856 | return GSOCK_NOERROR; | |
857 | } | |
858 | ||
859 | GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf) | |
860 | { | |
861 | struct hostent *he; | |
862 | char *addr_buf; | |
863 | struct sockaddr_in *addr; | |
864 | ||
865 | assert(address != NULL); | |
866 | CHECK_ADDRESS(address, INET, GSOCK_INVADDR); | |
867 | ||
868 | addr = (struct sockaddr_in *)address->m_addr; | |
869 | addr_buf = (char *)&(addr->sin_addr); | |
870 | ||
871 | he = gethostbyaddr(addr_buf, sizeof(addr->sin_addr), AF_INET); | |
872 | if (he == NULL) { | |
873 | address->m_error = GSOCK_NOHOST; | |
874 | return GSOCK_NOHOST; | |
875 | } | |
876 | ||
877 | strncpy(hostname, he->h_name, sbuf); | |
878 | ||
879 | return GSOCK_NOERROR; | |
880 | } | |
881 | ||
882 | unsigned long GAddress_INET_GetHostAddress(GAddress *address) | |
883 | { | |
884 | struct sockaddr_in *addr; | |
885 | ||
886 | assert(address != NULL); | |
887 | CHECK_ADDRESS(address, INET, 0); | |
888 | ||
889 | addr = (struct sockaddr_in *)address->m_addr; | |
890 | ||
891 | return addr->sin_addr.s_addr; | |
892 | } | |
893 | ||
894 | unsigned short GAddress_INET_GetPort(GAddress *address) | |
895 | { | |
896 | struct sockaddr_in *addr; | |
897 | ||
898 | assert(address != NULL); | |
899 | CHECK_ADDRESS(address, INET, 0); | |
900 | ||
901 | addr = (struct sockaddr_in *)address->m_addr; | |
902 | return ntohs(addr->sin_port); | |
903 | } | |
904 | ||
905 | /* | |
906 | * ------------------------------------------------------------------------- | |
907 | * Unix address family | |
908 | * ------------------------------------------------------------------------- | |
909 | */ | |
910 | ||
911 | void _GAddress_Init_UNIX(GAddress *address) | |
912 | { | |
913 | address->m_len = sizeof(struct sockaddr_un); | |
914 | address->m_addr = (struct sockaddr *)malloc(address->m_len); | |
915 | address->m_family = GSOCK_UNIX; | |
916 | address->m_realfamily = PF_UNIX; | |
917 | ((struct sockaddr_un *)address->m_addr)->sun_family = AF_UNIX; | |
918 | ((struct sockaddr_un *)address->m_addr)->sun_path[0] = 0; | |
919 | } | |
920 | ||
921 | GSocketError GAddress_UNIX_SetPath(GAddress *address, const char *path) | |
922 | { | |
923 | struct sockaddr_un *addr; | |
924 | ||
925 | assert(address != NULL); | |
926 | ||
927 | CHECK_ADDRESS(address, UNIX, GSOCK_INVADDR); | |
928 | ||
929 | addr = ((struct sockaddr_un *)address->m_addr); | |
930 | memcpy(addr->sun_path, path, strlen(path)); | |
931 | ||
932 | return GSOCK_NOERROR; | |
933 | } | |
934 | ||
935 | GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf) | |
936 | { | |
937 | struct sockaddr_un *addr; | |
938 | ||
939 | assert(address != NULL); | |
940 | CHECK_ADDRESS(address, UNIX, GSOCK_INVADDR); | |
941 | ||
942 | addr = (struct sockaddr_un *)address->m_addr; | |
943 | ||
944 | strncpy(path, addr->sun_path, sbuf); | |
945 | ||
946 | return GSOCK_NOERROR; | |
947 | } |