[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