fix up addrinfo to hold a real platform.addrinfo, storing ai_addr/ai_canonname as objects
authorTero Marttila <terom@fixme.fi>
Tue, 18 Aug 2009 22:24:36 +0300
changeset 23 15d8bb96b8d4
parent 22 f6e8d5e37998
child 24 f18b5787c46c
fix up addrinfo to hold a real platform.addrinfo, storing ai_addr/ai_canonname as objects
qmsk/net/socket/address.pxd
qmsk/net/socket/address.pyx
--- a/qmsk/net/socket/address.pxd	Mon Aug 17 20:24:12 2009 +0300
+++ b/qmsk/net/socket/address.pxd	Tue Aug 18 22:24:36 2009 +0300
@@ -49,15 +49,32 @@
 
 cdef class addrinfo :
     """
-        A socket-level endpoint address, which contains the full socket parameters and an bind/connect address
-    """
+        A socket-level endpoint address, which contains the full socket parameters and an bind/connect address.
+        
+        A full addrinfo struct is stored, but ai_canonname and ai_addr are stored as (optional) objects outside of the
+        addrinfo struct.
 
-#    cdef readonly int flags
-    cdef readonly int family, socktype, protocol
-    cdef readonly sockaddr addr
-    cdef readonly object canonname
+        >>> ai = addrinfo()
+        >>> ai.addr
+        >>> ai.canonname
+        >>> print addrinfo(addr=sockaddr_in())
+        family=0, socktype=0, protocol=0, addr=0.0.0.0:0, canonname=None
+    """
+    
+    # canonname is not stored
+    # may be NULL
+    cdef platform.addrinfo ai
 
-    cdef _init_addrinfo (self, platform.addrinfo *c_ai)
+    # may be NULL
+    cdef sockaddr ai_addr
+    cdef object ai_canonname
+   
+    # update self.ai.ai_* to reflect self.ai_*
+    cdef _init_ai_members (self)
+
+    # set the contents of self.ai from the given real addrinfo
+    # this ignores the ai_canonname attribute
+    cdef _init_addrinfo (self, platform.addrinfo *ai)
 
 # build and return a new addrinfo instance
 cdef addrinfo build_addrinfo (platform.addrinfo *c_ai)
--- a/qmsk/net/socket/address.pyx	Mon Aug 17 20:24:12 2009 +0300
+++ b/qmsk/net/socket/address.pyx	Tue Aug 18 22:24:36 2009 +0300
@@ -51,6 +51,9 @@
     def getnameinfo (self) :
         """
             Returns a (host, serv) tuple for this address à la getnameinfo
+
+            >>> addr = sockaddr_in()
+            >>> assert addr.getnameinfo() == (addr.addr, str(addr.port))
         """
 
         cdef platform.sockaddr *sa
@@ -165,6 +168,9 @@
     property port :
         """
             The integer port number
+
+            >>> sockaddr_in(port=1234).port
+            1234
         """
 
         def __get__ (self) :
@@ -273,6 +279,9 @@
             The integer port number.
 
             This will represent it correctly in host byte order.
+
+            >>> sockaddr_in6(port=1234).port
+            1234
         """
 
         def __get__ (self) :
@@ -284,6 +293,9 @@
             The integer flowinfo
 
             XXX: byteorder?
+            
+            >>> sockaddr_in6().flowinfo
+            0
         """
 
         def __get__ (self) :
@@ -295,6 +307,9 @@
             The scope ID - corresponds to an interface index for link-scope addresses.
 
             This should be in host byte order...
+
+            >>> sockaddr_in6(scope_id=1337).scope_id
+            1337
         """
 
         def __get__ (self) :
@@ -372,14 +387,95 @@
     return addr
 
 cdef class addrinfo :
+ 
+    cdef _init_ai_members (self) :
+        """
+            Update self.ai.ai_* to reflect self.ai_*
+        """
+
+        cdef platform.socklen_t addr_len
+
+        if self.ai_addr is not None :
+            self.ai_addr._get_sockaddr(&self.ai.ai_addr, &addr_len)
+            self.ai.ai_addrlen = addr_len
+
+        else :
+            self.ai.ai_addr = NULL
+            self.ai.ai_addrlen = 0
+        
+        if self.ai_canonname is not None :
+            self.ai.ai_canonname = self.ai_canonname
+
+        else :
+            self.ai.ai_canonname = NULL
     
+    def __init__ (self, int flags = 0, int family = 0, int socktype = 0, int protocol = 0, sockaddr addr = None, object canonname = None) :
+        """
+            Construct a new addrinfo with the given parameters
+        """
+
+
+        self.ai.ai_flags = flags
+        self.ai.ai_family = family
+        self.ai.ai_socktype = socktype
+        self.ai.ai_protocol = protocol
+
+        self.ai_addr = addr
+
+        if canonname is not None :
+            self.ai_canonname = str(canonname)
+
+        else :
+            self.ai_canonname = None
+
+        # update self.ai
+        self._init_ai_members()
+        
     cdef _init_addrinfo (self, platform.addrinfo *ai) :
-        #ai.flags = c_ai.ai_flags
-        self.family = ai.ai_family
-        self.socktype = ai.ai_socktype
-        self.protocol = ai.ai_protocol
-        self.addr = build_sockaddr(ai.ai_addr, ai.ai_addrlen)
-        self.canonname = ai.ai_canonname if ai.ai_canonname else None
+        """
+            Re-initialize this addrinfo's parameters from the given addrinfo
+        """
+        
+        # copy raw
+        self.ai = ai[0]
+        
+        # store copies of external objects
+        if ai.ai_addr :
+            # copy addr as object
+            self.ai_addr = build_sockaddr(ai.ai_addr, ai.ai_addrlen)
+            
+        else :
+            self.ai_addr = None
+
+        if ai.ai_canonname :
+            # copy as object
+            self.ai_canonname = ai.ai_canonname
+            
+        else :
+            self.ai_canonname = None
+
+        # update self.ai
+        self._init_ai_members()
+
+    property flags :
+        def __get__ (self) : return self.ai.ai_flags
+
+    property family :
+        def __get__ (self) : return self.ai.ai_family
+
+    property socktype :
+        def __get__ (self) : return self.ai.ai_socktype
+    
+    property protocol :
+        def __get__ (self) : return self.ai.ai_protocol
+    
+    property addr :
+        # XXX: None?
+        def __get__ (self) : return self.ai_addr
+    
+    property canonname :
+        # XXX: None?
+        def __get__ (self) : return self.ai_canonname
 
     def __str__ (self) :
         return "family=%d, socktype=%d, protocol=%d, addr=%s, canonname=%s" % (self.family, self.socktype, self.protocol, self.addr, self.canonname)
@@ -442,7 +538,7 @@
                 # XXX: raise a GAIError
                 raise Exception(platform.gai_strerror(err))
             
-            # gather results
+            # gather results from linked list to PyList
             r = res
 
             while r :