[pypy-svn] r18901 - in pypy/dist/pypy: module/_socket module/_socket/rpython module/_socket/rpython/test translator/c translator/c/src translator/c/test

afa at codespeak.net afa at codespeak.net
Tue Oct 25 02:52:08 CEST 2005


Author: afa
Date: Tue Oct 25 02:51:56 2005
New Revision: 18901

Modified:
   pypy/dist/pypy/module/_socket/interp_socket.py
   pypy/dist/pypy/module/_socket/rpython/exttable.py
   pypy/dist/pypy/module/_socket/rpython/ll__socket.py
   pypy/dist/pypy/module/_socket/rpython/test/test_ll__socket.py
   pypy/dist/pypy/translator/c/extfunc.py
   pypy/dist/pypy/translator/c/src/ll__socket.h
   pypy/dist/pypy/translator/c/test/test_extfunc.py
Log:
Implemented socket.getaddrinfo()

- Only support for ipv4 addresses

- Hard, because I need 2 structures: an opaque object that works
  as an iterator, and a tuple to get each result.

- Each string is IncRef'd twice: in RPyString_FromString, and when inserted
  into the tuple. Is there a way to DecRef a rstring from custom C code?
  I had to mark the test "in-progress" because of this.

- There must be an easier way. For example, ll__socket.ADDRINFO_RESULT
  and exttable.ann_addrinfo should come from a unique source.

Comments are welcome!
- This line, and those below, will be ignored--

M    pypy/module/_socket/interp_socket.py
M    pypy/module/_socket/rpython/test/test_ll__socket.py
M    pypy/module/_socket/rpython/exttable.py
M    pypy/module/_socket/rpython/ll__socket.py
M    pypy/translator/c/test/test_extfunc.py
M    pypy/translator/c/src/ll__socket.h
M    pypy/translator/c/extfunc.py


Modified: pypy/dist/pypy/module/_socket/interp_socket.py
==============================================================================
--- pypy/dist/pypy/module/_socket/interp_socket.py	(original)
+++ pypy/dist/pypy/module/_socket/interp_socket.py	Tue Oct 25 02:51:56 2005
@@ -4,6 +4,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import W_Root, NoneNotWrapped
 from pypy.interpreter.gateway import ObjSpace, interp2app
+from pypy.module._socket.rpython import rsocket
 
 if sys.platform == 'win32':
     WIN32_ERROR_MESSAGES = {
@@ -325,25 +326,53 @@
         raise wrap_socketerror(space, e)
 inet_ntop.unwrap_spec = [ObjSpace, int, str]
 
+def enumerateaddrinfo(space, addr):
+    result = []
+    while addr.nextinfo():
+        info = (addr.family, addr.socktype, addr.proto,
+                addr.canonname, addr.sockaddr)
+        result.append(space.wrap(info))
+    return space.newlist(result)
+
 def getaddrinfo(space, w_host, w_port, family=0, socktype=0, proto=0, flags=0):
     """getaddrinfo(host, port [, family, socktype, proto, flags])
         -> list of (family, socktype, proto, canonname, sockaddr)
 
     Resolve host and port into addrinfo struct.
     """
-    if space.is_true(space.isinstance(w_host, space.w_unicode)):
-        w_host = space.call_method(w_host, "encode", space.wrap("idna"))
-    host = space.unwrap(w_host)
+    # host can be None, string or unicode
+    if space.is_w(w_host, space.w_None):
+        host = None
+    elif space.is_true(space.isinstance(w_host, space.w_str)):
+        host = space.str_w(w_host)
+    elif space.is_true(space.isinstance(w_host, space.w_unicode)):
+        w_shost = space.call_method(w_host, "encode", space.wrap("idna"))
+        host = space.str_w(w_shost)
+    else:
+        raise OperationError(space.w_TypeError,
+                             space.wrap(
+            "getaddrinfo() argument 1 must be string or None"))
 
-    if space.is_true(space.isinstance(w_port, space.w_int)):
+    # port can be None, int or string
+    if space.is_w(w_port, space.w_None):
+        port = None
+    elif space.is_true(space.isinstance(w_port, space.w_int)):
         port = str(space.int_w(w_port))
-    else:
+    elif space.is_true(space.isinstance(w_port, space.w_str)):
         port = space.str_w(w_port)
+    else:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("Int or String expected"))
 
     try:
-        return space.wrap(socket.getaddrinfo(host, port, family, socktype, proto, flags))
+        addr = rsocket.getaddrinfo(host, port, family, socktype, proto, flags)
     except socket.error, e:
         raise wrap_socketerror(space, e)
