tagged release 0.7.1
[parrot.git] / src / io / io_unix.c
blobae49dfd83a8d32ba52fe1108a760155a53b28e61
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/io/io_unix.c - UNIX IO layer
9 =head1 DESCRIPTION
11 This is the Parrot UNIX IO layer. It implements unbuffered, low-level,
12 UNIX-specific functionality.
14 As "UNIX" is already a generalization, it may be necessary to create
15 separate OS-specific layers for UNIX flavors, to avoid
16 over-complicating this file.
18 =head2 References:
20 APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons)
22 =head2 Functions
24 =over 4
26 =cut
30 #include "parrot/parrot.h"
31 #include "io_private.h"
33 #ifdef PIO_OS_UNIX
35 /* Defined at bottom */
36 extern const ParrotIOLayerAPI pio_unix_layer_api;
38 ParrotIOLayer pio_unix_layer = {
39 NULL,
40 "unix",
41 PIO_L_TERMINAL,
42 &pio_unix_layer_api,
43 0, 0
46 /* HEADERIZER HFILE: none */
48 /* HEADERIZER BEGIN: static */
49 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
51 PARROT_CONST_FUNCTION
52 static INTVAL flags_to_unix(INTVAL flags);
54 PARROT_WARN_UNUSED_RESULT
55 PARROT_CAN_RETURN_NULL
56 static ParrotIO * PIO_unix_accept(PARROT_INTERP,
57 SHIM(ParrotIOLayer *layer),
58 ARGMOD(ParrotIO *io))
59 __attribute__nonnull__(1)
60 __attribute__nonnull__(3)
61 FUNC_MODIFIES(*io);
63 static INTVAL PIO_unix_bind(SHIM_INTERP,
64 SHIM(ParrotIOLayer *layer),
65 ARGMOD(ParrotIO *io),
66 ARGMOD(STRING *l))
67 __attribute__nonnull__(3)
68 __attribute__nonnull__(4)
69 FUNC_MODIFIES(*io)
70 FUNC_MODIFIES(*l);
72 static INTVAL PIO_unix_close(SHIM_INTERP,
73 SHIM(ParrotIOLayer *layer),
74 ARGMOD(ParrotIO *io))
75 __attribute__nonnull__(3)
76 FUNC_MODIFIES(*io);
78 static INTVAL PIO_unix_connect(SHIM_INTERP,
79 SHIM(ParrotIOLayer *layer),
80 ARGMOD(ParrotIO *io),
81 ARGIN_NULLOK(STRING *r))
82 __attribute__nonnull__(3)
83 FUNC_MODIFIES(*io);
85 PARROT_WARN_UNUSED_RESULT
86 PARROT_CANNOT_RETURN_NULL
87 static ParrotIO * PIO_unix_fdopen(PARROT_INTERP,
88 SHIM(ParrotIOLayer *layer),
89 PIOHANDLE fd,
90 INTVAL flags)
91 __attribute__nonnull__(1);
93 static INTVAL PIO_unix_flush(SHIM_INTERP,
94 SHIM(ParrotIOLayer *layer),
95 ARGMOD(ParrotIO *io))
96 __attribute__nonnull__(3)
97 FUNC_MODIFIES(*io);
99 static INTVAL PIO_unix_init(PARROT_INTERP, ARGIN(ParrotIOLayer *layer))
100 __attribute__nonnull__(1)
101 __attribute__nonnull__(2);
103 static INTVAL PIO_unix_isatty(PIOHANDLE fd);
104 static INTVAL PIO_unix_listen(SHIM_INTERP,
105 SHIM(ParrotIOLayer *layer),
106 ARGIN(ParrotIO *io),
107 INTVAL sec)
108 __attribute__nonnull__(3);
110 PARROT_WARN_UNUSED_RESULT
111 PARROT_CAN_RETURN_NULL
112 static ParrotIO * PIO_unix_open(PARROT_INTERP,
113 ARGIN(ParrotIOLayer *layer),
114 ARGIN(const char *spath),
115 INTVAL flags)
116 __attribute__nonnull__(1)
117 __attribute__nonnull__(2)
118 __attribute__nonnull__(3);
120 PARROT_WARN_UNUSED_RESULT
121 PARROT_CAN_RETURN_NULL
122 static ParrotIO * PIO_unix_pipe(PARROT_INTERP,
123 SHIM(ParrotIOLayer *l),
124 ARGIN(const char *cmd),
125 int flags)
126 __attribute__nonnull__(1)
127 __attribute__nonnull__(3);
129 static INTVAL PIO_unix_poll(SHIM_INTERP,
130 SHIM(ParrotIOLayer *l),
131 ARGMOD(ParrotIO *io),
132 int which,
133 int sec,
134 int usec)
135 __attribute__nonnull__(3)
136 FUNC_MODIFIES(*io);
138 static size_t PIO_unix_read(PARROT_INTERP,
139 SHIM(ParrotIOLayer *layer),
140 ARGMOD(ParrotIO *io),
141 ARGIN(STRING **buf))
142 __attribute__nonnull__(1)
143 __attribute__nonnull__(3)
144 __attribute__nonnull__(4)
145 FUNC_MODIFIES(*io);
147 static INTVAL PIO_unix_recv(PARROT_INTERP,
148 SHIM(ParrotIOLayer *layer),
149 ARGMOD(ParrotIO *io),
150 ARGOUT(STRING **s))
151 __attribute__nonnull__(1)
152 __attribute__nonnull__(3)
153 __attribute__nonnull__(4)
154 FUNC_MODIFIES(*io)
155 FUNC_MODIFIES(*s);
157 static PIOOFF_T PIO_unix_seek(SHIM_INTERP,
158 SHIM(ParrotIOLayer *layer),
159 ARGMOD(ParrotIO *io),
160 PIOOFF_T offset,
161 INTVAL whence)
162 __attribute__nonnull__(3)
163 FUNC_MODIFIES(*io);
165 static INTVAL PIO_unix_send(SHIM_INTERP,
166 SHIM(ParrotIOLayer *layer),
167 ARGMOD(ParrotIO *io),
168 ARGMOD(STRING *s))
169 __attribute__nonnull__(3)
170 __attribute__nonnull__(4)
171 FUNC_MODIFIES(*io)
172 FUNC_MODIFIES(*s);
174 PARROT_WARN_UNUSED_RESULT
175 PARROT_CAN_RETURN_NULL
176 static ParrotIO * PIO_unix_socket(PARROT_INTERP,
177 SHIM(ParrotIOLayer *layer),
178 int fam,
179 int type,
180 int proto)
181 __attribute__nonnull__(1);
183 static PIOOFF_T PIO_unix_tell(SHIM_INTERP,
184 SHIM(ParrotIOLayer *layer),
185 ARGMOD(ParrotIO *io))
186 __attribute__nonnull__(3)
187 FUNC_MODIFIES(*io);
189 static size_t PIO_unix_write(SHIM_INTERP,
190 SHIM(ParrotIOLayer *layer),
191 ARGMOD(ParrotIO *io),
192 ARGMOD(STRING *s))
193 __attribute__nonnull__(3)
194 __attribute__nonnull__(4)
195 FUNC_MODIFIES(*io)
196 FUNC_MODIFIES(*s);
198 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
199 /* HEADERIZER END: static */
204 =item C<static INTVAL flags_to_unix>
206 Returns a UNIX-specific interpretation of C<flags> suitable for passing
207 to C<open()> and C<fopen()> in C<PIO_unix_open()> and
208 C<PIO_unix_fdopen()> respectively.
210 =cut
214 PARROT_CONST_FUNCTION
215 static INTVAL
216 flags_to_unix(INTVAL flags)
218 INTVAL oflags = 0;
220 if ((flags & (PIO_F_WRITE | PIO_F_READ)) == (PIO_F_WRITE | PIO_F_READ)) {
221 oflags |= O_RDWR | O_CREAT;
223 else if (flags & PIO_F_WRITE) {
224 oflags |= O_WRONLY | O_CREAT;
226 else if (flags & PIO_F_READ) {
227 oflags |= O_RDONLY;
230 if (flags & PIO_F_APPEND) {
231 oflags |= O_APPEND;
233 else if (flags & PIO_F_TRUNC) {
234 oflags |= O_TRUNC;
236 return oflags;
241 =item C<static INTVAL PIO_unix_init>
243 Sets up the interpreter's standard C<std*> IO handles. Returns C<0> on
244 success and C<-1> on error.
246 =cut
250 static INTVAL
251 PIO_unix_init(PARROT_INTERP, ARGIN(ParrotIOLayer *layer))
253 ParrotIOData * const d = interp->piodata;
254 if (d != NULL && d->table != NULL) {
255 ParrotIO *io;
257 io = PIO_unix_fdopen(interp, layer, STDIN_FILENO, PIO_F_READ);
258 if (!io)
259 return -1;
260 _PIO_STDIN(interp) = new_io_pmc(interp, io);
262 io = PIO_unix_fdopen(interp, layer, STDOUT_FILENO, PIO_F_WRITE);
263 if (!io)
264 return -1;
265 _PIO_STDOUT(interp) = new_io_pmc(interp, io);
267 io = PIO_unix_fdopen(interp, layer, STDERR_FILENO, PIO_F_WRITE);
268 if (!io)
269 return -1;
270 _PIO_STDERR(interp) = new_io_pmc(interp, io);
272 return 0;
274 return -1;
279 =item C<static ParrotIO * PIO_unix_open>
281 Opens C<*spath>. C<flags> is a bitwise C<or> combination of C<PIO_F_*>
282 values.
284 =cut
288 PARROT_WARN_UNUSED_RESULT
289 PARROT_CAN_RETURN_NULL
290 static ParrotIO *
291 PIO_unix_open(PARROT_INTERP, ARGIN(ParrotIOLayer *layer),
292 ARGIN(const char *spath), INTVAL flags)
294 INTVAL oflags;
295 PIOHANDLE fd;
297 const INTVAL type = PIO_TYPE_FILE;
298 const INTVAL mode = DEFAULT_OPEN_MODE;
300 if (flags & PIO_F_PIPE)
301 return PIO_unix_pipe(interp, layer, spath, flags);
303 if ((flags & (PIO_F_WRITE | PIO_F_READ)) == 0)
304 return NULL;
306 oflags = flags_to_unix(flags);
308 /* Only files for now */
309 flags |= PIO_F_FILE;
311 /* Try open with no create first */
312 while ((fd = open(spath, oflags & (O_WRONLY | O_RDWR | O_APPEND), mode))
313 < 0 && errno == EINTR)
314 errno = 0;
316 /* File open */
317 if (fd >= 0) {
319 * Now check if we specified O_CREAT|O_EXCL or not.
320 * If so, we must return NULL, else either use the
321 * descriptor or create the file.
323 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
324 close(fd);
325 return NULL;
328 * Check for truncate?
330 if (oflags & O_TRUNC) {
331 int tfd;
332 while ((tfd = creat(spath, PIO_DEFAULTMODE)) < 0 && errno == EINTR)
333 errno = 0;
334 close(tfd);
337 else if (oflags & O_CREAT) {
338 /* O_CREAT and file doesn't exist. */
339 while ((fd = creat(spath, PIO_DEFAULTMODE)) < 0 && errno == EINTR)
340 errno = 0;
341 if (!(oflags & O_WRONLY)) {
342 close(fd);
344 * File created, reopen with read+write
346 while ((fd = open(spath, oflags & (O_WRONLY | O_RDWR),
347 mode)) < 0 && errno == EINTR)
348 errno = 0;
351 else {
352 /* File doesn't exist and O_CREAT not specified */
355 if (fd >= 0) {
356 /* Set generic flag here if is a terminal then
357 * higher layers can know how to setup buffering.
358 * STDIN, STDOUT, STDERR would be in this case
359 * so we would setup linebuffering.
361 ParrotIO *io;
362 if (PIO_unix_isatty(fd))
363 flags |= PIO_F_CONSOLE;
364 io = PIO_new(interp, type, flags, mode);
365 io->fd = fd;
366 return io;
368 return NULL;
372 # if PARROT_ASYNC_DEVEL
376 =item C<INTVAL PIO_unix_async>
378 Experimental asynchronous IO.
380 This is available if C<PARROT_ASYNC_DEVEL> is defined.
382 Only works on Linux at the moment.
384 Toggles the C<O_ASYNC> flag on the IO file descriptor.
386 =cut
390 INTVAL
391 PIO_unix_async(PARROT_INTERP, ARGMOD(ParrotIOLayer *layer), ARGMOD(ParrotIO *io), INTVAL b)
393 int rflags;
394 # if defined(linux)
395 if ((rflags = fcntl(io->fd, F_GETFL, 0)) >= 0) {
396 if (b)
397 rflags |= O_ASYNC;
398 else
399 rflags &= ~O_ASYNC;
400 return fcntl(io->fd, F_SETFL, rflags);
402 # else
403 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_NOT_IMPLEMENTED,
404 "Async support not available");
405 # endif
406 return -1;
409 # endif
413 =item C<static ParrotIO * PIO_unix_fdopen>
415 Returns a new C<ParrotIO> with file descriptor C<fd>.
417 =cut
421 PARROT_WARN_UNUSED_RESULT
422 PARROT_CANNOT_RETURN_NULL
423 static ParrotIO *
424 PIO_unix_fdopen(PARROT_INTERP, SHIM(ParrotIOLayer *layer), PIOHANDLE fd, INTVAL flags)
426 ParrotIO *io;
427 const INTVAL mode = 0;
429 # if 0
430 /* XXX the fcntl fails (-1, errno=0) with
431 * ./parrot -tf - < foo.pir
434 /* FIXME - Check file handle flags, validity */
435 # ifdef PARROT_HAS_HEADER_FCNTL
437 INTVAL rflags;
438 /* Get descriptor flags */
439 if ((rflags = fcntl(fd, F_GETFL, 0)) >= 0) {
440 UNUSED(rflags);
441 /*int accmode = rflags & O_ACCMODE; */
442 /* Check other flags (APPEND, ASYNC, etc) */
444 else {
445 /* Probably invalid descriptor */
446 return NULL;
449 # endif
450 # endif
452 if (PIO_unix_isatty(fd))
453 flags |= PIO_F_CONSOLE;
455 /* fdopened files are always shared */
456 flags |= PIO_F_SHARED;
458 io = PIO_new(interp, PIO_F_FILE, flags, mode);
459 io->fd = fd;
460 return io;
465 =item C<static INTVAL PIO_unix_close>
467 Closes C<*io>'s file descriptor.
469 =cut
473 static INTVAL
474 PIO_unix_close(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io))
476 /* BSD and Solaris need explicit fsync() */
477 if (io->fd >= 0) {
478 fsync(io->fd);
479 close(io->fd);
481 io->fd = -1;
482 return 0;
487 =item C<static INTVAL PIO_unix_isatty>
489 Returns a boolean value indicating whether C<fd> is a console/tty.
491 =cut
495 static INTVAL
496 PIO_unix_isatty(PIOHANDLE fd)
498 return isatty(fd);
503 =item C<INTVAL PIO_unix_getblksize>
505 Various ways of determining block size.
507 If passed a file descriptor then C<fstat()> and the C<stat> buffer are
508 used if available.
510 If called without an argument then the C<BLKSIZE> constant is returned
511 if it was available at compile time, otherwise C<PIO_BLKSIZE> is returned.
513 =cut
517 INTVAL
518 PIO_unix_getblksize(PIOHANDLE fd)
520 if (fd >= 0) {
521 /* Try to get the block size of a regular file */
522 # if 0
524 * Is it even worth adding non-portable code here
525 * or should we just estimate a nice buffer size?
526 * Some systems have st_blksize, some don't.
529 struct stat sbuf;
530 int err;
531 err = fstat(fd, &sbuf);
532 if (err == 0) {
533 return sbuf.st_blksize;
536 # endif
538 /* Try to determine it from general means. */
539 # ifdef BLKSIZE
540 return BLKSIZE;
541 # else
542 return PIO_BLKSIZE;
543 # endif
548 =item C<static INTVAL PIO_unix_flush>
550 At lowest layer all we can do for C<flush> is to ask the kernel to
551 C<sync()>.
553 XXX: Is it necessary to C<sync()> here?
555 =cut
559 static INTVAL
560 PIO_unix_flush(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io))
562 return fsync(io->fd);
567 =item C<static size_t PIO_unix_read>
569 Calls C<read()> to return up to C<len> bytes in the memory starting at
570 C<buffer>.
572 =cut
576 static size_t
577 PIO_unix_read(PARROT_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io),
578 ARGIN(STRING **buf))
580 STRING * const s = PIO_make_io_string(interp, buf, 2048);
582 const size_t len = s->bufused;
583 void * const buffer = s->strstart;
585 for (;;) {
586 const int bytes = read(io->fd, buffer, len);
587 if (bytes > 0) {
588 s->bufused = s->strlen = bytes;
589 return bytes;
591 else if (bytes < 0) {
592 switch (errno) {
593 case EINTR:
594 continue;
595 default:
596 s->bufused = s->strlen = 0;
597 return bytes;
600 else {
601 /* Read returned 0, EOF if len requested > 0 */
602 if (len > 0)
603 io->flags |= PIO_F_EOF;
604 s->bufused = s->strlen = 0;
605 return bytes;
612 =item C<static size_t PIO_unix_write>
614 Calls C<write()> to write C<len> bytes from the memory starting at
615 C<buffer> to the file descriptor in C<*io>.
617 =cut
621 static size_t
622 PIO_unix_write(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io), ARGMOD(STRING *s))
624 const char * const buffer = s->strstart;
625 const char * ptr = buffer;
627 size_t to_write = s->bufused;
628 size_t written = 0;
630 write_through:
631 while (to_write > 0) {
632 const int err = write(io->fd, ptr, to_write);
633 if (err >= 0) {
634 ptr += err;
635 to_write -= err;
636 written += err;
638 else {
639 switch (errno) {
640 case EINTR:
641 goto write_through;
642 # ifdef EAGAIN
643 case EAGAIN:
644 return written;
645 # endif
646 default:
647 return (size_t)-1;
651 return written;
656 =item C<static PIOOFF_T PIO_unix_seek>
658 Hard seek.
660 Calls C<lseek()> to advance the read/write position on C<*io>'s file
661 descriptor to C<offset> bytes from the location indicated by C<whence>.
663 =cut
667 static PIOOFF_T
668 PIO_unix_seek(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io),
669 PIOOFF_T offset, INTVAL whence)
671 const PIOOFF_T pos = lseek(io->fd, offset, whence);
673 if (pos >= 0) {
674 switch (whence) {
675 case SEEK_SET:
676 io->fsize = offset > io->fsize ? offset : io->fsize;
677 break;
678 case SEEK_CUR:
680 const PIOOFF_T avail = io->b.next - io->b.startb + offset;
681 io->fsize = (avail > io->fsize) ? avail : io->fsize;
683 break;
684 case SEEK_END:
685 default:
686 break;
689 io->lpos = io->fpos;
690 io->fpos = pos;
692 /* Seek clears EOF */
693 io->flags &= ~PIO_F_EOF;
694 return pos;
699 =item C<static PIOOFF_T PIO_unix_tell>
701 Returns the current read/write position on C<*io>'s file discriptor.
703 =cut
707 static PIOOFF_T
708 PIO_unix_tell(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io))
710 const PIOOFF_T pos = lseek(io->fd, (PIOOFF_T)0, SEEK_CUR);
712 return pos;
717 =back
719 =head2 Networking
721 Define C<PARROT_NET_DEVEL> to enable networking.
723 These could be native extensions but they probably should be here if we
724 wish to make them integrated with the async IO system.
726 Very minimal stubs for now, maybe someone will run with these.
728 =over 4
730 =item C<STRING * PIO_sockaddr_in>
732 C<PIO_sockaddr_in()> is not part of the layer and so must be C<extern>.
734 XXX: We can probably just write our own routines (C<htons()>,
735 C<inet_aton()>, etc.) and take this out of platform specific compilation
737 =cut
741 PARROT_WARN_UNUSED_RESULT
742 PARROT_CANNOT_RETURN_NULL
743 STRING *
744 PIO_sockaddr_in(PARROT_INTERP, unsigned short port, ARGIN(STRING *addr))
746 struct sockaddr_in sa;
747 /* Hard coded to IPv4 for now */
748 const int family = AF_INET;
750 char * const s = string_to_cstring(interp, addr);
752 * due to a bug in OS/X, we've to zero the struct
753 * else bind is failing erratically
755 memset(&sa, 0, sizeof (sa));
756 # ifdef PARROT_DEF_INET_ATON
757 if (inet_aton(s, &sa.sin_addr) != 0) {
758 # else
759 /* positive retval is success */
760 if (inet_pton(family, s, &sa.sin_addr) > 0) {
761 # endif
762 /* Success converting numeric IP */
764 else {
765 /* Maybe it is a hostname, try to lookup */
766 /* XXX Check PIO option before doing a name lookup,
767 * it may have been toggled off.
769 struct hostent *he = gethostbyname(s);
770 /* XXX FIXME - Handle error condition better */
771 if (!he) {
772 string_cstring_free(s);
773 fprintf(stderr, "gethostbyname failure [%s]\n", s);
774 return NULL;
776 memcpy((char*)&sa.sin_addr, he->h_addr, sizeof (sa.sin_addr));
778 string_cstring_free(s);
780 sa.sin_family = family;
781 sa.sin_port = htons(port);
783 return string_make(interp, (char *)&sa, sizeof (struct sockaddr_in),
784 "binary", 0);
788 # if PARROT_NET_DEVEL
792 =item C<static ParrotIO * PIO_unix_socket>
794 Uses C<socket()> to create a socket with the specified address family,
795 socket type and protocol number.
797 =cut
801 PARROT_WARN_UNUSED_RESULT
802 PARROT_CAN_RETURN_NULL
803 static ParrotIO *
804 PIO_unix_socket(PARROT_INTERP, SHIM(ParrotIOLayer *layer), int fam, int type, int proto)
806 const int sock = socket(fam, type, proto);
807 if (sock >= 0) {
808 ParrotIO * const io = PIO_new(interp, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
809 io->fd = sock;
810 memset(&io->local, 0, sizeof (struct sockaddr_in));
811 memset(&io->remote, 0, sizeof (struct sockaddr_in));
812 io->remote.sin_family = fam;
813 return io;
815 return NULL;
820 =item C<static INTVAL PIO_unix_connect>
822 Connects C<*io>'s socket to address C<*r>.
824 =cut
828 static INTVAL
829 PIO_unix_connect(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io),
830 ARGIN_NULLOK(STRING *r))
832 struct sockaddr_in * saddr = &io->remote;
834 if (r)
835 memcpy(&io->remote, PObj_bufstart(r), sizeof (struct sockaddr_in));
837 AGAIN:
838 if ((connect(io->fd, (struct sockaddr *)saddr,
839 sizeof (struct sockaddr_in))) != 0) {
840 switch (errno) {
841 case EINTR:
842 goto AGAIN;
843 case EINPROGRESS:
844 goto AGAIN;
845 case EISCONN:
846 return 0;
847 default:
848 return -1;
852 return 0;
857 =item C<static INTVAL PIO_unix_bind>
859 Binds C<*io>'s socket to the local address and port specified by C<*l>.
861 =cut
865 static INTVAL
866 PIO_unix_bind(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io),
867 ARGMOD(STRING *l))
869 struct sockaddr_in * saddr = &io->local;
871 if (!l)
872 return -1;
874 memcpy(&io->local, PObj_bufstart(l), sizeof (struct sockaddr_in));
876 if ((bind(io->fd, (struct sockaddr *) saddr,
877 sizeof (struct sockaddr_in))) == -1) {
878 return -1;
881 return 0;
886 =item C<static INTVAL PIO_unix_listen>
888 Listen for new connections. This is only applicable to C<STREAM> or
889 C<SEQ> sockets.
891 =cut
895 static INTVAL
896 PIO_unix_listen(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGIN(ParrotIO *io),
897 INTVAL sec)
899 if ((listen(io->fd, sec)) == -1) {
900 return -1;
902 return 0;
907 =item C<static ParrotIO * PIO_unix_accept>
909 Accept a new connection and return a newly created C<ParrotIO> socket.
911 =cut
915 PARROT_WARN_UNUSED_RESULT
916 PARROT_CAN_RETURN_NULL
917 static ParrotIO *
918 PIO_unix_accept(PARROT_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io))
920 ParrotIO * const newio = PIO_new(interp, PIO_F_SOCKET, 0,
921 PIO_F_READ|PIO_F_WRITE);
922 Parrot_Socklen_t addrlen = sizeof (struct sockaddr_in);
923 struct sockaddr_in *saddr = &newio->remote;
924 const int newsock = accept(io->fd, (struct sockaddr *)saddr,
925 &addrlen);
927 if (newsock == -1) {
928 mem_sys_free(newio);
929 return NULL;
932 newio->fd = newsock;
934 /* XXX FIXME: Need to do a getsockname and getpeername here to
935 * fill in the sockaddr_in structs for local and peer */
937 /* Optionally do a gethostyaddr() to resolve remote IP address.
938 * This should be based on an option set in the master socket */
940 return newio;
945 =item C<static INTVAL PIO_unix_send>
947 Send the message C<*s> to C<*io>'s connected socket.
949 =cut
953 static INTVAL
954 PIO_unix_send(SHIM_INTERP, SHIM(ParrotIOLayer *layer), ARGMOD(ParrotIO *io),
955 ARGMOD(STRING *s))
957 int error, bytes, byteswrote;
959 bytes = s->bufused;
960 byteswrote = 0;
961 AGAIN:
963 * Ignore encoding issues for now.
965 if ((error = send(io->fd, (char *)s->strstart + byteswrote,
966 bytes, 0)) >= 0) {
967 byteswrote += error;
968 bytes -= error;
969 if (!bytes) {
970 return byteswrote;
972 goto AGAIN;
974 else {
975 switch (errno) {
976 case EINTR:
977 goto AGAIN;
978 # ifdef EWOULDBLOCK
979 case EWOULDBLOCK:
980 goto AGAIN;
981 # else
982 case EAGAIN:
983 goto AGAIN;
984 # endif
985 case EPIPE:
986 /* XXX why close it here and not below */
987 close(io->fd);
988 return -1;
989 default:
990 return -1;
997 =item C<static INTVAL PIO_unix_recv>
999 Receives a message in C<**s> from C<*io>'s connected socket.
1001 =cut
1005 static INTVAL
1006 PIO_unix_recv(PARROT_INTERP, SHIM(ParrotIOLayer *layer),
1007 ARGMOD(ParrotIO *io), ARGOUT(STRING **s))
1009 int error;
1010 unsigned int bytesread = 0;
1011 char buf[2048];
1013 AGAIN:
1014 if ((error = recv(io->fd, buf, 2048, 0)) >= 0) {
1015 bytesread += error;
1016 /* The charset should probably be 'binary', but right now httpd.pir
1017 * only works with 'ascii'
1019 *s = string_make(interp, buf, bytesread, "ascii", 0);
1020 return bytesread;
1022 else {
1023 switch (errno) {
1024 case EINTR:
1025 goto AGAIN;
1026 # ifdef EWOULDBLOCK
1027 case EWOULDBLOCK:
1028 goto AGAIN;
1029 # else
1030 case EAGAIN:
1031 goto AGAIN;
1032 # endif
1033 case ECONNRESET:
1034 /* XXX why close it on err return result is -1 anyway */
1035 close(io->fd);
1036 *s = string_make_empty(interp, enum_stringrep_one, 0);
1037 return -1;
1038 default:
1039 close(io->fd);
1040 *s = string_make_empty(interp, enum_stringrep_one, 0);
1041 return -1;
1048 =item C<static INTVAL PIO_unix_poll>
1050 Utility function for polling a single IO stream with a timeout.
1052 Returns a 1 | 2 | 4 (read, write, error) value.
1054 This is not equivalent to any speficic POSIX or BSD socket call, however
1055 it is a useful, common primitive.
1057 Not at all usefule --leo.
1059 Also, a buffering layer above this may choose to reimpliment by checking
1060 the read buffer.
1062 =cut
1066 static INTVAL
1067 PIO_unix_poll(SHIM_INTERP, SHIM(ParrotIOLayer *l), ARGMOD(ParrotIO *io), int which,
1068 int sec, int usec)
1070 int n;
1071 fd_set r, w, e;
1072 struct timeval t;
1074 t.tv_sec = sec;
1075 t.tv_usec = usec;
1076 FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
1077 /* These should be defined in header */
1078 if (which & 1) FD_SET(io->fd, &r);
1079 if (which & 2) FD_SET(io->fd, &w);
1080 if (which & 4) FD_SET(io->fd, &e);
1081 AGAIN:
1082 if ((select(io->fd+1, &r, &w, &e, &t)) >= 0) {
1083 n = (FD_ISSET(io->fd, &r) ? 1 : 0);
1084 n |= (FD_ISSET(io->fd, &w) ? 2 : 0);
1085 n |= (FD_ISSET(io->fd, &e) ? 4 : 0);
1086 return n;
1088 else {
1089 switch (errno) {
1090 case EINTR: goto AGAIN;
1091 default: return -1;
1096 # endif
1099 =item C<static ParrotIO * PIO_unix_pipe>
1101 Very limited C<exec> for now.
1103 XXX: Where does this fit, should it belong in the ParrotIOLayerAPI?
1105 =cut
1109 PARROT_WARN_UNUSED_RESULT
1110 PARROT_CAN_RETURN_NULL
1111 static ParrotIO *
1112 PIO_unix_pipe(PARROT_INTERP, SHIM(ParrotIOLayer *l), ARGIN(const char *cmd), int flags)
1115 * pipe(), fork() should be defined, if this header is present
1116 * if that's not true, we need a test
1118 # ifdef PARROT_HAS_HEADER_UNISTD
1119 int pid, err, fds[2];
1121 err = pipe(fds);
1122 if (err < 0) {
1123 return NULL;
1126 /* Parent - return IO stream */
1127 if ((pid = fork()) > 0) {
1128 ParrotIO * const io =
1129 PIO_new(interp, PIO_F_PIPE, 0, flags & (PIO_F_READ|PIO_F_WRITE));
1130 if (flags & PIO_F_READ) {
1131 /* close this writer's end of pipe */
1132 close(fds[1]);
1133 io->fd = fds[0];
1134 io->fd2 = 0;
1136 else { /* assume write only for now */
1137 /* close this reader's end */
1138 close(fds[0]);
1139 io->fd = fds[1];
1140 io->fd2 = 0;
1142 return io;
1145 /* Child - exec process */
1146 if (pid == 0) {
1147 char *argv[10], *p, *c;
1148 int n;
1150 if (flags & PIO_F_WRITE) {
1151 /* the other end is writing - we read from the pipe */
1152 close(STDIN_FILENO);
1153 close(fds[1]);
1154 if (Parrot_dup(fds[0]) != STDIN_FILENO) {
1155 exit(EXIT_SUCCESS);
1158 else {
1159 /* XXX redirect stdout, stderr to pipe */
1160 close(STDIN_FILENO);
1161 close(STDOUT_FILENO);
1162 close(STDERR_FILENO);
1163 if (Parrot_dup(fds[0]) != STDIN_FILENO
1164 || Parrot_dup(fds[1]) != STDOUT_FILENO
1165 || Parrot_dup(fds[1]) != STDERR_FILENO)
1167 exit(EXIT_SUCCESS);
1171 * XXX ugly hack to be able to pass some arguments
1172 * split cmd at blanks
1174 c = strdup(cmd);
1175 for (n = 0, p = strtok(c, " "); n < 9 && p; p = strtok(NULL, " ")) {
1176 if (n == 0)
1177 cmd = p;
1178 argv[n++] = p;
1180 argv[n] = NULL;
1181 execv(cmd, argv); /* XXX use execvp ? */
1182 /* Will never reach this unless exec fails. */
1183 perror("execvp");
1184 exit(EXIT_FAILURE);
1187 perror("fork");
1188 # else
1189 UNUSED(l);
1190 UNUSED(cmd);
1191 UNUSED(flags);
1192 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
1193 "pipe() unimplemented");
1194 # endif
1195 return NULL;
1199 const ParrotIOLayerAPI pio_unix_layer_api = {
1200 PIO_unix_init,
1201 PIO_base_new_layer,
1202 PIO_base_delete_layer,
1203 PIO_null_push_layer,
1204 PIO_null_pop_layer,
1205 PIO_unix_open,
1206 PIO_null_open2,
1207 PIO_null_open3,
1208 PIO_null_open_async,
1209 PIO_unix_fdopen,
1210 PIO_unix_close,
1211 PIO_unix_write,
1212 PIO_null_write_async,
1213 PIO_unix_read,
1214 PIO_null_read_async,
1215 PIO_unix_flush,
1216 NULL, /* no peek */
1217 PIO_unix_seek,
1218 PIO_unix_tell,
1219 PIO_null_setbuf,
1220 PIO_null_setlinebuf,
1221 PIO_null_getcount,
1222 PIO_null_fill,
1223 PIO_null_eof,
1224 # if PARROT_NET_DEVEL
1225 PIO_unix_poll,
1226 PIO_unix_socket,
1227 PIO_unix_connect,
1228 PIO_unix_send,
1229 PIO_unix_recv,
1230 PIO_unix_bind,
1231 PIO_unix_listen,
1232 PIO_unix_accept
1233 # else
1234 NULL, /* no poll */
1235 NULL, /* no socket */
1236 NULL, /* no connect */
1237 NULL, /* no send */
1238 NULL, /* no recv */
1239 NULL, /* no bind */
1240 NULL, /* no listen */
1241 NULL /* no accept */
1242 # endif
1246 #endif /* PIO_OS_UNIX */
1250 =back
1252 =head1 SEE ALSO
1254 F<src/io/io_buf.c>,
1255 F<src/io/io_passdown.c>,
1256 F<src/io/io_stdio.c>,
1257 F<src/io/io_unix.c>,
1258 F<src/io/io_win32.c>,
1259 F<src/io/io.c>,
1260 F<src/io/io_private.h>.
1262 =head1 HISTORY
1264 Initially written by Melvin Smith (mrjoltcola@mindspring.com).
1266 =cut
1272 * Local variables:
1273 * c-file-style: "parrot"
1274 * End:
1275 * vim: expandtab shiftwidth=4: