[svn:parrot] r37705 - in trunk: compilers/pct/src/PCT compilers/pge config/gen/makefiles examples/io include/parrot src/io src/ops src/pmc t/pmc

jonathan at svn.parrot.org jonathan at svn.parrot.org
Wed Mar 25 12:14:08 UTC 2009


Author: jonathan
Date: Wed Mar 25 12:14:06 2009
New Revision: 37705
URL: https://trac.parrot.org/parrot/changeset/37705

Log:
[io] Apply patch from bacek++ to bring socket IO back to Parrot. Seems to largely match up with the I/O PDD, and no tests fail as a result (plus the test it adds passes). This patch also contains my naiive port of the code to Win32, which actually just about runs httpd.pir (an example included in bacek++'s patch), though with a curious browser hang once the complete page has been served.  Patch was from TT#496.

Added:
   trunk/examples/io/
   trunk/examples/io/httpd.pir   (contents, props changed)
   trunk/src/pmc/sockaddr.pmc   (contents, props changed)
   trunk/src/pmc/socket.pmc   (contents, props changed)
   trunk/t/pmc/sockaddr.t   (contents, props changed)
Modified:
   trunk/compilers/pct/src/PCT/Node.pir
   trunk/compilers/pge/demo.pir
   trunk/config/gen/makefiles/root.in
   trunk/include/parrot/io.h
   trunk/include/parrot/io_unix.h
   trunk/include/parrot/io_win32.h
   trunk/src/io/socket_api.c
   trunk/src/io/socket_unix.c
   trunk/src/io/socket_win32.c
   trunk/src/ops/io.ops
   trunk/src/ops/ops.num

Modified: trunk/compilers/pct/src/PCT/Node.pir
==============================================================================
--- trunk/compilers/pct/src/PCT/Node.pir	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/compilers/pct/src/PCT/Node.pir	Wed Mar 25 12:14:06 2009	(r37705)
@@ -295,6 +295,17 @@
 .end
 
 
+=item VTABLE get_number()
+
+Number of elements in this node.
+
+=cut
+
+.sub '' :vtable('get_number') :method
+    $I0 = elements self
+    .return ($I0)
+.end
+
 =back
 
 =head1 AUTHOR

Modified: trunk/compilers/pge/demo.pir
==============================================================================
--- trunk/compilers/pge/demo.pir	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/compilers/pge/demo.pir	Wed Mar 25 12:14:06 2009	(r37705)
@@ -55,7 +55,7 @@
   match_result:
     unless match goto match_fail
     print "match succeeded\n"
-    $P0 = find_global "_dumper"
+    $P0 = get_global "_dumper"
     $P0(match, "$/")
     goto read_loop
   match_fail:
@@ -87,7 +87,7 @@
   save_rule:
     if_null rulesub, match_nopattern
     x = substr x, 5
-    store_global x, rulesub
+    set_global x, rulesub
     print "Saved as "
     print x
     print "\n"
@@ -101,7 +101,7 @@
 
   print_exp:
     if_null rulesub, match_nopattern
-    $P0 = find_global "_dumper"
+    $P0 = get_global "_dumper"
     $P0(exp, "exp")
     goto read_loop
 

Modified: trunk/config/gen/makefiles/root.in
==============================================================================
--- trunk/config/gen/makefiles/root.in	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/config/gen/makefiles/root.in	Wed Mar 25 12:14:06 2009	(r37705)
@@ -362,7 +362,10 @@
     $(IO_DIR)/unix$(O) \
     $(IO_DIR)/win32$(O) \
     $(IO_DIR)/portable$(O) \
-    $(IO_DIR)/filehandle$(O)
+    $(IO_DIR)/filehandle$(O) \
+    $(IO_DIR)/socket_api$(O) \
+    $(IO_DIR)/socket_unix$(O) \
+    $(IO_DIR)/socket_win32$(O)
 
 INTERP_O_FILES := \
     $(SRC_DIR)/string/api$(O) \

Added: trunk/examples/io/httpd.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/examples/io/httpd.pir	Wed Mar 25 12:14:06 2009	(r37705)
@@ -0,0 +1,426 @@
+# Copyright (C) 2006-2008, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+examples/io/httpd.pir - HTTP server
+
+=head1 SYNOPSIS
+
+  $ ./parrot examples/io/httpd.pir
+
+=head1 DESCRIPTION
+
+A very tiny HTTP-Server. It currently only understands the GET method.
+It's a nice way of testing pretty much all IO functions.
+By default (and not yet configurable) it binds to localhost:1234.
+
+=head2 Serving Parrot Docs
+
+If no filename is given it serves the HTML documentation
+in ./docs/html. Make sure you have built them with
+
+  $ make html
+
+After that you can browse the documentation with
+
+  http://localhost:1234
+
+which redirects to
+
+  http://localhost:1234/docs/html/index.html
+
+=head2 Serving Other HTML Files
+
+If a html file is present in the request, this file will be served:
+
+  http://localhost:1234/index.html
+
+This will sent F<./index.html> from the directory, where F<httpd.pir>
+was started.
+
+=head2 CGI
+
+If the file extension is C<.pir> or C<.pbc>, this file will be loaded
+below the directory F<cgi-pir> and the function C<cgi_main> will be
+invoked with the query as an argument.
+This functions should return a plain string, which will be sent to the
+browser.
+
+F<cgi_main> is called with 3 arguments: a todo/reserved PMC, a string
+with the original query and a Hash, with C<key=value> items split by
+C<'+'>. C<key> and C<value> are already C<urldecoded>.
+
+  $ cat cgi-pir/foo.pir
+  .sub cgi_main
+    .param pmc reserved         # TODO
+    .param string query		# all after '?':  "foo=1+bar=A"
+    .param pmc query_hash       # Hash { foo=>'1', bar=>'A' }
+    .return ("<p>foo</p>")      # in practice use a full <html>doc</html>
+                                # unless serving XMLHttpRequest's
+  .end
+
+The browser request:
+
+  http://localhost:1234/foo.pir?foo=1+bar=%61
+
+will serve, whatever the C<cgi_main> function returned.
+
+=head1 TODO
+
+make it work on W32/IE
+
+Transcode the received string to ascii, in order to have access to an
+implemented 'index' op. Or just use unicode instead.
+
+=head1 SEE ALSO
+
+RFC2616
+
+=head1 AUTHOR
+
+Original author is Markus Amsler - <markus.amsler at oribi.org>
+The code was heavily hacked by bernhard and leo.
+
+=cut
+
+.const string CRLF     = "\r\n"
+.const string CRLFCRLF = "\r\n\r\n"
+.const string LFLF     = "\n\n"
+.const string CRCR     = "\r\r"
+
+.const string SERVER_NAME = "Parrot-httpd/0.1"
+
+.include "stat.pasm"
+
+.sub main :main
+    .local pmc sock, work, fp
+    .local pmc fp               # read requested files from disk
+    .local int port
+    .local pmc address
+    .local string host
+    .local string buf, req, rep, temp
+    .local string meth, url, file_content
+    .local int ret
+    .local int len, pos, occ1, occ2, dotdot
+
+    .local string doc_root
+    doc_root = "."
+    host = "localhost"
+    port = 1234
+
+    # TODO provide sys/socket constants
+    socket sock, 2, 1, 6	# PF_INET, SOCK_STREAM, tcp
+    unless sock goto ERR_NO_SOCKET
+
+    # Pack a sockaddr_in structure with IP and port
+    address = sockaddr host, port
+    ret = bind sock, address
+    if ret == -1 goto ERR_bind
+    $S0 = port
+    print "Running webserver on port "
+    print $S0
+    print " of "
+    print host
+    print ".\n"
+    print "The Parrot documentation can now be accessed at http://"
+    print host
+    print ":"
+    print $S0
+    print "\n"
+    print "Be sure that the HTML docs have been generated with 'make html'.\n"
+
+    listen ret, sock, 1
+NEXT:
+    accept work, sock
+    req = ""
+MORE:
+    recv ret, work, buf
+    # charset I0, buf
+    # charsetname S1, I0
+    # print "\nret: "
+    # print ret
+    # print "\ncharset of buf: "
+    # print S1
+    # print "\nbuf:"
+    # print buf
+    # print "\nafter buf"
+
+    if ret <= 0 goto SERVE_REQ
+    concat req, buf
+    index pos, req, CRLFCRLF
+    # print "\npos1:"
+    # print pos
+    if pos >= 0 goto SERVE_REQ
+    index pos, req, LFLF
+    # print "\npos2:"
+    # print pos
+    if pos >= 0 goto SERVE_REQ
+    index pos, req, CRCR
+    # print "\npos3:"
+    # print pos
+    if pos >= 0 goto SERVE_REQ
+    goto MORE
+
+SERVE_REQ:
+#    print "Request:\n"
+#    print req
+#    print "*******\n"
+
+# parse
+# GET the_file HTTP*
+    index occ1, req, " "
+    substr meth, req, 0, occ1
+    inc occ1
+    index occ2, req, " ", occ1
+    len = occ2 - occ1
+    substr url, req, occ1, len
+
+    if meth == "GET" goto SERVE_GET
+
+    print "unknown method:'"
+    print meth
+    print "'\n"
+    close work
+    goto NEXT
+
+SERVE_GET:
+    .local int is_cgi
+    (is_cgi, file_content, len) = check_cgi(url)
+    if is_cgi goto SERVE_blob
+
+    # decode the url
+    url = urldecode(url)
+
+    # Security: Don't allow access to the parent dir
+    index dotdot, url, ".."
+    if dotdot >= 0 goto SERVE_404
+
+    # redirect instead of serving index.html
+    if url == "/" goto SERVE_docroot
+
+    # Those little pics in the URL field or in tabs
+    if url == "/favicon.ico" goto SERVE_favicon
+
+    # try to serve a file
+    goto SERVE_file
+
+SERVE_file:
+    # try to open the file in url
+    concat url, doc_root, url
+    fp = open url, 'r'
+    unless fp goto SERVE_404
+    len = stat url, .STAT_FILESIZE
+    read file_content, fp, len
+
+SERVE_blob:
+    # TODO make more subs
+    # takes: file_content, len
+    rep = "HTTP/1.1 200 OK"
+    rep .= CRLF
+    rep .= "Server: "
+    rep .= SERVER_NAME
+    rep .= CRLF
+    rep .= "Content-Length: "
+    temp = to_string (len)
+    rep .= temp
+    rep .= CRLFCRLF
+    rep .= file_content
+    send ret, work, rep
+    # TODO provide a log method
+    print "served file '"
+    print url
+    print "'\n"
+    close work
+    goto NEXT
+
+SERVE_docroot:
+    rep = 'HTTP/1.1 301 Moved Permamently'
+    rep .= CRLF
+    rep .= "Server: "
+    rep .= SERVER_NAME
+    rep .= CRLF
+    rep .= 'Location: /docs/html/index.html'
+    rep .= CRLF
+    rep .= 'Content-Length: '
+    file_content = "Please go to <a href='docs/html/index.html'>Parrot Documentation</a>."
+    length len, file_content
+    temp = to_string (len)
+    concat rep, temp
+    concat rep, CRLFCRLF
+    concat rep, file_content
+    send ret, work, rep
+    print "Redirect to 'docs/html/index.html'\n"
+    close work
+    goto NEXT
+
+SERVE_favicon:
+    url = urldecode( '/docs/resources/favicon.ico')
+    goto SERVE_file
+
+SERVE_404:
+    $S0 = '404 Not found'
+    $I0 = length $S0
+    rep = 'HTTP/1.1 404 Not Found'
+    rep .= CRLF
+    rep .= "Server: "
+    rep .= SERVER_NAME
+    rep .= CRLF
+    rep .= 'Content-Length: '
+    $S1 = $I0
+    rep .= $S1
+    rep .= CRLF
+    rep .= 'Content-Type: text/plain'
+    rep .= CRLFCRLF
+    rep .= $S0
+    print "File not found: '"
+    print url
+    print "'\n"
+    send ret, work, rep
+    goto NEXT
+
+ERR_NO_SOCKET:
+    print "Could not open socket.\n"
+    print "Did you enable PARROT_NET_DEVEL in include/io_private.h?\n"
+    end
+ERR_bind:
+    print "bind failed\n"
+    # fall through
+END:
+    close sock
+    end
+.end
+
+.sub to_string
+    .param pmc args :slurpy
+
+    .local string ret
+    ret = sprintf "%d", args
+    .return( ret )
+.end
+
+# convert %xx to char
+.sub urldecode
+    .param string in
+
+    .local string out, char_in, char_out
+    .local int    c_out, pos_in, len
+    .local string hex
+
+    len = length in
+    pos_in = 0
+    out = ""
+START:
+    if pos_in >= len goto END
+    substr char_in, in, pos_in, 1
+    char_out = char_in
+    if char_in != "%" goto INC_IN
+    # OK this was a escape character, next two are hexadecimal
+    inc pos_in
+    substr hex, in, pos_in, 2
+    c_out = hex_to_int (hex)
+    chr char_out, c_out
+    inc pos_in
+
+INC_IN:
+    concat out, char_out
+    inc pos_in
+    goto START
+END:
+   .return( out )
+.end
+
+.sub hex_to_int
+    .param pmc hex
+    .tailcall hex.'to_int'(16)
+.end
+
+# if file is *.pir or *.pbc run it as CGI
+.sub check_cgi
+    .param string url
+    $I0 = index url, ".pir"
+    if $I0 > 0 goto cgi_1
+    $I0 = index url, ".pbc"
+    if $I0 > 0 goto cgi_1
+    .return (0, '', 0)
+cgi_1:
+    # file.pir?foo=1+bar=2
+    $I0 = index url, '?'
+    if $I0 == -1 goto no_query
+    .local string file, query
+    .local pmc query_hash
+    file = substr url, 0, $I0
+    inc $I0
+    query = substr url, $I0
+    # TODO split into a hash, then decode parts
+    query_hash = make_query_hash(query)
+    query = urldecode(query)
+    goto have_query
+no_query:
+    file = url
+    query = ''
+    query_hash = new 'Hash'
+have_query:
+    # escape %
+    file = urldecode(file)
+
+    # Security: Don't allow access to the parent dir
+    .local int dotdot
+    index dotdot, file, ".."
+    if dotdot < 0 goto cgi_file
+    .return (0, '', 0)
+
+cgi_file:
+    print "CGI: '"
+    print file
+    print "' Q: '"
+    print query
+    print "'\n"
+    file = "cgi-pir/" . file
+    # TODO stat the file
+    load_bytecode file
+    .local string result
+    null $P0	# not yet
+    # TODO catch ex
+    result = 'cgi_main'($P0, query, query_hash)
+    $I0 = length result
+    .return (1, result, $I0)
+.end
+
+# split query at '+', make hash from foo=bar items
+.sub make_query_hash
+    .param string query		# the unescapced one
+    .local pmc query_hash, items
+    .local string kv, k, v
+    query_hash = new 'Hash'
+    items = split '+', query
+    .local int i, n
+    i = 0
+    n = elements items
+lp_items:
+    kv = items[i]
+    $I0 = index kv, "="
+    if $I0 == -1 goto no_val
+    k = substr kv, 0, $I0
+    inc $I0
+    v = substr kv, $I0
+    v = urldecode(v)
+    goto set_val
+no_val:
+    k = kv
+    v = 1
+set_val:
+    k = urldecode(k)
+    query_hash[k] = v
+
+next_item:
+    inc i
+    if i < n goto lp_items
+    .return (query_hash)
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Modified: trunk/include/parrot/io.h
==============================================================================
--- trunk/include/parrot/io.h	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/include/parrot/io.h	Wed Mar 25 12:14:06 2009	(r37705)
@@ -757,6 +757,122 @@
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/io/filehandle.c */
 
+/* HEADERIZER BEGIN: src/io/socket_api.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+PMC * Parrot_io_accept(PARROT_INTERP, ARGMOD(PMC *pmc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+PARROT_EXPORT
+INTVAL Parrot_io_bind(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pmc)
+        FUNC_MODIFIES(*address);
+
+PARROT_EXPORT
+INTVAL Parrot_io_connect(PARROT_INTERP,
+    ARGMOD(PMC *pmc),
+    ARGMOD(PMC *address))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pmc)
+        FUNC_MODIFIES(*address);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+INTVAL Parrot_io_listen(PARROT_INTERP, ARGMOD(PMC *pmc), INTVAL backlog)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+PMC * Parrot_io_new_socket_pmc(PARROT_INTERP, INTVAL flags)
+        __attribute__nonnull__(1);
+
+PARROT_EXPORT
+INTVAL Parrot_io_poll(PARROT_INTERP,
+    ARGMOD(PMC *pmc),
+    INTVAL which,
+    INTVAL sec,
+    INTVAL usec)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+PARROT_EXPORT
+INTVAL Parrot_io_recv(PARROT_INTERP, ARGMOD(PMC *pmc), ARGOUT(STRING **buf))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pmc)
+        FUNC_MODIFIES(*buf);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+INTVAL Parrot_io_send(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(STRING *buf))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pmc)
+        FUNC_MODIFIES(*buf);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+PMC * Parrot_io_socket(PARROT_INTERP, INTVAL fam, INTVAL type, INTVAL proto)
+        __attribute__nonnull__(1);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+INTVAL Parrot_io_socket_is_closed(ARGMOD(PMC *socket))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*socket);
+
+#define ASSERT_ARGS_Parrot_io_accept __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc)
+#define ASSERT_ARGS_Parrot_io_bind __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc) \
+    || PARROT_ASSERT_ARG(address)
+#define ASSERT_ARGS_Parrot_io_connect __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc) \
+    || PARROT_ASSERT_ARG(address)
+#define ASSERT_ARGS_Parrot_io_listen __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc)
+#define ASSERT_ARGS_Parrot_io_new_socket_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp)
+#define ASSERT_ARGS_Parrot_io_poll __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc)
+#define ASSERT_ARGS_Parrot_io_recv __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc) \
+    || PARROT_ASSERT_ARG(buf)
+#define ASSERT_ARGS_Parrot_io_send __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(pmc) \
+    || PARROT_ASSERT_ARG(buf)
+#define ASSERT_ARGS_Parrot_io_socket __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp)
+#define ASSERT_ARGS_Parrot_io_socket_is_closed __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(socket)
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/io/socket_api.c */
+
 /* Put platform specific macros here if you must */
 #ifdef PIO_OS_WIN32
 extern STRING          *PIO_sockaddr_in(PARROT_INTERP, unsigned short, STRING *);

Modified: trunk/include/parrot/io_unix.h
==============================================================================
--- trunk/include/parrot/io_unix.h	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/include/parrot/io_unix.h	Wed Mar 25 12:14:06 2009	(r37705)
@@ -155,6 +155,106 @@
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/io/unix.c */
 
+
+/* HEADERIZER BEGIN: src/io/socket_unix.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+PMC * Parrot_io_accept_unix(PARROT_INTERP, ARGMOD(PMC *socket))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*socket);
+
+INTVAL Parrot_io_bind_unix(PARROT_INTERP,
+    ARGMOD(PMC *socket),
+    ARGMOD(PMC *sockaddr))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*socket)
+        FUNC_MODIFIES(*sockaddr);
+
+INTVAL Parrot_io_connect_unix(PARROT_INTERP,
+    ARGMOD(PMC *socket),
+    ARGIN(PMC *r))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*socket);
+
+INTVAL Parrot_io_listen_unix(SHIM_INTERP, ARGMOD(PMC *socket), INTVAL sec)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*socket);
+
+INTVAL Parrot_io_poll_unix(SHIM_INTERP,
+    ARGMOD(PMC *socket),
+    int which,
+    int sec,
+    int usec)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*socket);
+
+INTVAL Parrot_io_recv_unix(PARROT_INTERP,
+    ARGMOD(PMC *socket),
+    ARGOUT(STRING **s))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*socket)
+        FUNC_MODIFIES(*s);
+
+INTVAL Parrot_io_send_unix(SHIM_INTERP,
+    ARGMOD(PMC *socket),
+    ARGMOD(STRING *s))
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*socket)
+        FUNC_MODIFIES(*s);
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+PMC * Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+PMC * Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto)
+        __attribute__nonnull__(1);
+
+#define ASSERT_ARGS_Parrot_io_accept_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(socket)
+#define ASSERT_ARGS_Parrot_io_bind_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(socket) \
+    || PARROT_ASSERT_ARG(sockaddr)
+#define ASSERT_ARGS_Parrot_io_connect_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(socket) \
+    || PARROT_ASSERT_ARG(r)
+#define ASSERT_ARGS_Parrot_io_listen_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(socket)
+#define ASSERT_ARGS_Parrot_io_poll_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(socket)
+#define ASSERT_ARGS_Parrot_io_recv_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(socket) \
+    || PARROT_ASSERT_ARG(s)
+#define ASSERT_ARGS_Parrot_io_send_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(socket) \
+    || PARROT_ASSERT_ARG(s)
+#define ASSERT_ARGS_Parrot_io_sockaddr_in __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(addr)
+#define ASSERT_ARGS_Parrot_io_socket_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp)
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/io/socket_unix.c */
+
+
+
 #define PIO_INIT(interp) Parrot_io_init_unix((interp))
 #define PIO_OPEN(interp, pmc, file, flags) \
     Parrot_io_open_unix((interp), (pmc), (file), (flags))
@@ -173,6 +273,23 @@
 #define PIO_FLUSH(interp, pmc) Parrot_io_flush_unix((interp), (pmc))
 #define PIO_GETBLKSIZE(handle) Parrot_io_getblksize_unix((handle))
 
+#define PIO_POLL(interp, pmc, which, sec, usec) \
+    Parrot_io_poll_unix((interp), (pmc), (which), (sec), (usec))
+#define PIO_NEW_SOCKET(interp, fam, type, proto) \
+    Parrot_io_socket_unix((interp), (fam), (type), (proto))
+#define PIO_RECV(interp, pmc, buf) \
+    Parrot_io_recv_unix((interp), (pmc), (buf))
+#define PIO_SEND(interp, pmc, buf) \
+    Parrot_io_send_unix((interp), (pmc), (buf))
+#define PIO_CONNECT(interp, pmc, address) \
+    Parrot_io_connect_unix((interp), (pmc), (address))
+#define PIO_BIND(interp, pmc, address) \
+    Parrot_io_bind_unix((interp), (pmc), (address))
+#define PIO_LISTEN(interp, pmc, backlog) \
+    Parrot_io_listen_unix((interp), (pmc), (backlog))
+#define PIO_ACCEPT(interp, pmc) \
+    Parrot_io_accept_unix((interp), (pmc))
+
 #endif /* PARROT_IO_UNIX_H_GUARD */
 
 /*

Modified: trunk/include/parrot/io_win32.h
==============================================================================
--- trunk/include/parrot/io_win32.h	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/include/parrot/io_win32.h	Wed Mar 25 12:14:06 2009	(r37705)
@@ -154,6 +154,23 @@
 #define PIO_FLUSH(interp, pmc) Parrot_io_flush_win32((interp), (pmc))
 #define PIO_GETBLKSIZE(handle) Parrot_io_getblksize_win32((handle))
 
+#define PIO_POLL(interp, pmc, which, sec, usec) \
+    Parrot_io_poll_win32((interp), (pmc), (which), (sec), (usec))
+#define PIO_NEW_SOCKET(interp, fam, type, proto) \
+    Parrot_io_socket_win32((interp), (fam), (type), (proto))
+#define PIO_RECV(interp, pmc, buf) \
+    Parrot_io_recv_win32((interp), (pmc), (buf))
+#define PIO_SEND(interp, pmc, buf) \
+    Parrot_io_send_win32((interp), (pmc), (buf))
+#define PIO_CONNECT(interp, pmc, address) \
+    Parrot_io_connect_win32((interp), (pmc), (address))
+#define PIO_BIND(interp, pmc, address) \
+    Parrot_io_bind_win32((interp), (pmc), (address))
+#define PIO_LISTEN(interp, pmc, backlog) \
+    Parrot_io_listen_win32((interp), (pmc), (backlog))
+#define PIO_ACCEPT(interp, pmc) \
+    Parrot_io_accept_win32((interp), (pmc))
+
 #endif /* PARROT_IO_WIN32_H_GUARD */
 
 /*

Modified: trunk/src/io/socket_api.c
==============================================================================
--- trunk/src/io/socket_api.c	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/src/io/socket_api.c	Wed Mar 25 12:14:06 2009	(r37705)
@@ -20,7 +20,7 @@
 
 #include "parrot/parrot.h"
 #include "io_private.h"
-#include "io.str"
+#include "api.str"
 
 #include <stdarg.h>
 
@@ -32,6 +32,27 @@
 
 
 =over 4
+*/
+
+
+/*
+
+=item C<INTVAL Parrot_io_socket_is_closed>
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+INTVAL
+Parrot_io_socket_is_closed(ARGMOD(PMC *socket))
+{
+    return 0;
+}
+
+/*
 
 =item C<INTVAL Parrot_io_poll>
 
@@ -71,8 +92,7 @@
 PMC *
 Parrot_io_socket(PARROT_INTERP, INTVAL fam, INTVAL type, INTVAL proto)
 {
-    ParrotIOLayer * const l = interp->piodata->default_stack;
-    return PIO_NEW_SOCKET(interp, l, fam, type, proto);
+    return PIO_NEW_SOCKET(interp, fam, type, proto);
 }
 
 /*
@@ -130,7 +150,7 @@
 
 PARROT_EXPORT
 INTVAL
-Parrot_io_connect(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(STRING *address))
+Parrot_io_connect(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
 {
     if (Parrot_io_socket_is_closed(pmc))
         return -1;
@@ -151,12 +171,12 @@
 
 PARROT_EXPORT
 INTVAL
-Parrot_io_bind(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(STRING *address))
+Parrot_io_bind(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
 {
     if (Parrot_io_socket_is_closed(pmc))
         return -1;
 
-    return PIO_BIND(interp, address);
+    return PIO_BIND(interp, pmc, address);
 }
 
 /*
@@ -199,13 +219,37 @@
 {
 
     if (Parrot_io_socket_is_closed(pmc))
-        return -1;
+        return PMCNULL;
 
-    return PIO_ACCEPT(interp, l, io);
+    return PIO_ACCEPT(interp, pmc);
 }
 
 /*
 
+=item C<PMC * Parrot_io_new_socket_pmc>
+
+Creates a new I/O socket object. The value of C<flags> is set
+in the returned PMC.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+PMC *
+Parrot_io_new_socket_pmc(PARROT_INTERP, INTVAL flags)
+{
+    ASSERT_ARGS(Parrot_io_new_socket_pmc)
+    PMC * const new_io = pmc_new(interp, enum_class_Socket);
+
+    Parrot_io_set_flags(interp, new_io, flags);
+
+    return new_io;
+}
+/*
+
 =back
 
 =head1 SEE ALSO

Modified: trunk/src/io/socket_unix.c
==============================================================================
--- trunk/src/io/socket_unix.c	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/src/io/socket_unix.c	Wed Mar 25 12:14:06 2009	(r37705)
@@ -30,18 +30,38 @@
 
 #include "parrot/parrot.h"
 #include "io_private.h"
+#include "../pmc/pmc_socket.h"
 
 #ifdef PIO_OS_UNIX
 
+#include <sys/socket.h>
+
 /* HEADERIZER HFILE: include/parrot/io_unix.h */
 
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
+static void get_sockaddr_in(PARROT_INTERP,
+    ARGIN(PMC * sockaddr),
+    ARGIN(const char* host),
+    int port)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3);
+
+#define ASSERT_ARGS_get_sockaddr_in __attribute__unused__ int _ASSERT_ARGS_CHECK = \
+       PARROT_ASSERT_ARG(interp) \
+    || PARROT_ASSERT_ARG(sockaddr) \
+    || PARROT_ASSERT_ARG(host)
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: static */
 
 /*
+static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr),
+    ARGIN(const char* host), ARGIN(int port));
+*/
+
+/*
 
 =back
 
@@ -56,7 +76,7 @@
 
 =over 4
 
-=item C<STRING * Parrot_io_sockaddr_in>
+=item C<PMC * Parrot_io_sockaddr_in>
 
 C<Parrot_io_sockaddr_in()> is not part of the layer and so must be C<extern>.
 
@@ -67,50 +87,23 @@
 
 */
 
+/* Helper macros to get sockaddr_in */
+#define SOCKADDR(p, t) ((struct sockaddr_in*)VTABLE_get_pointer(interp, PARROT_SOCKET((p))->t))
+
+
 PARROT_WARN_UNUSED_RESULT
 PARROT_CANNOT_RETURN_NULL
-STRING *
-Parrot_io_sockaddr_in(PARROT_INTERP, unsigned short port, ARGIN(STRING *addr))
+PMC *
+Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port)
 {
-    struct sockaddr_in sa;
-    /* Hard coded to IPv4 for now */
-    const int family = AF_INET;
+    PMC * sockaddr;
+    char * s;
 
-    char * const s = Parrot_str_to_cstring(interp, addr);
-    /*
-     * due to a bug in OS/X, we've to zero the struct
-     * else bind is failing erratically
-     */
-    memset(&sa, 0, sizeof (sa));
-#  ifdef PARROT_DEF_INET_ATON
-    if (inet_aton(s, &sa.sin_addr) != 0) {
-#  else
-    /* positive retval is success */
-    if (inet_pton(family, s, &sa.sin_addr) > 0) {
-#  endif
-        /* Success converting numeric IP */
-    }
-    else {
-        /* Maybe it is a hostname, try to lookup */
-        /* XXX Check PIO option before doing a name lookup,
-         * it may have been toggled off.
-         */
-        struct hostent *he = gethostbyname(s);
-        /* XXX FIXME - Handle error condition better */
-        if (!he) {
-            fprintf(stderr, "gethostbyname failure [%s]\n", s);
-            Parrot_str_free_cstring(s);
-            return NULL;
-        }
-        memcpy((char*)&sa.sin_addr, he->h_addr, sizeof (sa.sin_addr));
-    }
-    Parrot_str_free_cstring(s);
-
-    sa.sin_family = family;
-    sa.sin_port = htons(port);
-
-    return string_make(interp, (char *)&sa, sizeof (struct sockaddr_in),
-            "binary", 0);
+    s = Parrot_str_to_cstring(interp, addr);
+    sockaddr = pmc_new(interp, enum_class_Sockaddr);
+    get_sockaddr_in(interp, sockaddr, s, port);
+    free(s);
+    return sockaddr;
 }
 
 
@@ -130,18 +123,18 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 PMC *
-Parrot_io_socket_unix(PARROT_INTERP, ARGMOD(PMC *socket), int fam, int type, int proto)
+Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto)
 {
+    int i;
     const int sock = socket(fam, type, proto);
     if (sock >= 0) {
-        ParrotIO * const io = Parrot_io_new(interp, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
-        Parrot_io_set_os_handle(interp, socket, sock);
-        memset(&io->local, 0, sizeof (struct sockaddr_in));
-        memset(&io->remote, 0, sizeof (struct sockaddr_in));
-        io->remote.sin_family = fam;
+        PMC * io = Parrot_io_new_socket_pmc(interp, PIO_F_SOCKET|PIO_F_READ|PIO_F_WRITE);
+        PARROT_SOCKET(io)->os_handle = sock;
+        setsockopt(PARROT_SOCKET(io)->os_handle, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+        SOCKADDR(io, remote)->sin_family = fam;
         return io;
     }
-    return NULL;
+    return PMCNULL;
 }
 
 /*
@@ -155,16 +148,17 @@
 */
 
 INTVAL
-Parrot_io_connect_unix(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io),
-        ARGIN_NULLOK(STRING *r))
+Parrot_io_connect_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGIN(PMC *r))
 {
-    struct sockaddr_in * saddr = &io->remote;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+
+    if(!r)
+        return -1;
 
-    if (r)
-        memcpy(&io->remote, PObj_bufstart(r), sizeof (struct sockaddr_in));
+    PARROT_SOCKET(socket)->remote = r;
 
 AGAIN:
-    if ((connect(io->fd, (struct sockaddr *)saddr,
+    if ((connect(io->os_handle, (struct sockaddr *)SOCKADDR(socket, remote),
             sizeof (struct sockaddr_in))) != 0) {
         switch (errno) {
             case EINTR:
@@ -192,17 +186,19 @@
 */
 
 INTVAL
-Parrot_io_bind_unix(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io),
-        ARGMOD(STRING *l))
+Parrot_io_bind_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGMOD(PMC *sockaddr))
 {
-    struct sockaddr_in * saddr = &io->local;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    struct sockaddr_in * saddr;
 
-    if (!l)
+    if (!sockaddr)
         return -1;
 
-    memcpy(&io->local, PObj_bufstart(l), sizeof (struct sockaddr_in));
+    PARROT_SOCKET(socket)->local = sockaddr;
+
+    saddr = SOCKADDR(socket, local);
 
-    if ((bind(io->fd, (struct sockaddr *) saddr,
+    if ((bind(io->os_handle, (struct sockaddr *) saddr,
             sizeof (struct sockaddr_in))) == -1) {
         return -1;
     }
@@ -222,10 +218,10 @@
 */
 
 INTVAL
-Parrot_io_listen_unix(SHIM_INTERP, SHIM(PMC *socket), ARGIN(ParrotIO *io),
-        INTVAL sec)
+Parrot_io_listen_unix(SHIM_INTERP, ARGMOD(PMC *socket), INTVAL sec)
 {
-    if ((listen(io->fd, sec)) == -1) {
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    if ((listen(io->os_handle, sec)) == -1) {
         return -1;
     }
     return 0;
@@ -233,7 +229,7 @@
 
 /*
 
-=item C<ParrotIO * Parrot_io_accept_unix>
+=item C<PMC * Parrot_io_accept_unix>
 
 Accept a new connection and return a newly created C<ParrotIO> socket.
 
@@ -244,21 +240,26 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 PMC *
-Parrot_io_accept_unix(PARROT_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io))
+Parrot_io_accept_unix(PARROT_INTERP, ARGMOD(PMC *socket))
 {
-    ParrotIO * const    newio   = Parrot_io_new(interp, PIO_F_SOCKET, 0,
-                                    PIO_F_READ|PIO_F_WRITE);
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    PMC * newio   = Parrot_io_new_socket_pmc(interp,
+            PIO_F_SOCKET | PIO_F_READ|PIO_F_WRITE);
     Parrot_Socklen_t    addrlen = sizeof (struct sockaddr_in);
-    struct sockaddr_in *saddr   = &newio->remote;
-    const int           newsock = accept(io->fd, (struct sockaddr *)saddr,
-                                    &addrlen);
+    struct sockaddr_in *saddr;
+
+    PARROT_SOCKET(newio)->local  = PARROT_SOCKET(socket)->local;
+    PARROT_SOCKET(newio)->remote = pmc_new(interp, enum_class_Sockaddr);
+    saddr                        = SOCKADDR(newio, remote);
+
+    const int           newsock = accept(io->os_handle,
+           (struct sockaddr *)saddr, &addrlen);
 
     if (newsock == -1) {
-        mem_sys_free(newio);
-        return NULL;
+        return PMCNULL;
     }
 
-    newio->fd = newsock;
+    PARROT_SOCKET(newio)->os_handle = newsock;
 
     /* XXX FIXME: Need to do a getsockname and getpeername here to
      * fill in the sockaddr_in structs for local and peer */
@@ -280,10 +281,10 @@
 */
 
 INTVAL
-Parrot_io_send_unix(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io),
-        ARGMOD(STRING *s))
+Parrot_io_send_unix(SHIM_INTERP, ARGMOD(PMC *socket), ARGMOD(STRING *s))
 {
     int error, bytes, byteswrote;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
 
     bytes = s->bufused;
     byteswrote = 0;
@@ -291,7 +292,7 @@
     /*
      * Ignore encoding issues for now.
      */
-    if ((error = send(io->fd, (char *)s->strstart + byteswrote,
+    if ((error = send(io->os_handle, (char *)s->strstart + byteswrote,
                     bytes, 0)) >= 0) {
         byteswrote += error;
         bytes -= error;
@@ -313,7 +314,7 @@
 #    endif
             case EPIPE:
                 /* XXX why close it here and not below */
-                close(io->fd);
+                close(io->os_handle);
                 return -1;
             default:
                 return -1;
@@ -332,15 +333,15 @@
 */
 
 INTVAL
-Parrot_io_recv_unix(PARROT_INTERP, SHIM(PMC *socket),
-        ARGMOD(ParrotIO *io), ARGOUT(STRING **s))
+Parrot_io_recv_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGOUT(STRING **s))
 {
     int error;
     unsigned int bytesread = 0;
     char buf[2048];
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
 
 AGAIN:
-    if ((error = recv(io->fd, buf, 2048, 0)) >= 0) {
+    if ((error = recv(io->os_handle, buf, 2048, 0)) >= 0) {
         bytesread += error;
         /* The charset should probably be 'binary', but right now httpd.pir
          * only works with 'ascii'
@@ -361,11 +362,11 @@
 #    endif
             case ECONNRESET:
                 /* XXX why close it on err return result is -1 anyway */
-                close(io->fd);
+                close(io->os_handle);
                 *s = Parrot_str_new_noinit(interp, enum_stringrep_one, 0);
                 return -1;
             default:
-                close(io->fd);
+                close(io->os_handle);
                 *s = Parrot_str_new_noinit(interp, enum_stringrep_one, 0);
                 return -1;
         }
@@ -393,25 +394,26 @@
 */
 
 INTVAL
-Parrot_io_poll_unix(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io), int which,
-               int sec, int usec)
+Parrot_io_poll_unix(SHIM_INTERP, ARGMOD(PMC *socket), int which, int sec,
+    int usec)
 {
     int n;
     fd_set r, w, e;
     struct timeval t;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
 
     t.tv_sec = sec;
     t.tv_usec = usec;
     FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
     /* These should be defined in header */
-    if (which & 1) FD_SET(io->fd, &r);
-    if (which & 2) FD_SET(io->fd, &w);
-    if (which & 4) FD_SET(io->fd, &e);
+    if (which & 1) FD_SET(io->os_handle, &r);
+    if (which & 2) FD_SET(io->os_handle, &w);
+    if (which & 4) FD_SET(io->os_handle, &e);
 AGAIN:
-    if ((select(io->fd+1, &r, &w, &e, &t)) >= 0) {
-        n = (FD_ISSET(io->fd, &r) ? 1 : 0);
-        n |= (FD_ISSET(io->fd, &w) ? 2 : 0);
-        n |= (FD_ISSET(io->fd, &e) ? 4 : 0);
+    if ((select(io->os_handle+1, &r, &w, &e, &t)) >= 0) {
+        n = (FD_ISSET(io->os_handle, &r) ? 1 : 0);
+        n |= (FD_ISSET(io->os_handle, &w) ? 2 : 0);
+        n |= (FD_ISSET(io->os_handle, &e) ? 4 : 0);
         return n;
     }
     else {
@@ -422,105 +424,41 @@
     }
 }
 
-#  endif
-/*
-
-=item C<PMC * Parrot_io_pipe_unix>
-
-Very limited C<exec> for now.
-
-=cut
-
-*/
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CAN_RETURN_NULL
-PMC *
-Parrot_io_pipe_unix(PARROT_INTERP, SHIM(PMC *filehandle), ARGIN(const char *cmd), int flags)
+static void
+get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host),
+            int port)
 {
-    /*
-     * pipe(), fork() should be defined, if this header is present
-     *        if that's not true, we need a test
-     */
-#  ifdef PARROT_HAS_HEADER_UNISTD
-    int pid, err, fds[2];
+    struct sockaddr_in *sa;
+    /* Hard coded to IPv4 for now */
+    const int family = AF_INET;
 
-    err = pipe(fds);
-    if (err < 0) {
-        return NULL;
-    }
-
-    /* Parent - return IO stream */
-    if ((pid = fork()) > 0) {
-        ParrotIO * const io =
-            Parrot_io_new(interp, PIO_F_PIPE, 0, flags & (PIO_F_READ|PIO_F_WRITE));
-        if (flags & PIO_F_READ) {
-            /* close this writer's end of pipe */
-            close(fds[1]);
-            io->fd = fds[0];
-            io->fd2 = 0;
-        }
-        else {  /* assume write only for now */
-            /* close this reader's end */
-            close(fds[0]);
-            io->fd = fds[1];
-            io->fd2 = 0;
-        }
-        return io;
+    sa = (struct sockaddr_in*)VTABLE_get_pointer(interp, sockaddr);
+#  ifdef PARROT_DEF_INET_ATON
+    if (inet_aton(host, &sa->sin_addr) != 0) {
+#  else
+    /* positive retval is success */
+    if (inet_pton(family, host, &sa->sin_addr) > 0) {
+#  endif
+        /* Success converting numeric IP */
     }
-
-    /* Child - exec process */
-    if (pid == 0) {
-        char *argv[10], *p, *c;
-        int n;
-
-        if (flags & PIO_F_WRITE) {
-            /* the other end is writing - we read from the pipe */
-            close(STDIN_FILENO);
-            close(fds[1]);
-            if (Parrot_dup(fds[0]) != STDIN_FILENO) {
-                exit(EXIT_SUCCESS);
-            }
-        }
-        else {
-            /* XXX redirect stdout, stderr to pipe */
-            close(STDIN_FILENO);
-            close(STDOUT_FILENO);
-            close(STDERR_FILENO);
-            if (Parrot_dup(fds[0]) != STDIN_FILENO
-             || Parrot_dup(fds[1]) != STDOUT_FILENO
-             || Parrot_dup(fds[1]) != STDERR_FILENO)
-            {
-                exit(EXIT_SUCCESS);
-            }
-        }
-        /*
-         * XXX ugly hack to be able to pass some arguments
-         *     split cmd at blanks
+    else {
+        /* Maybe it is a hostname, try to lookup */
+        /* XXX Check PIO option before doing a name lookup,
+         * it may have been toggled off.
          */
-        c = strdup(cmd);
-        for (n = 0, p = strtok(c, " "); n < 9 && p; p = strtok(NULL, " ")) {
-            if (n == 0)
-                cmd = p;
-            argv[n++] = p;
+        struct hostent *he = gethostbyname(host);
+        /* XXX FIXME - Handle error condition better */
+        if (!he) {
+            fprintf(stderr, "gethostbyname failure [%s]\n", host);
+            return;
         }
-        argv[n] = NULL;
-        execv(cmd, argv);       /* XXX use execvp ? */
-        /* Will never reach this unless exec fails. */
-        perror("execvp");
-        exit(EXIT_FAILURE);
+        memcpy((char*)&sa->sin_addr, he->h_addr, sizeof (sa->sin_addr));
     }
 
-    perror("fork");
-#  else
-    UNUSED(l);
-    UNUSED(cmd);
-    UNUSED(flags);
-    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
-        "pipe() unimplemented");
-#  endif
-    return NULL;
+    sa->sin_family = family;
+    sa->sin_port = htons(port);
 }
+#  endif
 
 
 #endif /* PIO_OS_UNIX */

Modified: trunk/src/io/socket_win32.c
==============================================================================
--- trunk/src/io/socket_win32.c	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/src/io/socket_win32.c	Wed Mar 25 12:14:06 2009	(r37705)
@@ -28,10 +28,11 @@
 
 #include "parrot/parrot.h"
 #include "io_private.h"
+#include "../pmc/pmc_socket.h"
 
 #ifdef PIO_OS_WIN32
 
-/* HEADERIZER HFILE: none */
+/* HEADERIZER HFILE: include/parrot/io_win32.h */
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
@@ -40,6 +41,9 @@
 
 #  if PARROT_NET_DEVEL
 
+/* Helper macros to get sockaddr_in */
+#define SOCKADDR(p, t) ((struct sockaddr_in*)VTABLE_get_pointer(interp, PARROT_SOCKET((p))->t))
+
 /*
 
 =item C<PMC * Parrot_io_socket_win32>
@@ -54,18 +58,18 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 PMC *
-Parrot_io_socket_win32(PARROT_INTERP, SHIM(PMC *socket), int fam, int type, int proto)
+Parrot_io_socket_win32(PARROT_INTERP, int fam, int type, int proto)
 {
+    int i;
     const int sock = socket(fam, type, proto);
-
     if (sock >= 0) {
-        ParrotIO * const io = Parrot_io_new(interp, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
-        io->fd = (PIOHANDLE) sock;
-        io->remote.sin_family = (short)fam;
+        PMC * io = Parrot_io_new_socket_pmc(interp, PIO_F_SOCKET|PIO_F_READ|PIO_F_WRITE);
+        PARROT_SOCKET(io)->os_handle = (void*)sock;
+        setsockopt((int)PARROT_SOCKET(io)->os_handle, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+        SOCKADDR(io, remote)->sin_family = fam;
         return io;
     }
-    perror("socket:");
-    return NULL;
+    return PMCNULL;
 }
 
 /*
@@ -79,24 +83,58 @@
 */
 
 INTVAL
-Parrot_io_connect_win32(PARROT_INTERP,
-        SHIM(PMC *socket),
-        ARGMOD(ParrotIO *io),
-        ARGIN_NULLOK(STRING *r))
+Parrot_io_connect_win32(PARROT_INTERP, ARGMOD(PMC *socket), ARGIN(PMC *r))
 {
-    if (r) {
-        struct sockaddr_in sa;
-        memcpy(&sa, PObj_bufstart(r), sizeof (struct sockaddr));
-        io->remote.sin_addr.s_addr = sa.sin_addr.s_addr;
-        io->remote.sin_port = sa.sin_port;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+
+    if(!r)
+        return -1;
+
+    PARROT_SOCKET(socket)->remote = r;
+
+AGAIN:
+    if ((connect((int)io->os_handle, (struct sockaddr *)SOCKADDR(socket, remote),
+            sizeof (struct sockaddr_in))) != 0) {
+        switch (errno) {
+            case WSAEINTR:
+                goto AGAIN;
+            case WSAEINPROGRESS:
+                goto AGAIN;
+            case WSAEISCONN:
+                return 0;
+            default:
+                return -1;
+        }
     }
 
-    /*    Parrot_io_eprintf(interp, "connect: fd = %d port = %d\n",
-     *    io->fd, ntohs(io->remote.sin_port));*/
-    if ((connect((SOCKET)io->fd, (struct sockaddr*)&io->remote,
-                   sizeof (struct sockaddr))) != 0) {
-        Parrot_io_eprintf(interp, "Parrot_io_connect_win32: errno = %d\n",
-                    WSAGetLastError());
+    return 0;
+}
+
+/*
+
+=item C<INTVAL Parrot_io_bind_win32>
+
+Binds C<*io>'s socket to the local address and port specified by C<*l>.
+
+=cut
+
+*/
+
+INTVAL
+Parrot_io_bind_win32(PARROT_INTERP, ARGMOD(PMC *socket), ARGMOD(PMC *sockaddr))
+{
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    struct sockaddr_in * saddr;
+
+    if (!sockaddr)
+        return -1;
+
+    PARROT_SOCKET(socket)->local = sockaddr;
+
+    saddr = SOCKADDR(socket, local);
+
+    if ((bind((int)io->os_handle, (struct sockaddr *) saddr,
+            sizeof (struct sockaddr_in))) == -1) {
         return -1;
     }
 
@@ -105,6 +143,70 @@
 
 /*
 
+=item C<INTVAL Parrot_io_listen_win32>
+
+Listen for new connections. This is only applicable to C<STREAM> or
+C<SEQ> sockets.
+
+=cut
+
+*/
+
+INTVAL
+Parrot_io_listen_win32(SHIM_INTERP, ARGMOD(PMC *socket), INTVAL sec)
+{
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    if ((listen((int)io->os_handle, sec)) == -1) {
+        return -1;
+    }
+    return 0;
+}
+
+/*
+
+=item C<PMC * Parrot_io_accept_win32>
+
+Accept a new connection and return a newly created C<ParrotIO> socket.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+PMC *
+Parrot_io_accept_win32(PARROT_INTERP, ARGMOD(PMC *socket))
+{
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+    PMC * newio   = Parrot_io_new_socket_pmc(interp,
+            PIO_F_SOCKET | PIO_F_READ|PIO_F_WRITE);
+    Parrot_Socklen_t    addrlen = sizeof (struct sockaddr_in);
+    struct sockaddr_in *saddr;
+    int newsock;
+
+    PARROT_SOCKET(newio)->local  = PARROT_SOCKET(socket)->local;
+    PARROT_SOCKET(newio)->remote = pmc_new(interp, enum_class_Sockaddr);
+    saddr                        = SOCKADDR(newio, remote);
+
+    newsock = accept((int)io->os_handle, (struct sockaddr *)saddr, &addrlen);
+
+    if (newsock == -1) {
+        return PMCNULL;
+    }
+
+    PARROT_SOCKET(newio)->os_handle = (void*)newsock;
+
+    /* XXX FIXME: Need to do a getsockname and getpeername here to
+     * fill in the sockaddr_in structs for local and peer */
+
+    /* Optionally do a gethostyaddr() to resolve remote IP address.
+     * This should be based on an option set in the master socket */
+
+    return newio;
+}
+
+/*
+
 =item C<INTVAL Parrot_io_send_win32>
 
 Send the message C<*s> to C<*io>'s connected socket.
@@ -114,42 +216,40 @@
 */
 
 INTVAL
-Parrot_io_send_win32(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io),
-        ARGIN(const STRING *s))
+Parrot_io_send_win32(SHIM_INTERP, ARGMOD(PMC *socket), ARGMOD(STRING *s))
 {
-    int error, byteswrote, maxwrite;
+    int error, bytes, byteswrote;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
 
-    const int bytes = sizeof (s); /* XXX This can't be correct, to send the size of a pointer */
+    bytes = s->bufused;
     byteswrote = 0;
-    maxwrite = 2048;
 AGAIN:
     /*
      * Ignore encoding issues for now.
      */
-    if ((error = send((SOCKET)io->fd, (char *)PObj_bufstart(s) + byteswrote,
-                            PObj_buflen(s), 0)) >= 0) {
+    if ((error = send((int)io->os_handle, (char *)s->strstart + byteswrote,
+                    bytes, 0)) >= 0) {
         byteswrote += error;
-        if (byteswrote >= bytes) {
+        bytes -= error;
+        if (!bytes) {
             return byteswrote;
         }
-        else if (bytes - byteswrote < maxwrite) {
-            maxwrite = bytes - byteswrote;
-        }
         goto AGAIN;
     }
     else {
         switch (errno) {
-            case EINTR:
+            case WSAEINTR:
                 goto AGAIN;
-#    ifdef EWOULDBLOCK
-            case EWOULDBLOCK:
+#    ifdef WSAEWOULDBLOCK
+            case WSAEWOULDBLOCK:
                 goto AGAIN;
 #    else
-            case EAGAIN:
+            case WSAEAGAIN:
                 goto AGAIN;
 #    endif
             case EPIPE:
-                _close((SOCKET)io->fd);
+                /* XXX why close it here and not below */
+                close((int)io->os_handle);
                 return -1;
             default:
                 return -1;
@@ -168,51 +268,41 @@
 */
 
 INTVAL
-Parrot_io_recv_win32(PARROT_INTERP,
-        SHIM(PMC *socket),
-        ARGMOD(ParrotIO *io),
-        ARGOUT(STRING **s))
+Parrot_io_recv_win32(PARROT_INTERP, ARGMOD(PMC *socket), ARGOUT(STRING **s))
 {
     int error;
-    int err;
     unsigned int bytesread = 0;
-    char buf[2048+1];
+    char buf[2048];
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
 
 AGAIN:
-    error = recv((SOCKET)io->fd, buf, 2048, 0);
-    err = WSAGetLastError();
-    if (error > 0) {
-        if (error > 0)
-            bytesread += error;
-        else {
-            _close((SOCKET)io->fd);
-        }
+    if ((error = recv((int)io->os_handle, buf, 2048, 0)) >= 0) {
+        bytesread += error;
         /* The charset should probably be 'binary', but right now httpd.pir
          * only works with 'ascii'
          */
         *s = string_make(interp, buf, bytesread, "ascii", 0);
-#    if PIO_TRACE
-        Parrot_io_eprintf(interp, "Parrot_io_recv_win32: %d bytes\n", bytesread);
-#    endif
         return bytesread;
     }
     else {
-        switch (err) {
-            case WSAEINTR:
+        switch (errno) {
+            case EINTR:
                 goto AGAIN;
+#    ifdef WSAEWOULDBLOCK
             case WSAEWOULDBLOCK:
                 goto AGAIN;
-            case WSAECONNRESET:
-                _close((SOCKET)io->fd);
-#    if PIO_TRACE
-                Parrot_io_eprintf(interp, "recv: Connection reset by peer\n");
+#    else
+            case WSAEAGAIN:
+                goto AGAIN;
 #    endif
+            case WSAECONNRESET:
+                /* XXX why close it on err return result is -1 anyway */
+                close((int)io->os_handle);
+                *s = Parrot_str_new_noinit(interp, enum_stringrep_one, 0);
                 return -1;
             default:
-                _close((SOCKET)io->fd);
-#    if PIO_TRACE
-                Parrot_io_eprintf(interp, "recv: errno = %d\n", err);
-#    endif
+                close((int)io->os_handle);
+                *s = Parrot_str_new_noinit(interp, enum_stringrep_one, 0);
                 return -1;
         }
     }
@@ -220,149 +310,101 @@
 
 /*
 
-=item C<INTVAL Parrot_io_bind_win32>
+=item C<INTVAL Parrot_io_poll_win32>
 
-Binds C<*io>'s socket to the local address and port specified by C<*l>.
+Utility function for polling a single IO stream with a timeout.
 
-=cut
+Returns a 1 | 2 | 4 (read, write, error) value.
 
-*/
-
-INTVAL
-Parrot_io_bind_win32(PARROT_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io),
-        ARGIN_NULLOK(STRING *l))
-{
-    struct sockaddr_in sa;
+This is not equivalent to any speficic POSIX or BSD socket call, however
+it is a useful, common primitive.
 
-    if (!l)
-        return -1;
+Not at all usefule --leo.
 
-    memcpy(&sa, PObj_bufstart(l), sizeof (struct sockaddr));
-    io->local.sin_addr.s_addr = sa.sin_addr.s_addr;
-    io->local.sin_port = sa.sin_port;
-    io->local.sin_family = AF_INET;
-
-    if ((bind((SOCKET)io->fd, (struct sockaddr *)&io->local,
-              sizeof (struct sockaddr))) == -1) {
-        Parrot_io_eprintf(interp, "Parrot_io_bind_win32: errno = %d\n",
-                    WSAGetLastError());
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
-
-=item C<INTVAL Parrot_io_listen_win32>
-
-Listen for new connections. This is only applicable to C<STREAM> or
-C<SEQ> sockets.
+Also, a buffering layer above this may choose to reimpliment by checking
+the read buffer.
 
 =cut
 
 */
 
 INTVAL
-Parrot_io_listen_win32(SHIM_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io), INTVAL backlog)
+Parrot_io_poll_win32(SHIM_INTERP, ARGMOD(PMC *socket), int which, int sec,
+    int usec)
 {
-    if ((listen((SOCKET)io->fd, backlog)) == -1) {
-        fprintf(stderr, "listen: errno= ret=%d fd = %d port = %d\n",
-             errno, (int)io->fd, ntohs(io->local.sin_port));
-        return -1;
+    int n;
+    fd_set r, w, e;
+    struct timeval t;
+    Parrot_Socket_attributes * io = PARROT_SOCKET(socket);
+
+    t.tv_sec = sec;
+    t.tv_usec = usec;
+    FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+    /* These should be defined in header */
+    if (which & 1) FD_SET((int)io->os_handle, &r);
+    if (which & 2) FD_SET((int)io->os_handle, &w);
+    if (which & 4) FD_SET((int)io->os_handle, &e);
+AGAIN:
+    if ((select((int)io->os_handle+1, &r, &w, &e, &t)) >= 0) {
+        n = (FD_ISSET((int)io->os_handle, &r) ? 1 : 0);
+        n |= (FD_ISSET((int)io->os_handle, &w) ? 2 : 0);
+        n |= (FD_ISSET((int)io->os_handle, &e) ? 4 : 0);
+        return n;
+    }
+    else {
+        switch (errno) {
+            case EINTR:        goto AGAIN;
+            default:           return -1;
+        }
     }
-    return 0;
 }
 
-/*
-
-=item C<PMC * Parrot_io_accept_win32>
-
-Accept a new connection and return a newly created C<Socket> PMC.
-
-=cut
-
-*/
-
-PARROT_CAN_RETURN_NULL
-PMC *
-Parrot_io_accept_win32(PARROT_INTERP, SHIM(PMC *socket), ARGMOD(ParrotIO *io))
+static void
+get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host),
+            int port)
 {
-    int newsock;
-    int err_code;
-
-    ParrotIO * const newio = Parrot_io_new(interp, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
-    Parrot_Socklen_t newsize = sizeof (struct sockaddr);
-
-    newsock = accept((SOCKET)io->fd, (struct sockaddr *)&(newio->remote),
-                     &newsize);
-    err_code = WSAGetLastError();
+    struct sockaddr_in *sa;
+    /* Hard coded to IPv4 for now */
+    const int family = AF_INET;
 
-    if (err_code != 0) {
-        fprintf(stderr, "accept: errno=%d", err_code);
-        /* Didn't get far enough, free the io */
-        mem_sys_free(newio);
-        return NULL;
+    sa = (struct sockaddr_in*)VTABLE_get_pointer(interp, sockaddr);
+    if (inet_addr(host, &sa->sin_addr) != 0) {
+        /* Success converting numeric IP */
+    }
+    else {
+        /* Maybe it is a hostname, try to lookup */
+        /* XXX Check PIO option before doing a name lookup,
+         * it may have been toggled off.
+         */
+        struct hostent *he = gethostbyname(host);
+        /* XXX FIXME - Handle error condition better */
+        if (!he) {
+            fprintf(stderr, "gethostbyname failure [%s]\n", host);
+            return;
+        }
+        memcpy((char*)&sa->sin_addr, he->h_addr, sizeof (sa->sin_addr));
     }
 
-    newio->fd = (PIOHANDLE) newsock;
-
-    /* XXX FIXME: Need to do a getsockname and getpeername here to
-     * fill in the sockaddr_in structs for local and peer
-     */
-
-    /* Optionally do a gethostyaddr() to resolve remote IP address.
-     * This should be based on an option set in the master socket
-     */
-
-    return newio;
+    sa->sin_family = family;
+    sa->sin_port = htons(port);
 }
 
-#  endif
-
-/*
-
-=item C<STRING * Parrot_io_sockaddr_in>
-
-C<Parrot_io_sockaddr_in()> is not part of the layer and so must be C<extern>.
-
-XXX: We can probably just write our own routines (C<htons()>,
-C<inet_aton()>, etc.) and take this out of platform specific compilation
-
-=cut
-
-*/
-
 PARROT_WARN_UNUSED_RESULT
-PARROT_CAN_RETURN_NULL
-STRING *
-Parrot_io_sockaddr_in(PARROT_INTERP, unsigned short port, ARGMOD(STRING *addr))
+PARROT_CANNOT_RETURN_NULL
+PMC *
+Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port)
 {
-    struct sockaddr_in sa;
-    struct hostent *he;
-    char * const s = Parrot_str_to_cstring(interp, addr);
-    /* Hard coded to IPv4 for now */
-
-    sa.sin_addr.s_addr = inet_addr(s);
-    /* Maybe it is a hostname, try to lookup */
-    /* XXX Check PIO option before doing a name lookup,
-     * it may have been toggled off.
-     */
-    he = gethostbyname(s);
-    Parrot_str_free_cstring(s);
-
-    /* XXX FIXME - Handle error condition better */
-    if (!he) {
-        fprintf(stderr, "gethostbyname failure [%s]\n", s);
-        return NULL;
-    }
-    memcpy((char*)&sa.sin_addr, he->h_addr, sizeof (sa.sin_addr));
-
-    sa.sin_port = htons(port);
+    PMC * sockaddr;
+    char * s;
 
-    return string_make(interp, (char *)&sa, sizeof (struct sockaddr), "binary", 0);
+    s = Parrot_str_to_cstring(interp, addr);
+    sockaddr = pmc_new(interp, enum_class_Sockaddr);
+    get_sockaddr_in(interp, sockaddr, s, port);
+    free(s);
+    return sockaddr;
 }
 
+#endif /* PARROT_NET_DEVEL */
 
 #endif /* PIO_OS_WIN32 */
 
@@ -373,7 +415,7 @@
 =head1 SEE ALSO
 
 F<src/io/win32.c>,
-F<src/io/unix_socket.c>,
+F<src/io/win32_socket.c>,
 F<src/io/io.c>,
 F<src/io/io_private.h>.
 

Modified: trunk/src/ops/io.ops
==============================================================================
--- trunk/src/ops/io.ops	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/src/ops/io.ops	Wed Mar 25 12:14:06 2009	(r37705)
@@ -496,6 +496,76 @@
 
 ########################################
 
+=item B<sockaddr>(out PMC, in STRING, in INT)
+
+Create new Sockaddr PMC.
+
+=cut
+
+op sockaddr(out PMC, in STR, in INT) {
+    $1 = Parrot_io_sockaddr_in(interp, $2, $3);
+}
+
+=item B<socket>(out PMC, in INT, in INT, in INT)
+
+Create new Socket
+
+=cut
+
+op socket(out PMC, in INT, in INT, in INT) {
+    $1 = Parrot_io_socket(interp, $2, $3, $4);
+}
+
+=item B<bind>(out INT, in PMC, in PMC)
+
+Bind Socket to address
+
+=cut
+
+op bind(out INT, in PMC, in PMC) {
+    $1 = Parrot_io_bind(interp, $2, $3);
+}
+
+=item B<listen>(out INT, in PMC, in INT)
+
+Start listening on previously bounded socket
+
+=cut
+
+op listen(out INT, in PMC, in INT) {
+    $1 = Parrot_io_listen(interp, $2, $3);
+}
+
+=item B<accept>(out PMC, in PMC)
+
+Accept incoming connection
+
+=cut
+
+op accept(out PMC, in PMC) {
+    $1 = Parrot_io_accept(interp, $2);
+}
+
+=item B<recv>(out INT, in PMC, out STR)
+
+Recive data from socket
+
+=cut
+
+op recv(out INT, in PMC, out STR) {
+    $1 = Parrot_io_recv(interp, $2, &$3);
+}
+
+=item B<send>(out INT, in PMC, int STR)
+
+Recive data from socket
+
+=cut
+
+op send(out INT, in PMC, in STR) {
+    $1 = Parrot_io_send(interp, $2, $3);
+}
+
 =back
 
 =cut

Modified: trunk/src/ops/ops.num
==============================================================================
--- trunk/src/ops/ops.num	Wed Mar 25 07:17:01 2009	(r37704)
+++ trunk/src/ops/ops.num	Wed Mar 25 12:14:06 2009	(r37705)
@@ -1268,3 +1268,31 @@
 find_sub_not_null_p_sc         1244
 load_language_s                1245
 load_language_sc               1246
+socket_p_i_i_i                 1247
+socket_p_ic_i_i                1248
+socket_p_i_ic_i                1249
+socket_p_i_i_ic                1250
+socket_p_ic_i_ic               1251
+socket_p_i_ic_ic               1252
+socket_p_ic_ic_ic              1253
+socket_p_ic_ic_i               1254
+sockaddr_p_s_i                 1255
+sockaddr_p_sc_i                1256
+sockaddr_p_s_ic                1257
+sockaddr_p_sc_ic               1258
+bind_i_p_p                     1259
+bind_i_pc_p                    1260
+bind_i_p_pc                    1261
+bind_i_pc_pc                   1262
+listen_i_p_i                   1263
+listen_i_pc_i                  1264
+listen_i_p_ic                  1265
+listen_i_pc_ic                 1266
+accept_p_p                     1267
+accept_p_pc                    1268
+recv_i_p_s                     1269
+recv_i_pc_s                    1270
+send_i_p_s                     1271
+send_i_pc_s                    1272
+send_i_p_sc                    1273
+send_i_pc_sc                   1274

Added: trunk/src/pmc/sockaddr.pmc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/pmc/sockaddr.pmc	Wed Mar 25 12:14:06 2009	(r37705)
@@ -0,0 +1,140 @@
+/*
+Copyright (C) 2008-2009, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/pmc/sockaddr.pmc - sockaddr_in holder
+
+=head1 DESCRIPTION
+
+The Sockaddr PMC holds raw c-pointer to sockaddr_in
+
+
+=head2 Vtable Functions
+
+These are the vtable functions for the Sockaddr class.
+
+=over 4
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    struct sockaddr_in;
+#ifdef __cplusplus
+}
+#endif
+
+pmclass Sockaddr need_ext {
+    ATTR void   *pointer; /* The stored pointer. */
+
+/*
+
+=item C<void init()>
+
+Initializes the pointer object.
+
+=cut
+
+*/
+
+    VTABLE void init() {
+        Parrot_Sockaddr_attributes * const pdata_struct =
+            mem_allocate_typed(Parrot_Sockaddr_attributes);
+
+        PMC_data(SELF)        = pdata_struct;
+        pdata_struct->pointer = mem_allocate_zeroed_typed(struct sockaddr_in);
+    }
+
+/*
+
+=item C<void destroy()>
+
+Destroys the PMC and frees all allocated memory.
+
+=cut
+
+*/
+
+    VTABLE void destroy() {
+        Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
+
+        if (data) {
+            mem_sys_free(data->pointer);
+            mem_sys_free(data);
+            PMC_data(SELF) = NULL;
+        }
+    }
+
+/*
+
+=item C<PMC *clone()>
+
+Creates and returns a clone of the pointer.
+
+=cut
+
+*/
+
+    VTABLE PMC *clone() {
+        PMC * const dest = pmc_new(INTERP, SELF->vtable->base_type);
+        memcpy(PARROT_SOCKADDR(dest)->pointer, PARROT_SOCKADDR(SELF)->pointer,
+                sizeof(struct sockaddr_in));
+        return dest;
+    }
+
+/*
+
+=item C<void *get_pointer()>
+
+Returns the pointer.
+
+=cut
+
+*/
+
+    VTABLE void *get_pointer() {
+        Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
+        return data->pointer;
+    }
+
+/*
+
+=item C<void set_pointer(void *)>
+
+Sets the pointer.
+
+=cut
+
+*/
+
+/*
+    VTABLE void set_pointer(void *value) {
+        Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
+        return data->pointer;
+    }
+*/
+
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
+

Added: trunk/src/pmc/socket.pmc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/pmc/socket.pmc	Wed Mar 25 12:14:06 2009	(r37705)
@@ -0,0 +1,231 @@
+/*
+Copyright (C) 2008, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/pmc/socket.pmc - Socket PMC
+
+=head1 DESCRIPTION
+
+The Socket PMC performs network I/O operations.
+
+=head2 Vtable Functions
+
+=over 4
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "../src/io/io_private.h"
+
+//#include <sys/socket.h>
+
+pmclass Socket extends FileHandle need_ext {
+    ATTR PMC *local;           /* Local addr                   */
+    ATTR PMC *remote;          /* Remote addr                  */
+
+/*
+
+=item C<void init()>
+
+Initializes a newly created Socket object.
+
+=cut
+
+*/
+
+    VTABLE void init() {
+        Parrot_Socket_attributes *data_struct =
+                mem_allocate_typed(Parrot_Socket_attributes);
+
+        PMC_data(SELF)      = data_struct;
+        data_struct->local  = PMCNULL;
+        data_struct->remote = PMCNULL;
+
+        /* Initialize the os_handle to the platform-specific value for closed. */
+#ifdef PIO_OS_WIN32
+    data_struct->os_handle    = (PIOHANDLE)INVALID_HANDLE_VALUE;
+#endif
+#ifdef PIO_OS_UNIX
+    data_struct->os_handle    = (PIOHANDLE)-1;
+#endif
+#ifdef PIO_OS_STDIO
+    data_struct->os_handle    = (PIOHANDLE)NULL;
+#endif
+
+        PObj_custom_mark_destroy_SETALL(SELF);
+    }
+
+/*
+
+=item C<PMC *clone()>
+
+Create a copy of the filehandle.
+
+=cut
+
+*/
+
+    VTABLE PMC *clone() {
+        Parrot_Socket_attributes * const old_struct  = PARROT_SOCKET(SELF);
+        PMC * const copy = Parrot_io_new_socket_pmc(interp, old_struct->flags);
+        Parrot_Socket_attributes * const data_struct = PARROT_SOCKET(copy);
+
+        data_struct->os_handle    = Parrot_dup(old_struct->os_handle);
+        //memcpy(data_struct->local, old_struct->local, sizeof(struct sockaddr_in));
+        //memcpy(data_struct->remote, old_struct->remote, sizeof(struct sockaddr_in));
+
+        return SELF;
+    }
+
+/*
+
+=item C<void mark()>
+
+Mark active filehandle data as live.
+
+=cut
+
+*/
+
+    VTABLE void mark() {
+        Parrot_Socket_attributes * const data = PARROT_SOCKET(SELF);
+
+        if (data) {
+            if (data->local)
+                pobject_lives(interp, (PObj *)data->local);
+
+            if (data->remote)
+                pobject_lives(interp, (PObj *)data->remote);
+        }
+    }
+/*
+
+=item C<void destroy()>
+
+Free structures.
+
+=cut
+
+*/
+    VTABLE void destroy() {
+        if (PARROT_SOCKET(SELF)) {
+            Parrot_Socket_attributes *data_struct = PARROT_SOCKET(SELF);
+
+            /* TODO Shutdown socket */
+        }
+    }
+
+    METHOD close() {
+        INTVAL status = 0;
+        close(PARROT_SOCKET(SELF)->os_handle);
+        RETURN(INTVAL status);
+    }
+
+
+/*
+
+=back
+
+=head2 Methods
+
+=over 4
+
+
+/*
+
+=item C<connect> 
+
+Connects a socket object to an address.
+
+The asynchronous version takes an additional final PMC callback
+argument, and only returns a status object. When the socket operation is
+complete, it invokes the callback, passing it a status object and the
+socket object it was called on. [If you want notification when a connect
+operation is completed, you probably want to do something with that
+connected socket object.]
+
+=cut
+
+*/
+
+    METHOD connect(PMC * address) {
+        INTVAL res = Parrot_io_connect(INTERP, SELF, address);
+        RETURN(INTVAL res);
+    }
+
+/*
+
+=item C<recv> 
+
+Receives a message from a connected socket object. It returns
+the message in a string.
+
+The asynchronous version takes an additional final PMC callback
+argument, and only returns a status object. When the recv operation is
+complete, it invokes the callback, passing it a status object and a
+string containing the received message.
+
+=cut
+
+*/
+
+    METHOD recv() {
+        STRING * result;
+        INTVAL read = Parrot_io_recv(INTERP, SELF, &result);
+        RETURN(STRING * result);
+    }
+
+/*
+
+=item C<send>
+
+Sends a message string to a connected socket object.
+
+The asynchronous version takes an additional final PMC callback
+argument, and only returns a status object. When the send operation is
+complete, it invokes the callback, passing it a status object.
+
+=cut
+
+*/
+
+    METHOD send(STRING *buf) {
+        INTVAL res = Parrot_io_send(INTERP, SELF, buf);
+        RETURN(INTVAL res);
+    }
+
+    METHOD bind(PMC *host) {
+        INTVAL res = Parrot_io_bind(INTERP, SELF, host);
+        RETURN(INTVAL res);
+    }
+
+    METHOD listen(INTVAL backlog) {
+        INTVAL res = Parrot_io_listen(INTERP, SELF, backlog);
+        RETURN(INTVAL res);
+    }
+
+    METHOD accept() {
+        PMC * res = Parrot_io_accept(INTERP, SELF);
+        RETURN(PMC * res);
+    }
+
+/*
+
+=back
+
+=cut
+
+*/
+
+} /* end pmclass */
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4 ft=pmc:
+ */

Added: trunk/t/pmc/sockaddr.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/t/pmc/sockaddr.t	Wed Mar 25 12:14:06 2009	(r37705)
@@ -0,0 +1,39 @@
+#! parrot
+# Copyright (C) 2006-2008, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+t/pmc/sockaddr.t - test the Sockaddr PMC
+
+=head1 SYNOPSIS
+
+    % prove t/pmc/sockaddr.t
+
+=head1 DESCRIPTION
+
+Tests the SharedRef PMC.
+
+=cut
+
+.sub main :main
+    .include 'test_more.pir'
+
+    plan(3)
+
+    new $P0, ['Sockaddr']
+    ok(1, 'Instantiated a Sockaddr PMC')
+
+    $P0 = sockaddr "localhost", 1234
+    ok(1, 'op sockaddr successful')
+
+    $I0 = isnull $P0
+    $I0 = not $I0
+    ok($I0, 'Sockaddr PMC created')
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:


More information about the parrot-commits mailing list