+
+    try:
+        return enumerateaddrinfo(space, addr)
+    finally:
+        addr.free()
 getaddrinfo.unwrap_spec = [ObjSpace, W_Root, W_Root, int, int, int, int]
 
 def getnameinfo(space, w_sockaddr, flags):

Modified: pypy/dist/pypy/module/_socket/rpython/exttable.py
==============================================================================
--- pypy/dist/pypy/module/_socket/rpython/exttable.py	(original)
+++ pypy/dist/pypy/module/_socket/rpython/exttable.py	Tue Oct 25 02:51:56 2005
@@ -3,15 +3,38 @@
 """
 
 import _socket
-from pypy.rpython.extfunctable import declare
+from pypy.module._socket.rpython import rsocket
+from pypy.rpython.extfunctable import declare, declareptrtype
+from pypy.annotation.model import Constant, SomeTuple, SomeList, SomeInteger, SomeString
+from pypy.annotation.listdef import ListDef
+from pypy.annotation.model import unionof
 
 module = 'pypy.module._socket.rpython.ll__socket'
 
 # ____________________________________________________________
 # Built-in functions needed in the rtyper
 
+def ann_addrinfo(*s_args):
+    # Address info is a tuple: (family, socktype, proto, canonname, sockaddr)
+    # where sockaddr is either a 2-tuple or a 4-tuple
+    addrinfo = SomeTuple([SomeInteger(),
+                          SomeInteger(),
+                          SomeInteger(),
+                          SomeString(),
+                          SomeString(),
+                          SomeInteger(),
+                          SomeInteger(),
+                          SomeInteger(),
+                          ])
+    return addrinfo
+
 declare(_socket.gethostname, str, '%s/gethostname' % module)
 
+declare(rsocket.getaddrinfo, rsocket.ADDRINFO, '%s/getaddrinfo' % module)
+declareptrtype(rsocket.ADDRINFO, "ADDRINFO",
+               nextinfo = (ann_addrinfo, '%s/nextaddrinfo' % module),
+               free     = (type(None), '%s/freeaddrinfo' % module))
+
 declare(_socket.ntohs, int, '%s/ntohs' % module)
 declare(_socket.htons, int, '%s/ntohs' % module)
 declare(_socket.ntohl, int, '%s/ntohl' % module)

Modified: pypy/dist/pypy/module/_socket/rpython/ll__socket.py
==============================================================================
--- pypy/dist/pypy/module/_socket/rpython/ll__socket.py	(original)
+++ pypy/dist/pypy/module/_socket/rpython/ll__socket.py	Tue Oct 25 02:51:56 2005
@@ -1,11 +1,58 @@
 import _socket
 
-from pypy.rpython.module.support import to_rstr
+from pypy.rpython.rstr import STR
+from pypy.rpython.lltype import GcStruct, Signed, Array, Char, Ptr, malloc
+from pypy.rpython.module.support import to_rstr, from_rstr
+from pypy.rpython.module.support import to_opaque_object, from_opaque_object
+from pypy.module._socket.rpython import rsocket
 
 def ll__socket_gethostname():
     return to_rstr(_socket.gethostname())
 ll__socket_gethostname.suggested_primitive = True
 
+def ll__socket_getaddrinfo(host, port, family, socktype, proto, flags):
+    addr = rsocket.getaddrinfo(from_rstr(host), port,
+                               family, socktype, proto, flags)
+    return to_opaque_object(addr)
+ll__socket_getaddrinfo.suggested_primitive = True
+
+
+# XXX The tag and the items names must have the same name as
+# the structure computed from ann_addrinfo
+ADDRINFO_RESULT = GcStruct('tuple8',
+                           ('item0', Signed),
+                           ('item1', Signed),
+                           ('item2', Signed),
+                           ('item3', Ptr(STR)),
+                           ('item4', Ptr(STR)),
+                           ('item5', Signed),
+                           ('item6', Signed),
+                           ('item7', Signed),
+                           )
+
+def ll__socket_addrinfo(family, socktype, proto, canonname,
+                        ipaddr, port, flowinfo, scopeid):
+    tup = malloc(ADDRINFO_RESULT)
+    tup.item0 = family
+    tup.item1 = socktype
+    tup.item2 = proto
+    tup.item3 = canonname
+    tup.item4 = ipaddr
+    tup.item5 = port
+    tup.item6 = flowinfo  # ipV6
+    tup.item7 = scopeid   # ipV6
+    return tup
+
+def ll__socket_nextaddrinfo(opaqueaddr):
+    addr = from_opaque_object(opaqueaddr)
+    return addr.nextinfo()
+ll__socket_nextaddrinfo.suggested_primitive = True
+
+def ll__socket_freeaddrinfo(opaqueaddr):
+    addr = from_opaque_object(opaqueaddr)
+    return addr.free()
+ll__socket_freeaddrinfo.suggested_primitive = True
+
 def ll__socket_ntohs(htons):
     return _socket.ntohs(htons)
 ll__socket_ntohs.suggested_primitive = True

Modified: pypy/dist/pypy/module/_socket/rpython/test/test_ll__socket.py
==============================================================================
--- pypy/dist/pypy/module/_socket/rpython/test/test_ll__socket.py	(original)
+++ pypy/dist/pypy/module/_socket/rpython/test/test_ll__socket.py	Tue Oct 25 02:51:56 2005
@@ -5,6 +5,7 @@
 from pypy.translator.annrpython import RPythonAnnotator
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.module.support import from_rstr
+from pypy.rpython.module.support import to_opaque_object, from_opaque_object
 
 def test_ntohs():
     def fn():
@@ -19,3 +20,12 @@
     a = RPythonAnnotator()
     res = interpret(fn, [])
     assert from_rstr(res) == _socket.gethostname()
+
+def test_getaddrinfo():
+    host = "localhost"
+    port = 25
+    result = []
+    addr = ll__socket_getaddrinfo(to_rstr(host), port, 0, 0, 0, 0)
+    info = ll__socket_nextaddrinfo(addr)
+    info = info[:4] + (info[4:],)
+    assert info == _socket.getaddrinfo(host, port)[0]

Modified: pypy/dist/pypy/translator/c/extfunc.py
==============================================================================
--- pypy/dist/pypy/translator/c/extfunc.py	(original)
+++ pypy/dist/pypy/translator/c/extfunc.py	Tue Oct 25 02:51:56 2005
@@ -58,6 +58,9 @@
     ll_stack.ll_stack_unwind: 'LL_stack_unwind',
     ll_stack.ll_stack_too_big: 'LL_stack_too_big',
     ll__socket.ll__socket_gethostname: 'LL__socket_gethostname',
+    ll__socket.ll__socket_getaddrinfo:  'LL__socket_getaddrinfo',
+    ll__socket.ll__socket_nextaddrinfo: 'LL__socket_nextaddrinfo',
+    ll__socket.ll__socket_freeaddrinfo: 'LL__socket_freeaddrinfo',
     ll__socket.ll__socket_ntohs: 'LL__socket_ntohs',
     ll__socket.ll__socket_htons: 'LL__socket_htons',
     ll__socket.ll__socket_htonl: 'LL__socket_htonl',
@@ -85,6 +88,7 @@
     yield ('RPyFREXP_RESULT', ll_math.FREXP_RESULT)
     yield ('RPyMODF_RESULT', ll_math.MODF_RESULT)
     yield ('RPySTAT_RESULT', ll_os.STAT_RESULT)
+    yield ('RPySOCKET_ADDRINFO', ll__socket.ADDRINFO_RESULT)
 
 def predeclare_utility_functions(db, rtyper):
     # Common utility functions
@@ -123,6 +127,10 @@
     yield annotate(ll_math.ll_modf_result, lltype.Float, lltype.Float)
     yield annotate(ll_os.ll_stat_result, *([lltype.Signed] * 10))
 
+    args = [lltype.Signed, lltype.Signed, lltype.Signed, lltype.Ptr(STR),
+            lltype.Ptr(STR), lltype.Signed, lltype.Signed, lltype.Signed]
+    yield annotate(ll__socket.ll__socket_addrinfo, *args)
+
 def predeclare_extfuncs(db, rtyper):
     for func, funcobj in db.externalfuncs.items():
         c_name = EXTERNALS[func]

Modified: pypy/dist/pypy/translator/c/src/ll__socket.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/ll__socket.h	(original)
+++ pypy/dist/pypy/translator/c/src/ll__socket.h	Tue Oct 25 02:51:56 2005
@@ -9,41 +9,40 @@
 int LL__socket_htons(int ntohs);
 long LL__socket_ntohl(long htonl);
 long LL__socket_htonl(long ntohl);
+struct RPyOpaque_ADDRINFO *LL__socket_getaddrinfo(RPyString *host, RPyString *port, 
+						  int family, int socktype, 
+						  int proto, int flags);
+RPySOCKET_ADDRINFO *LL__socket_nextaddrinfo(struct RPyOpaque_ADDRINFO *addr);
 
 #ifndef PYPY_NOT_MAIN_FILE
+#ifdef MS_WINDOWS
+# include <Ws2tcpip.h>
+#endif
 
 int LL__socket_ntohs(int htons)
 {
-
     return (int)ntohs((short) htons);
-
 }
 
 int LL__socket_htons(int ntohs)
 {
-
     return (int)htons((short) ntohs);
-
 }
 
 long LL__socket_ntohl(long htonl)
 {
-
     return ntohl(htonl);
-
 }
 
 long LL__socket_htonl(long ntohl)
 {
-
     return htonl(ntohl);
-
 }
 
 RPyString *LL__socket_gethostname()
 {
 	char buf[1024];
-	char *res;
+	int res;
 	res = gethostname(buf, sizeof buf - 1);
 	if (res < 0) {
 		//XXX
@@ -56,4 +55,78 @@
 	return RPyString_FromString(buf);
 }
 
+struct RPyOpaque_ADDRINFO {
+	struct addrinfo *info0;
+	struct addrinfo *info;
+};
+
+struct RPyOpaque_ADDRINFO *LL__socket_getaddrinfo(RPyString *host, RPyString *port, 
+						  int family, int socktype, 
+						  int proto, int flags) 
+{
+	struct addrinfo hints;
+	struct addrinfo *res0;
+	struct RPyOpaque_ADDRINFO *addr;
+	int error;
+	char *hptr = RPyString_AsString(host);
+	char *pptr = RPyString_AsString(port);
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = family;
+	hints.ai_socktype = socktype;
+	hints.ai_protocol = proto;
+	hints.ai_flags = flags;
+	error = getaddrinfo(hptr, pptr, &hints, &res0);
+	addr = malloc(sizeof (struct RPyOpaque_ADDRINFO));
+	addr->info0 = res0;
+	addr->info  = res0;
+	return addr;
+}
+
+RPyString *makeipaddr(struct sockaddr *addr)
+{
+	char buf[NI_MAXHOST];
+	int error;
+
+	error = getnameinfo(addr, sizeof (struct sockaddr), buf, sizeof(buf), NULL, 0,
+		NI_NUMERICHOST);
+	if (error) {
+		return RPyString_FromString("Error"); // XXX
+	}
+	return RPyString_FromString(buf);
+}
+
+RPySOCKET_ADDRINFO *LL__socket_nextaddrinfo(struct RPyOpaque_ADDRINFO *addr)
+{
+	struct addrinfo *info = addr->info;
+
+	if( !info )
+		return ll__socket_addrinfo(0,0,0,NULL,NULL,0,0,0);
+
+	addr->info = addr->info->ai_next;
+
+	{
+		RPySOCKET_ADDRINFO *ret;
+		struct sockaddr_in *a = (struct sockaddr_in *)info->ai_addr;
+
+		RPyString *canonname = RPyString_FromString(
+			info->ai_canonname?info->ai_canonname:"");
+		RPyString *ipaddr = makeipaddr(info->ai_addr);
+
+		ret = ll__socket_addrinfo(info->ai_family,
+					  info->ai_socktype,
+					  info->ai_protocol,
+					  canonname,
+					  ipaddr, // XXX AF_INET Only!
+					  ntohs(a->sin_port),0,0);
+		// XXX DECREF(canonname)
+		// XXX DECREF(ipaddr)
+	}
+}
+
+void LL__socket_freeaddrinfo(struct RPyOpaque_ADDRINFO *addr)
+{
+	freeaddrinfo(addr->info0);
+	free(addr2);
+}
 #endif

Modified: pypy/dist/pypy/translator/c/test/test_extfunc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_extfunc.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_extfunc.py	Tue Oct 25 02:51:56 2005
@@ -562,3 +562,24 @@
     res = f1()
     assert res == _socket.gethostname()
 
+def test_getaddrinfo():
+    #py.test.skip("In progress")
+    # XXX fails on 'assert mallocs == frees'
+    # needs a way to decref rstrings from ll__socket.h
+    import pypy.module._socket.rpython.exttable   # for declare()/declaretype()
+    from pypy.module._socket.rpython import rsocket
+    def does_stuff(host, port):
+        addr = rsocket.getaddrinfo(host, port, 0, 0, 0, 0)
+        result = []
+        while True: 
+            info = addr.nextinfo()
+            if info[0] == 0:
+                break
+            result.append("(%d, %d, %d, '%s', ('%s', %d))" %
+                          (info[0],info[1],info[2],info[3],info[4],info[5]))
+        addr.free()
+        return str(result)
+    f1 = compile(does_stuff, [str, str])
+    res = f1("localhost", "25")
+    assert eval(res) == _socket.getaddrinfo("localhost", "25")
+



More information about the Pypy-commit mailing list