add svn properties
[parrot.git] / src / io / socket_unix.c
blobe66ddefb6d2125ad6774bbd09cf0cdc6b5bd58fa
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/io/unix.c - UNIX IO utility functions
9 =head1 DESCRIPTION
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.
19 =head2 References:
21 APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons)
23 =head2 Functions
25 =over 4
27 =cut
31 #include "parrot/parrot.h"
32 #include "io_private.h"
33 #include "pmc/pmc_socket.h"
35 #ifdef PIO_OS_UNIX
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),
47 int port)
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));
66 =back
68 =head2 Networking
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.
75 =over 4
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
84 =cut
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
97 PMC *
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);
107 return sockaddr;
113 =item C<INTVAL Parrot_io_socket_unix(PARROT_INTERP, PMC *s, int fam, int type,
114 int proto)>
116 Uses C<socket()> to create a socket with the specified address family,
117 socket type and protocol number.
119 =cut
123 PARROT_WARN_UNUSED_RESULT
124 PARROT_CAN_RETURN_NULL
125 INTVAL
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);
130 if (sock >= 0) {
131 int i = 1;
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;
135 return 0;
137 return -1;
142 =item C<INTVAL Parrot_io_connect_unix(PARROT_INTERP, PMC *socket, PMC *r)>
144 Connects C<*io>'s socket to address C<*r>.
146 =cut
150 INTVAL
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);
156 if (!r)
157 return -1;
159 PARROT_SOCKET(socket)->remote = r;
161 AGAIN:
162 if ((connect(io->os_handle, (struct sockaddr *)SOCKADDR_REMOTE(socket),
163 sizeof (struct sockaddr_in))) != 0) {
164 switch (errno) {
165 case EINTR:
166 goto AGAIN;
167 case EINPROGRESS:
168 goto AGAIN;
169 case EISCONN:
170 return 0;
171 default:
172 return -1;
176 return 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>.
185 =cut
189 INTVAL
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;
196 if (!sockaddr)
197 return -1;
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) {
205 return -1;
208 return 0;
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
216 C<SEQ> sockets.
218 =cut
222 INTVAL
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) {
228 return -1;
230 return 0;
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.
239 =cut
243 PARROT_WARN_UNUSED_RESULT
244 PARROT_CAN_RETURN_NULL
245 PMC *
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;
254 int newsock;
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);
262 if (newsock == -1) {
263 return PMCNULL;
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 */
274 return newio;
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.
283 =cut
287 INTVAL
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);
294 bytes = s->bufused;
295 byteswrote = 0;
296 AGAIN:
298 * Ignore encoding issues for now.
300 if ((error = send(io->os_handle, (char *)s->strstart + byteswrote,
301 bytes, 0)) >= 0) {
302 byteswrote += error;
303 bytes -= error;
304 if (!bytes) {
305 return byteswrote;
307 goto AGAIN;
309 else {
310 switch (errno) {
311 case EINTR:
312 goto AGAIN;
313 # ifdef EWOULDBLOCK
314 case EWOULDBLOCK:
315 goto AGAIN;
316 # else
317 case EAGAIN:
318 goto AGAIN;
319 # endif
320 case EPIPE:
321 /* XXX why close it here and not below */
322 close(io->os_handle);
323 return -1;
324 default:
325 return -1;
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.
336 =cut
340 INTVAL
341 Parrot_io_recv_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGOUT(STRING **s))
343 ASSERT_ARGS(Parrot_io_recv_unix)
344 int error;
345 unsigned int bytesread = 0;
346 char buf[2048];
347 Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
349 AGAIN:
350 if ((error = recv(io->os_handle, buf, 2048, 0)) >= 0) {
351 bytesread += error;
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);
356 return bytesread;
358 else {
359 switch (errno) {
360 case EINTR:
361 goto AGAIN;
362 # ifdef EWOULDBLOCK
363 case EWOULDBLOCK:
364 goto AGAIN;
365 # else
366 case EAGAIN:
367 goto AGAIN;
368 # endif
369 case ECONNRESET:
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);
373 return -1;
374 default:
375 close(io->os_handle);
376 *s = Parrot_str_new_noinit(interp, enum_stringrep_one, 0);
377 return -1;
384 =item C<INTVAL Parrot_io_poll_unix(PARROT_INTERP, PMC *socket, int which, int
385 sec, int usec)>
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
397 the read buffer.
399 =cut
403 INTVAL
404 Parrot_io_poll_unix(SHIM_INTERP, ARGMOD(PMC *socket), int which, int sec,
405 int usec)
407 ASSERT_ARGS(Parrot_io_poll_unix)
408 fd_set r, w, e;
409 struct timeval t;
410 const Parrot_Socket_attributes * const io = PARROT_SOCKET(socket);
412 t.tv_sec = sec;
413 t.tv_usec = usec;
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);
419 AGAIN:
420 if ((select(io->os_handle+1, &r, &w, &e, &t)) >= 0) {
421 int n;
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);
425 return n;
427 else {
428 switch (errno) {
429 case EINTR: goto AGAIN;
430 default: return -1;
437 =item C<static void get_sockaddr_in(PARROT_INTERP, PMC * sockaddr, const char*
438 host, int port)>
440 Get a new C<sockaddr_in> structure for the given PMC to connect to the
441 specified host and port.
443 =cut
447 static void
448 get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host),
449 int port)
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) {
458 # else
459 /* positive retval is success */
460 if (inet_pton(family, host, &sa->sin_addr) > 0) {
461 # endif
462 /* Success converting numeric IP */
464 else {
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 */
471 if (!he) {
472 fprintf(stderr, "gethostbyname failure [%s]\n", host);
473 return;
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 */
487 =back
489 =head1 SEE ALSO
491 F<src/io/common.c>,
492 F<src/io/win32.c>,
493 F<src/io/stdio.c>,
494 F<src/io/io_private.h>,
495 F<include/parrot/io_unix.h>.
497 =cut
503 * Local variables:
504 * c-file-style: "parrot"
505 * End:
506 * vim: expandtab shiftwidth=4: