qmsk/net/socket/address.pyx
changeset 24 f18b5787c46c
parent 23 15d8bb96b8d4
child 27 12468e38227e
equal deleted inserted replaced
23:15d8bb96b8d4 24:f18b5787c46c
    97             return int(port)
    97             return int(port)
    98     
    98     
    99     def __repr__ (self) :
    99     def __repr__ (self) :
   100         return "sockaddr(%d, %s, %d)" % (self.family, self.addr, self.port)
   100         return "sockaddr(%d, %s, %d)" % (self.family, self.addr, self.port)
   101 
   101 
   102 cdef class sockaddr_in (sockaddr) :
       
   103     """
       
   104         AF_INET struct sockaddr_in
       
   105 
       
   106         >>> sa = sockaddr_in("127.0.0.1", 80)
       
   107         >>> sa.addr
       
   108         '127.0.0.1'
       
   109         >>> sa.port
       
   110         80
       
   111         >>> str(sa)
       
   112         '127.0.0.1:80'
       
   113 
       
   114         >>> sockaddr_in('2001::5')
       
   115         Traceback (most recent call last):
       
   116           ...
       
   117         NameError: Invalid network address for specified address family: '2001::5'
       
   118 
       
   119     """
       
   120 
       
   121     # the struct sockaddr_in
       
   122     cdef platform.sockaddr_in sockaddr
       
   123 
       
   124     def __init__ (self, object addr=None, platform.in_port_t port=0) :
       
   125         """
       
   126             Construct using given literal IPv4 address and TCP/UDP port
       
   127 
       
   128                 addr        - IPv4 address, defaults to INADDR_ANY (0.0.0.0)
       
   129                 port        - TCP/UDP port, defaults to 0 (ephemeral)
       
   130         """
       
   131 
       
   132         # zero
       
   133         libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr))
       
   134 
       
   135         # store our family
       
   136         # XXX: this should be a class attribute...
       
   137         self._init_family(platform.AF_INET)
       
   138 
       
   139         # constant af
       
   140         self.sockaddr.sin_family = self.family
       
   141         
       
   142         # set the sin_port
       
   143         self.sockaddr.sin_port = platform.htons(port)
       
   144         
       
   145         if addr :
       
   146             # set the sin_addr
       
   147             # this automatically converts the addr from str -> char *
       
   148             platform.inet_pton(self.family, addr, &self.sockaddr.sin_addr)
       
   149 
       
   150         else :
       
   151             # set as INADDR_ANY
       
   152             self.sockaddr.sin_addr.s_addr = platform.INADDR_ANY
       
   153     
       
   154     cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 :
       
   155         if sa_ptr :
       
   156             sa_ptr[0] = <platform.sockaddr *> &self.sockaddr
       
   157 
       
   158         if sa_len :
       
   159             sa_len[0] = sizeof(self.sockaddr)
       
   160 
       
   161         return 0
       
   162 
       
   163     cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 :
       
   164         assert sa_len == sizeof(self.sockaddr)
       
   165 
       
   166         libc.memcpy(&self.sockaddr, sa, sa_len)
       
   167 
       
   168     property port :
       
   169         """
       
   170             The integer port number
       
   171 
       
   172             >>> sockaddr_in(port=1234).port
       
   173             1234
       
   174         """
       
   175 
       
   176         def __get__ (self) :
       
   177             return platform.ntohs(self.sockaddr.sin_port)
       
   178 
       
   179     def __cmp__ (self, other_obj) :
       
   180         """
       
   181             A sockaddr_in is equal to any other sockaddr_in which has the same addr and port
       
   182             
       
   183             >>> assert sockaddr_in() == sockaddr_in()
       
   184             >>> assert sockaddr_in('127.0.0.1', 80) == sockaddr_in('127.0.0.1', 80)
       
   185             >>> addr = sockaddr_in(); assert addr == addr
       
   186         """
       
   187 
       
   188         if not isinstance(other_obj, sockaddr_in) :
       
   189             return <object> py.Py_NotImplemented
       
   190 
       
   191         cdef sockaddr_in other = other_obj
       
   192         cdef platform.sockaddr_in *sa1 = &self.sockaddr, *sa2 = &other.sockaddr
       
   193 
       
   194         if other is self :
       
   195             return 0
       
   196 
       
   197         return (
       
   198                 libc.memcmp(<void *> &sa1.sin_port, <void *> &sa2.sin_port, sizeof(sa1.sin_port))
       
   199             or  libc.memcmp(<void *> &sa1.sin_addr, <void *> &sa2.sin_addr, sizeof(sa1.sin_addr))
       
   200         )
       
   201 
       
   202     def __str__ (self) :
       
   203         """
       
   204             Return the literal ASCII representation for this sockaddr as an '<addr>:<port> string
       
   205         
       
   206             >>> str(sockaddr_in())
       
   207             '0.0.0.0:0'
       
   208         """
       
   209         
       
   210         # format
       
   211         return "%s:%s" % self.getnameinfo()
       
   212 
       
   213 cdef class sockaddr_in6 (sockaddr) :
       
   214     """
       
   215         AF_INET6 struct sockaddr_in6
       
   216 
       
   217         >>> sa6 = sockaddr_in6("::1", 80)
       
   218         >>> sa6.addr
       
   219         '::1'
       
   220         >>> sa6.port
       
   221         80
       
   222         >>> str(sa6)
       
   223         '[::1]:80'
       
   224         
       
   225     """
       
   226 
       
   227     cdef platform.sockaddr_in6 sockaddr
       
   228 
       
   229     def __init__ (self, object addr=None, platform.in_port_t port=0, unsigned int scope_id = 0) :
       
   230         """
       
   231             Construct using given literal IPv6 address and TCP/UDP port
       
   232 
       
   233                 addr        - IPv6 address, defaults to platform.in6addr_any (::)
       
   234                 port        - TCP/UDP port, defaults to 0 (ephemeral)
       
   235                 scope_id    - (optional) scope ID representing interface index for link-local addresses
       
   236         """
       
   237 
       
   238         # zero
       
   239         libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr))
       
   240 
       
   241         # store our family
       
   242         # XXX: this should be a class attribute...
       
   243         self._init_family(platform.AF_INET6)
       
   244 
       
   245         # constant af
       
   246         self.sockaddr.sin6_family = self.family
       
   247         
       
   248         # set the sin_port
       
   249         self.sockaddr.sin6_port = platform.htons(port)
       
   250         
       
   251         if addr :
       
   252             # set the sin_addr
       
   253             # this automatically converts the addr from str -> char *
       
   254             platform.inet_pton(self.family, addr, &self.sockaddr.sin6_addr)
       
   255 
       
   256         else :
       
   257             # set as INADDR_ANY
       
   258             self.sockaddr.sin6_addr = platform.in6addr_any
       
   259 
       
   260         # scope ID
       
   261         self.sockaddr.sin6_scope_id = scope_id
       
   262 
       
   263     cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 :
       
   264         if sa_ptr :
       
   265             sa_ptr[0] = <platform.sockaddr *> &self.sockaddr
       
   266 
       
   267         if sa_len :
       
   268             sa_len[0] = sizeof(self.sockaddr)
       
   269 
       
   270         return 0
       
   271 
       
   272     cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 :
       
   273         assert sa_len == sizeof(self.sockaddr)
       
   274 
       
   275         libc.memcpy(&self.sockaddr, sa, sa_len)
       
   276 
       
   277     property port :
       
   278         """
       
   279             The integer port number.
       
   280 
       
   281             This will represent it correctly in host byte order.
       
   282 
       
   283             >>> sockaddr_in6(port=1234).port
       
   284             1234
       
   285         """
       
   286 
       
   287         def __get__ (self) :
       
   288             return platform.ntohs(self.sockaddr.sin6_port)
       
   289 
       
   290 
       
   291     property flowinfo :
       
   292         """
       
   293             The integer flowinfo
       
   294 
       
   295             XXX: byteorder?
       
   296             
       
   297             >>> sockaddr_in6().flowinfo
       
   298             0
       
   299         """
       
   300 
       
   301         def __get__ (self) :
       
   302             return self.sockaddr.sin6_flowinfo
       
   303 
       
   304 
       
   305     property scope_id :
       
   306         """
       
   307             The scope ID - corresponds to an interface index for link-scope addresses.
       
   308 
       
   309             This should be in host byte order...
       
   310 
       
   311             >>> sockaddr_in6(scope_id=1337).scope_id
       
   312             1337
       
   313         """
       
   314 
       
   315         def __get__ (self) :
       
   316             return self.sockaddr.sin6_scope_id
       
   317 
       
   318     def __cmp__ (self, other_obj) :
       
   319         """
       
   320             A sockaddr_in6 is equal to any other sockaddr_in6 which has the same addr, port and scope ID.
       
   321 
       
   322             XXX: flowinfo?
       
   323 
       
   324             XXX: A sockaddr_in6 is also equal to a sockaddr_in if the sockaddr_in6 represents the given v4-mapped address.
       
   325             
       
   326             >>> assert sockaddr_in6() == sockaddr_in6()
       
   327             >>> assert sockaddr_in6('0:0:0::1', 80) == sockaddr_in6('::1', 80)
       
   328             >>> assert sockaddr_in6('::127.0.0.1') == sockaddr_in('127.0.0.1')
       
   329         """
       
   330 
       
   331         if not isinstance(other_obj, sockaddr_in6) :
       
   332             return <object> py.Py_NotImplemented
       
   333 
       
   334         cdef sockaddr_in6 other = other_obj
       
   335         cdef platform.sockaddr_in6 *sa1 = &self.sockaddr, *sa2 = &other.sockaddr
       
   336 
       
   337         if other is self :
       
   338             return 0
       
   339 
       
   340         return (
       
   341                 libc.memcmp(<void *> &sa1.sin6_port,        <void *> &sa2.sin6_port,        sizeof(sa1.sin6_port))
       
   342             or  libc.memcmp(<void *> &sa1.sin6_addr,        <void *> &sa2.sin6_addr,        sizeof(sa1.sin6_addr))
       
   343             or  libc.memcmp(<void *> &sa1.sin6_scope_id,    <void *> &sa2.sin6_scope_id,    sizeof(sa1.sin6_scope_id))
       
   344         )
       
   345 
       
   346     def __str__ (self) :
       
   347         """
       
   348             Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> string
       
   349 
       
   350             >>> str(sockaddr_in6())
       
   351             '[::]:0'
       
   352 
       
   353             >>> str(sockaddr_in6('2001:0::05:1'))
       
   354             '[2001::5:1]'
       
   355 
       
   356             >>> str(sockaddr_in6('fe80::abcd', scope_id=5))
       
   357             '[fe80::abcd%5]'
       
   358         """
       
   359 
       
   360         addr, port = self.getnameinfo()
       
   361         scope_id = self.scope_id
       
   362 
       
   363         # format with scope_id
       
   364         return "[%s%s]:%s" % (
       
   365             addr,
       
   366             "%%%d" % scope_id if scope_id else "",
       
   367             port
       
   368         )
       
   369 
       
   370 # mapping of AF -> sockaddr, user-modifyable
   102 # mapping of AF -> sockaddr, user-modifyable
       
   103 cimport qmsk.net.socket.af_inet, qmsk.net.socket.af_inet6
       
   104 
   371 SOCKADDR_BY_FAMILY = {
   105 SOCKADDR_BY_FAMILY = {
   372     platform.AF_INET:   sockaddr_in,
   106     platform.AF_INET:   qmsk.net.socket.af_inet.sockaddr_in,
   373     platform.AF_INET6:  sockaddr_in6,
   107     platform.AF_INET6:  qmsk.net.socket.af_inet6.sockaddr_in6,
   374 }
   108 }
   375 
   109 
   376 # build a sockaddr from the given sockaddr struct, based on sa_family
   110 # build a sockaddr from the given sockaddr struct, based on sa_family
   377 cdef sockaddr build_sockaddr (platform.sockaddr *sa, size_t sa_len) :
   111 cdef sockaddr build_sockaddr (platform.sockaddr *sa, size_t sa_len) :
   378     # lookup correct class to use
   112     # lookup correct class to use