2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/io/unix.c - UNIX IO utility functions
11 This file implements unbuffered, low-level, UNIX-specific functionality.
12 "UNIX" is a generalization, it may be necessary to create separate OS-specific
13 functions for UNIX flavors.
15 These functions are not part of Parrot's API. Don't call them directly, call
16 the C<PIO_*> macros instead. Each platform defines the standard set of macros,
17 which call the correct functions for that platform.
21 APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons)
31 #include "parrot/parrot.h"
32 #include "io_private.h"
33 #include "pmc/pmc_socket.h"
37 # include <sys/socket.h>
39 /* HEADERIZER HFILE: include/parrot/io_unix.h */
41 /* HEADERIZER BEGIN: static */
42 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
44 static void get_sockaddr_in(PARROT_INTERP
,
45 ARGIN(PMC
* sockaddr
),
46 ARGIN(const char* host
),
48 __attribute__nonnull__(1)
49 __attribute__nonnull__(2)
50 __attribute__nonnull__(3);
52 #define ASSERT_ARGS_get_sockaddr_in __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
53 PARROT_ASSERT_ARG(interp) \
54 , PARROT_ASSERT_ARG(sockaddr) \
55 , PARROT_ASSERT_ARG(host))
56 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
57 /* HEADERIZER END: static */
60 static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr),
61 ARGIN(const char* host), ARGIN(int port));
70 These could be native extensions but they probably should be here if we
71 wish to make them integrated with the async IO system.
73 Very minimal stubs for now, maybe someone will run with these.
77 =item C<PMC * Parrot_io_sockaddr_in(PARROT_INTERP, STRING *addr, INTVAL port)>
79 C<Parrot_io_sockaddr_in()> is not part of the layer and so must be C<extern>.
81 XXX: We can probably just write our own routines (C<htons()>,
82 C<inet_aton()>, etc.) and take this out of platform specific compilation
88 /* Helper macros to get sockaddr_in */
89 # define SOCKADDR_LOCAL(p) ((struct sockaddr_in*)VTABLE_get_pointer(interp, \
90 PARROT_SOCKET((p))->local))
91 # define SOCKADDR_REMOTE(p) ((struct sockaddr_in*)VTABLE_get_pointer(interp, \
92 PARROT_SOCKET((p))->remote))
95 PARROT_WARN_UNUSED_RESULT
96 PARROT_CANNOT_RETURN_NULL
98 Parrot_io_sockaddr_in(PARROT_INTERP
, ARGIN(STRING
*addr
), INTVAL port
)
100 ASSERT_ARGS(Parrot_io_sockaddr_in
)
102 char * const s
= Parrot_str_to_cstring(interp
, addr
);
103 PMC
* const sockaddr
= Parrot_pmc_new(interp
, enum_class_Sockaddr
);
105 get_sockaddr_in(interp
, sockaddr
, s
, port
);
106 Parrot_str_free_cstring(s
);
113 =item C<INTVAL Parrot_io_socket_unix(PARROT_INTERP, PMC *s, int fam, int type,
116 Uses C<socket()> to create a socket with the specified address family,
117 socket type and protocol number.
123 PARROT_WARN_UNUSED_RESULT
124 PARROT_CAN_RETURN_NULL
126 Parrot_io_socket_unix(PARROT_INTERP
, ARGIN(PMC
*s
), int fam
, int type
, int proto
)
128 ASSERT_ARGS(Parrot_io_socket_unix
)
129 const int sock
= socket(fam
, type
, proto
);
132 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &i
, sizeof (i
));
133 Parrot_io_set_os_handle(interp
, s
, sock
);
134 SOCKADDR_REMOTE(s
)->sin_family
= fam
;
142 =item C<INTVAL Parrot_io_connect_unix(PARROT_INTERP, PMC *socket, PMC *r)>
144 Connects C<*io>'s socket to address C<*r>.
151 Parrot_io_connect_unix(PARROT_INTERP
, ARGMOD(PMC
*socket
), ARGIN(PMC
*r
))
153 ASSERT_ARGS(Parrot_io_connect_unix
)
154 const Parrot_Socket_attributes
* const io
= PARROT_SOCKET(socket
);
159 PARROT_SOCKET(socket
)->remote
= r
;
162 if ((connect(io
->os_handle
, (struct sockaddr
*)SOCKADDR_REMOTE(socket
),
163 sizeof (struct sockaddr_in
))) != 0) {
181 =item C<INTVAL Parrot_io_bind_unix(PARROT_INTERP, PMC *socket, PMC *sockaddr)>
183 Binds C<*io>'s socket to the local address and port specified by C<*l>.
190 Parrot_io_bind_unix(PARROT_INTERP
, ARGMOD(PMC
*socket
), ARGMOD(PMC
*sockaddr
))
192 ASSERT_ARGS(Parrot_io_bind_unix
)
193 const Parrot_Socket_attributes
* const io
= PARROT_SOCKET(socket
);
194 struct sockaddr_in
* saddr
;
199 PARROT_SOCKET(socket
)->local
= sockaddr
;
201 saddr
= SOCKADDR_LOCAL(socket
);
203 if ((bind(io
->os_handle
, (struct sockaddr
*) saddr
,
204 sizeof (struct sockaddr_in
))) == -1) {
213 =item C<INTVAL Parrot_io_listen_unix(PARROT_INTERP, PMC *socket, INTVAL sec)>
215 Listen for new connections. This is only applicable to C<STREAM> or
223 Parrot_io_listen_unix(SHIM_INTERP
, ARGMOD(PMC
*socket
), INTVAL sec
)
225 ASSERT_ARGS(Parrot_io_listen_unix
)
226 const Parrot_Socket_attributes
* const io
= PARROT_SOCKET(socket
);
227 if ((listen(io
->os_handle
, sec
)) == -1) {
235 =item C<PMC * Parrot_io_accept_unix(PARROT_INTERP, PMC *socket)>
237 Accept a new connection and return a newly created C<ParrotIO> socket.
243 PARROT_WARN_UNUSED_RESULT
244 PARROT_CAN_RETURN_NULL
246 Parrot_io_accept_unix(PARROT_INTERP
, ARGMOD(PMC
*socket
))
248 ASSERT_ARGS(Parrot_io_accept_unix
)
249 Parrot_Socket_attributes
* io
= PARROT_SOCKET(socket
);
250 PMC
* newio
= Parrot_io_new_socket_pmc(interp
,
251 PIO_F_SOCKET
| PIO_F_READ
|PIO_F_WRITE
);
252 Parrot_Socklen_t addrlen
= sizeof (struct sockaddr_in
);
253 struct sockaddr_in
*saddr
;
256 PARROT_SOCKET(newio
)->local
= PARROT_SOCKET(socket
)->local
;
257 PARROT_SOCKET(newio
)->remote
= Parrot_pmc_new(interp
, enum_class_Sockaddr
);
258 saddr
= SOCKADDR_REMOTE(newio
);
260 newsock
= accept(io
->os_handle
, (struct sockaddr
*)saddr
, &addrlen
);
266 PARROT_SOCKET(newio
)->os_handle
= newsock
;
268 /* XXX FIXME: Need to do a getsockname and getpeername here to
269 * fill in the sockaddr_in structs for local and peer */
271 /* Optionally do a gethostyaddr() to resolve remote IP address.
272 * This should be based on an option set in the master socket */
279 =item C<INTVAL Parrot_io_send_unix(PARROT_INTERP, PMC *socket, STRING *s)>
281 Send the message C<*s> to C<*io>'s connected socket.
288 Parrot_io_send_unix(SHIM_INTERP
, ARGMOD(PMC
*socket
), ARGMOD(STRING
*s
))
290 ASSERT_ARGS(Parrot_io_send_unix
)
291 int error
, bytes
, byteswrote
;
292 Parrot_Socket_attributes
* io
= PARROT_SOCKET(socket
);
298 * Ignore encoding issues for now.
300 if ((error
= send(io
->os_handle
, (char *)s
->strstart
+ byteswrote
,
321 /* XXX why close it here and not below */
322 close(io
->os_handle
);
332 =item C<INTVAL Parrot_io_recv_unix(PARROT_INTERP, PMC *socket, STRING **s)>
334 Receives a message in C<**s> from C<*io>'s connected socket.
341 Parrot_io_recv_unix(PARROT_INTERP
, ARGMOD(PMC
*socket
), ARGOUT(STRING
**s
))
343 ASSERT_ARGS(Parrot_io_recv_unix
)
345 unsigned int bytesread
= 0;
347 Parrot_Socket_attributes
* io
= PARROT_SOCKET(socket
);
350 if ((error
= recv(io
->os_handle
, buf
, 2048, 0)) >= 0) {
352 /* The charset should probably be 'binary', but right now httpd.pir
353 * only works with 'ascii'
355 *s
= string_make(interp
, buf
, bytesread
, "ascii", 0);
370 /* XXX why close it on err return result is -1 anyway */
371 close(io
->os_handle
);
372 *s
= Parrot_str_new_noinit(interp
, enum_stringrep_one
, 0);
375 close(io
->os_handle
);
376 *s
= Parrot_str_new_noinit(interp
, enum_stringrep_one
, 0);
384 =item C<INTVAL Parrot_io_poll_unix(PARROT_INTERP, PMC *socket, int which, int
387 Utility function for polling a single IO stream with a timeout.
389 Returns a 1 | 2 | 4 (read, write, error) value.
391 This is not equivalent to any specific POSIX or BSD socket call, but
392 it is a useful, common primitive.
394 Not at all useful --leo.
396 Also, a buffering layer above this may choose to reimplement by checking
404 Parrot_io_poll_unix(SHIM_INTERP
, ARGMOD(PMC
*socket
), int which
, int sec
,
407 ASSERT_ARGS(Parrot_io_poll_unix
)
410 const Parrot_Socket_attributes
* const io
= PARROT_SOCKET(socket
);
414 FD_ZERO(&r
); FD_ZERO(&w
); FD_ZERO(&e
);
415 /* These should be defined in header */
416 if (which
& 1) FD_SET(io
->os_handle
, &r
);
417 if (which
& 2) FD_SET(io
->os_handle
, &w
);
418 if (which
& 4) FD_SET(io
->os_handle
, &e
);
420 if ((select(io
->os_handle
+1, &r
, &w
, &e
, &t
)) >= 0) {
422 n
= (FD_ISSET(io
->os_handle
, &r
) ? 1 : 0);
423 n
|= (FD_ISSET(io
->os_handle
, &w
) ? 2 : 0);
424 n
|= (FD_ISSET(io
->os_handle
, &e
) ? 4 : 0);
429 case EINTR
: goto AGAIN
;
437 =item C<static void get_sockaddr_in(PARROT_INTERP, PMC * sockaddr, const char*
440 Get a new C<sockaddr_in> structure for the given PMC to connect to the
441 specified host and port.
448 get_sockaddr_in(PARROT_INTERP
, ARGIN(PMC
* sockaddr
), ARGIN(const char* host
),
451 ASSERT_ARGS(get_sockaddr_in
)
452 /* Hard coded to IPv4 for now */
453 const int family
= AF_INET
;
455 struct sockaddr_in
* const sa
= (struct sockaddr_in
*)VTABLE_get_pointer(interp
, sockaddr
);
456 # ifdef PARROT_DEF_INET_ATON
457 if (inet_aton(host
, &sa
->sin_addr
) != 0) {
459 /* positive retval is success */
460 if (inet_pton(family
, host
, &sa
->sin_addr
) > 0) {
462 /* Success converting numeric IP */
465 /* Maybe it is a hostname, try to lookup */
466 /* XXX Check PIO option before doing a name lookup,
467 * it may have been toggled off.
469 struct hostent
*he
= gethostbyname(host
);
470 /* XXX FIXME - Handle error condition better */
472 fprintf(stderr
, "gethostbyname failure [%s]\n", host
);
475 memcpy((char*)&sa
->sin_addr
, he
->h_addr
, sizeof (sa
->sin_addr
));
478 sa
->sin_family
= family
;
479 sa
->sin_port
= htons(port
);
483 #endif /* PIO_OS_UNIX */
494 F<src/io/io_private.h>,
495 F<include/parrot/io_unix.h>.
504 * c-file-style: "parrot"
506 * vim: expandtab shiftwidth=4: