qmsk/net/socket/address.pyx
changeset 22 f6e8d5e37998
parent 20 0e4933d5862e
child 23 15d8bb96b8d4
equal deleted inserted replaced
21:19d212c948e0 22:f6e8d5e37998
     1 cimport qmsk.net.libc as libc
     1 cimport qmsk.net.libc as libc
       
     2 cimport qmsk.net.py as py
     2 
     3 
     3 from qmsk.net.socket.address cimport *
     4 from qmsk.net.socket.address cimport *
     4 
     5 
     5 cimport qmsk.net.socket.platform as platform
     6 cimport qmsk.net.socket.platform as platform
     6 
     7 
   104         '127.0.0.1'
   105         '127.0.0.1'
   105         >>> sa.port
   106         >>> sa.port
   106         80
   107         80
   107         >>> str(sa)
   108         >>> str(sa)
   108         '127.0.0.1:80'
   109         '127.0.0.1:80'
   109         >>> str(sockaddr_in())
   110 
   110         '0.0.0.0:0'
   111         >>> sockaddr_in('2001::5')
       
   112         Traceback (most recent call last):
       
   113           ...
       
   114         NameError: Invalid network address for specified address family: '2001::5'
       
   115 
   111     """
   116     """
   112 
   117 
   113     # the struct sockaddr_in
   118     # the struct sockaddr_in
   114     cdef platform.sockaddr_in sockaddr
   119     cdef platform.sockaddr_in sockaddr
   115 
   120 
   118             Construct using given literal IPv4 address and TCP/UDP port
   123             Construct using given literal IPv4 address and TCP/UDP port
   119 
   124 
   120                 addr        - IPv4 address, defaults to INADDR_ANY (0.0.0.0)
   125                 addr        - IPv4 address, defaults to INADDR_ANY (0.0.0.0)
   121                 port        - TCP/UDP port, defaults to 0 (ephemeral)
   126                 port        - TCP/UDP port, defaults to 0 (ephemeral)
   122         """
   127         """
       
   128 
       
   129         # zero
       
   130         libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr))
   123 
   131 
   124         # store our family
   132         # store our family
   125         # XXX: this should be a class attribute...
   133         # XXX: this should be a class attribute...
   126         self._init_family(platform.AF_INET)
   134         self._init_family(platform.AF_INET)
   127 
   135 
   160         """
   168         """
   161 
   169 
   162         def __get__ (self) :
   170         def __get__ (self) :
   163             return platform.ntohs(self.sockaddr.sin_port)
   171             return platform.ntohs(self.sockaddr.sin_port)
   164 
   172 
       
   173     def __cmp__ (self, other_obj) :
       
   174         """
       
   175             A sockaddr_in is equal to any other sockaddr_in which has the same addr and port
       
   176             
       
   177             >>> assert sockaddr_in() == sockaddr_in()
       
   178             >>> assert sockaddr_in('127.0.0.1', 80) == sockaddr_in('127.0.0.1', 80)
       
   179             >>> addr = sockaddr_in(); assert addr == addr
       
   180         """
       
   181 
       
   182         if not isinstance(other_obj, sockaddr_in) :
       
   183             return <object> py.Py_NotImplemented
       
   184 
       
   185         cdef sockaddr_in other = other_obj
       
   186         cdef platform.sockaddr_in *sa1 = &self.sockaddr, *sa2 = &other.sockaddr
       
   187 
       
   188         if other is self :
       
   189             return 0
       
   190 
       
   191         return (
       
   192                 libc.memcmp(<void *> &sa1.sin_port, <void *> &sa2.sin_port, sizeof(sa1.sin_port))
       
   193             or  libc.memcmp(<void *> &sa1.sin_addr, <void *> &sa2.sin_addr, sizeof(sa1.sin_addr))
       
   194         )
       
   195 
   165     def __str__ (self) :
   196     def __str__ (self) :
   166         """
   197         """
   167             Return the literal ASCII representation for this sockaddr as an '<addr>:<port> string
   198             Return the literal ASCII representation for this sockaddr as an '<addr>:<port> string
       
   199         
       
   200             >>> str(sockaddr_in())
       
   201             '0.0.0.0:0'
   168         """
   202         """
   169         
   203         
   170         # format
   204         # format
   171         return "%s:%s" % self.getnameinfo()
   205         return "%s:%s" % self.getnameinfo()
   172 
   206 
   179         '::1'
   213         '::1'
   180         >>> sa6.port
   214         >>> sa6.port
   181         80
   215         80
   182         >>> str(sa6)
   216         >>> str(sa6)
   183         '[::1]:80'
   217         '[::1]:80'
   184         >>> str(sockaddr_in6())
   218         
   185         '[::]:0'
       
   186     """
   219     """
   187 
   220 
   188     cdef platform.sockaddr_in6 sockaddr
   221     cdef platform.sockaddr_in6 sockaddr
   189 
   222 
   190     def __init__ (self, object addr=None, platform.in_port_t port=0) :
   223     def __init__ (self, object addr=None, platform.in_port_t port=0, unsigned int scope_id = 0) :
   191         """
   224         """
   192             Construct using given literal IPv6 address and TCP/UDP port
   225             Construct using given literal IPv6 address and TCP/UDP port
   193 
   226 
   194                 addr        - IPv6 address, defaults to platform.in6addr_any (::)
   227                 addr        - IPv6 address, defaults to platform.in6addr_any (::)
   195                 port        - TCP/UDP port, defaults to 0 (ephemeral)
   228                 port        - TCP/UDP port, defaults to 0 (ephemeral)
   196         """
   229                 scope_id    - (optional) scope ID representing interface index for link-local addresses
       
   230         """
       
   231 
       
   232         # zero
       
   233         libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr))
   197 
   234 
   198         # store our family
   235         # store our family
   199         # XXX: this should be a class attribute...
   236         # XXX: this should be a class attribute...
   200         self._init_family(platform.AF_INET6)
   237         self._init_family(platform.AF_INET6)
   201 
   238 
   212 
   249 
   213         else :
   250         else :
   214             # set as INADDR_ANY
   251             # set as INADDR_ANY
   215             self.sockaddr.sin6_addr = platform.in6addr_any
   252             self.sockaddr.sin6_addr = platform.in6addr_any
   216 
   253 
       
   254         # scope ID
       
   255         self.sockaddr.sin6_scope_id = scope_id
       
   256 
   217     cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 :
   257     cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 :
   218         if sa_ptr :
   258         if sa_ptr :
   219             sa_ptr[0] = <platform.sockaddr *> &self.sockaddr
   259             sa_ptr[0] = <platform.sockaddr *> &self.sockaddr
   220 
   260 
   221         if sa_len :
   261         if sa_len :
   228 
   268 
   229         libc.memcpy(&self.sockaddr, sa, sa_len)
   269         libc.memcpy(&self.sockaddr, sa, sa_len)
   230 
   270 
   231     property port :
   271     property port :
   232         """
   272         """
   233             The integer port number
   273             The integer port number.
       
   274 
       
   275             This will represent it correctly in host byte order.
   234         """
   276         """
   235 
   277 
   236         def __get__ (self) :
   278         def __get__ (self) :
   237             return platform.ntohs(self.sockaddr.sin6_port)
   279             return platform.ntohs(self.sockaddr.sin6_port)
   238 
   280 
   239 
   281 
       
   282     property flowinfo :
       
   283         """
       
   284             The integer flowinfo
       
   285 
       
   286             XXX: byteorder?
       
   287         """
       
   288 
       
   289         def __get__ (self) :
       
   290             return self.sockaddr.sin6_flowinfo
       
   291 
       
   292 
       
   293     property scope_id :
       
   294         """
       
   295             The scope ID - corresponds to an interface index for link-scope addresses.
       
   296 
       
   297             This should be in host byte order...
       
   298         """
       
   299 
       
   300         def __get__ (self) :
       
   301             return self.sockaddr.sin6_scope_id
       
   302 
       
   303     def __cmp__ (self, other_obj) :
       
   304         """
       
   305             A sockaddr_in6 is equal to any other sockaddr_in6 which has the same addr, port and scope ID.
       
   306 
       
   307             XXX: flowinfo?
       
   308 
       
   309             XXX: A sockaddr_in6 is also equal to a sockaddr_in if the sockaddr_in6 represents the given v4-mapped address.
       
   310             
       
   311             >>> assert sockaddr_in6() == sockaddr_in6()
       
   312             >>> assert sockaddr_in6('0:0:0::1', 80) == sockaddr_in6('::1', 80)
       
   313             >>> assert sockaddr_in6('::127.0.0.1') == sockaddr_in('127.0.0.1')
       
   314         """
       
   315 
       
   316         if not isinstance(other_obj, sockaddr_in6) :
       
   317             return <object> py.Py_NotImplemented
       
   318 
       
   319         cdef sockaddr_in6 other = other_obj
       
   320         cdef platform.sockaddr_in6 *sa1 = &self.sockaddr, *sa2 = &other.sockaddr
       
   321 
       
   322         if other is self :
       
   323             return 0
       
   324 
       
   325         return (
       
   326                 libc.memcmp(<void *> &sa1.sin6_port,        <void *> &sa2.sin6_port,        sizeof(sa1.sin6_port))
       
   327             or  libc.memcmp(<void *> &sa1.sin6_addr,        <void *> &sa2.sin6_addr,        sizeof(sa1.sin6_addr))
       
   328             or  libc.memcmp(<void *> &sa1.sin6_scope_id,    <void *> &sa2.sin6_scope_id,    sizeof(sa1.sin6_scope_id))
       
   329         )
       
   330 
   240     def __str__ (self) :
   331     def __str__ (self) :
   241         """
   332         """
   242             Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> string
   333             Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> string
   243         """
   334 
   244         
   335             >>> str(sockaddr_in6())
   245         # format
   336             '[::]:0'
   246         return "[%s]:%s" % self.getnameinfo()
   337 
       
   338             >>> str(sockaddr_in6('2001:0::05:1'))
       
   339             '[2001::5:1]'
       
   340 
       
   341             >>> str(sockaddr_in6('fe80::abcd', scope_id=5))
       
   342             '[fe80::abcd%5]'
       
   343         """
       
   344 
       
   345         addr, port = self.getnameinfo()
       
   346         scope_id = self.scope_id
       
   347 
       
   348         # format with scope_id
       
   349         return "[%s%s]:%s" % (
       
   350             addr,
       
   351             "%%%d" % scope_id if scope_id else "",
       
   352             port
       
   353         )
   247 
   354 
   248 # mapping of AF -> sockaddr, user-modifyable
   355 # mapping of AF -> sockaddr, user-modifyable
   249 SOCKADDR_BY_FAMILY = {
   356 SOCKADDR_BY_FAMILY = {
   250     platform.AF_INET:   sockaddr_in,
   357     platform.AF_INET:   sockaddr_in,
   251     platform.AF_INET6:  sockaddr_in6,
   358     platform.AF_INET6:  sockaddr_in6,