diff --git a/config/gen/makefiles/root.in b/config/gen/makefiles/root.in index 6a1d9ac..7f3e5b9 100644 --- a/config/gen/makefiles/root.in +++ b/config/gen/makefiles/root.in @@ -362,7 +362,9 @@ IO_O_FILES := \ $(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) INTERP_O_FILES := \ $(SRC_DIR)/string/api$(O) \ diff --git a/examples/io/httpd.pir b/examples/io/httpd.pir new file mode 100644 index 0000000..2c6a2bc --- /dev/null +++ b/examples/io/httpd.pir @@ -0,0 +1,426 @@ +# Copyright (C) 2006-2008, Parrot Foundation. +# $Id: httpd.pir 36833 2009-02-17 20:09:26Z allison $ + +=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 +was started. + +=head2 CGI + +If the file extension is C<.pir> or C<.pbc>, this file will be loaded +below the directory F and the function C will be +invoked with the query as an argument. +This functions should return a plain string, which will be sent to the +browser. + +F is called with 3 arguments: a todo/reserved PMC, a string +with the original query and a Hash, with C items split by +C<'+'>. C and C are already C. + + $ 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 ("

foo

") # in practice use a full doc + # unless serving XMLHttpRequest's + .end + +The browser request: + + http://localhost:1234/foo.pir?foo=1+bar=%61 + +will serve, whatever the C 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 - +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 Parrot Documentation." + 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: diff --git a/include/parrot/io.h b/include/parrot/io.h index 9669788..8f0f035 100644 --- a/include/parrot/io.h +++ b/include/parrot/io.h @@ -1,7 +1,7 @@ /* io.h * Copyright (C) 2001-2003, Parrot Foundation. * SVN Info - * $Id$ + * $Id: io.h 36833 2009-02-17 20:09:26Z allison $ * Overview: * Parrot IO subsystem * Data Structure and Algorithms: @@ -757,6 +757,122 @@ void Parrot_io_set_buffer_start(SHIM_INTERP, /* 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 *); diff --git a/include/parrot/io_unix.h b/include/parrot/io_unix.h index 13d5373..4fd5c69 100644 --- a/include/parrot/io_unix.h +++ b/include/parrot/io_unix.h @@ -1,7 +1,7 @@ /* io_unix.h * Copyright (C) 2001-2003, Parrot Foundation. * SVN Info - * $Id$ + * $Id: io_unix.h 36833 2009-02-17 20:09:26Z allison $ * Overview: * Parrot IO subsystem * Data Structure and Algorithms: @@ -155,6 +155,106 @@ size_t Parrot_io_write_unix(PARROT_INTERP, /* 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 @@ size_t Parrot_io_write_unix(PARROT_INTERP, #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 */ /* diff --git a/src/io/socket_api.c b/src/io/socket_api.c index 3cb895d..17f5ce5 100644 --- a/src/io/socket_api.c +++ b/src/io/socket_api.c @@ -1,6 +1,6 @@ /* Copyright (C) 2001-2008, Parrot Foundation. -$Id$ +$Id: socket_api.c 36832 2009-02-17 19:58:58Z allison $ =head1 NAME @@ -20,7 +20,7 @@ These are the primary interface functions for working with socket objects. #include "parrot/parrot.h" #include "io_private.h" -#include "io.str" +#include "api.str" #include @@ -32,6 +32,27 @@ These are the primary interface functions for working with socket objects. =over 4 +*/ + + +/* + +=item C + +=cut + +*/ + +PARROT_EXPORT +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +INTVAL +Parrot_io_socket_is_closed(ARGMOD(PMC *socket)) +{ + return 0; +} + +/* =item C @@ -71,8 +92,7 @@ PARROT_CANNOT_RETURN_NULL 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 @@ Connects C<*pmc> to C<*address>. Returns C<-1> on failure. 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 @@ C<*address>. Returns C<-1> on failure. 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 @@ Parrot_io_accept(PARROT_INTERP, ARGMOD(PMC *pmc)) { if (Parrot_io_socket_is_closed(pmc)) - return -1; + return PMCNULL; - return PIO_ACCEPT(interp, l, io); + return PIO_ACCEPT(interp, pmc); } /* +=item C + +Creates a new I/O socket object. The value of C 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 diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c index 425a8ae..0a36548 100644 --- a/src/io/socket_unix.c +++ b/src/io/socket_unix.c @@ -1,6 +1,6 @@ /* Copyright (C) 2001-2008, Parrot Foundation. -$Id$ +$Id: socket_unix.c 36832 2009-02-17 19:58:58Z allison $ =head1 NAME @@ -28,8 +28,11 @@ APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons) */ +#include + #include "parrot/parrot.h" #include "io_private.h" +#include "../pmc/pmc_socket.h" #ifdef PIO_OS_UNIX @@ -38,10 +41,27 @@ APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons) /* 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 @@ Very minimal stubs for now, maybe someone will run with these. =over 4 -=item C +=item C C is not part of the layer and so must be C. @@ -67,50 +87,23 @@ C, etc.) and take this out of platform specific compilation */ +/* 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; - - 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); + PMC * sockaddr; + char * s; + + 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,19 @@ socket type and protocol number. 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_io_set_os_handle(interp, socket, sock); */ + 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 +149,17 @@ Connects C<*io>'s socket to address C<*r>. */ 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) - memcpy(&io->remote, PObj_bufstart(r), sizeof (struct sockaddr_in)); + if(!r) + return -1; + + 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 +187,19 @@ Binds C<*io>'s socket to the local address and port specified by C<*l>. */ 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 +219,10 @@ C sockets. */ 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 +230,7 @@ Parrot_io_listen_unix(SHIM_INTERP, SHIM(PMC *socket), ARGIN(ParrotIO *io), /* -=item C +=item C Accept a new connection and return a newly created C socket. @@ -244,21 +241,26 @@ Accept a new connection and return a newly created C socket. 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 +282,10 @@ Send the message C<*s> to C<*io>'s connected socket. */ 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 +293,7 @@ AGAIN: /* * 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 +315,7 @@ AGAIN: # 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 +334,15 @@ Receives a message in C<**s> from C<*io>'s connected socket. */ 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 +363,11 @@ AGAIN: # 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 +395,26 @@ the read buffer. */ 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 +425,41 @@ AGAIN: } } -# endif -/* - -=item C - -Very limited C 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]; - - err = pipe(fds); - if (err < 0) { - return NULL; - } + struct sockaddr_in *sa; + /* Hard coded to IPv4 for now */ + const int family = AF_INET; - /* 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 */ diff --git a/src/io/socket_win32.c b/src/io/socket_win32.c index e0e3c54..82ba19d 100644 --- a/src/io/socket_win32.c +++ b/src/io/socket_win32.c @@ -1,6 +1,6 @@ /* Copyright (C) 2001-2003, Parrot Foundation. -$Id$ +$Id: socket_win32.c 36832 2009-02-17 19:58:58Z allison $ =head1 NAME @@ -31,7 +31,7 @@ Win32 System Programming, 2nd Edition. #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. */ diff --git a/src/ops/io.ops b/src/ops/io.ops index 47c5dc4..b243819 100644 --- a/src/ops/io.ops +++ b/src/ops/io.ops @@ -496,6 +496,76 @@ op tell(out INT, out INT, invar PMC) :base_io { ######################################## +=item B(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(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(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(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(out PMC, in PMC) + +Accept incoming connection + +=cut + +op accept(out PMC, in PMC) { + $1 = Parrot_io_accept(interp, $2); +} + +=item B(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(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 diff --git a/src/ops/ops.num b/src/ops/ops.num index 98a337a..d7a956a 100644 --- a/src/ops/ops.num +++ b/src/ops/ops.num @@ -1266,3 +1266,31 @@ find_name_p_s 1241 find_name_p_sc 1242 find_sub_not_null_p_s 1243 find_sub_not_null_p_sc 1244 +socket_p_i_i_i 1245 +socket_p_ic_i_i 1246 +socket_p_i_ic_i 1247 +socket_p_i_i_ic 1248 +socket_p_ic_i_ic 1249 +socket_p_i_ic_ic 1250 +socket_p_ic_ic_ic 1251 +socket_p_ic_ic_i 1252 +sockaddr_p_s_i 1253 +sockaddr_p_sc_i 1254 +sockaddr_p_s_ic 1255 +sockaddr_p_sc_ic 1256 +bind_i_p_p 1257 +bind_i_pc_p 1258 +bind_i_p_pc 1259 +bind_i_pc_pc 1260 +listen_i_p_i 1261 +listen_i_pc_i 1262 +listen_i_p_ic 1263 +listen_i_pc_ic 1264 +accept_p_p 1265 +accept_p_pc 1266 +recv_i_p_s 1267 +recv_i_pc_s 1268 +send_i_p_s 1269 +send_i_pc_s 1270 +send_i_p_sc 1271 +send_i_pc_sc 1272 diff --git a/src/pmc/sockaddr.pmc b/src/pmc/sockaddr.pmc new file mode 100644 index 0000000..d90bc05 --- /dev/null +++ b/src/pmc/sockaddr.pmc @@ -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 + +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 + +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 + +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 + +Returns the pointer. + +=cut + +*/ + + VTABLE void *get_pointer() { + Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); + return data->pointer; + } + +/* + +=item C + +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: + */ + diff --git a/src/pmc/socket.pmc b/src/pmc/socket.pmc new file mode 100644 index 0000000..90bd3d3 --- /dev/null +++ b/src/pmc/socket.pmc @@ -0,0 +1,231 @@ +/* +Copyright (C) 2008, Parrot Foundation. +$Id: filehandle.pmc 36832 2009-02-17 19:58:58Z allison $ + +=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 + +pmclass Socket extends FileHandle need_ext { + ATTR PMC *local; /* Local addr */ + ATTR PMC *remote; /* Remote addr */ + +/* + +=item C + +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 + +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 + +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 + +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 + +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 + +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 + +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: + */ diff --git a/t/pmc/sockaddr.t b/t/pmc/sockaddr.t new file mode 100644 index 0000000..43b214d --- /dev/null +++ b/t/pmc/sockaddr.t @@ -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: