sock/addr.pyx
changeset 5 59bed837c265
parent 2 171e77f8d675
equal deleted inserted replaced
4:664a1dfe08ac 5:59bed837c265
     8 
     8 
     9 cdef class sockaddr :
     9 cdef class sockaddr :
    10     cdef void _init_family (self, libc.sa_family_t family=libc.AF_UNSPEC) :
    10     cdef void _init_family (self, libc.sa_family_t family=libc.AF_UNSPEC) :
    11         self.family = family
    11         self.family = family
    12 
    12 
       
    13     # XXX:use size_t
    13     cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 :
    14     cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 :
    14         """
    15         """
    15             Get the sockaddr pointer and sockaddr length for this address
    16             Get the sockaddr pointer and sockaddr length for this address
    16         """ 
    17         """ 
    17 
    18 
    38         cdef libc.socklen_t sa_len
    39         cdef libc.socklen_t sa_len
    39 
    40 
    40         self._get_sockaddr(&sa, &sa_len)
    41         self._get_sockaddr(&sa, &sa_len)
    41 
    42 
    42         return sa_len
    43         return sa_len
       
    44 
       
    45     cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 :
       
    46         """
       
    47             Set the sockaddr value for this address; sa_len must match!
       
    48         """
       
    49 
       
    50         raise NotImplementedError()
    43 
    51 
    44     def getnameinfo (self) :
    52     def getnameinfo (self) :
    45         """
    53         """
    46             Returns a (host, serv) tuple for this address à la getnameinfo
    54             Returns a (host, serv) tuple for this address à la getnameinfo
    47         """
    55         """
   138         if sa_len :
   146         if sa_len :
   139             sa_len[0] = sizeof(self.sockaddr)
   147             sa_len[0] = sizeof(self.sockaddr)
   140 
   148 
   141         return 0
   149         return 0
   142 
   150 
       
   151     cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 :
       
   152         assert sa_len == sizeof(self.sockaddr)
       
   153 
       
   154         libc.memcpy(&self.sockaddr, sa, sa_len)
       
   155 
   143     property port :
   156     property port :
   144         """
   157         """
   145             The integer port number
   158             The integer port number
   146         """
   159         """
   147 
   160 
   207         if sa_len :
   220         if sa_len :
   208             sa_len[0] = sizeof(self.sockaddr)
   221             sa_len[0] = sizeof(self.sockaddr)
   209 
   222 
   210         return 0
   223         return 0
   211 
   224 
       
   225     cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 :
       
   226         assert sa_len == sizeof(self.sockaddr)
       
   227 
       
   228         libc.memcpy(&self.sockaddr, sa, sa_len)
       
   229 
   212     property port :
   230     property port :
   213         """
   231         """
   214             The integer port number
   232             The integer port number
   215         """
   233         """
   216 
   234 
   224         """
   242         """
   225         
   243         
   226         # format
   244         # format
   227         return "[%s]:%s" % self.getnameinfo()
   245         return "[%s]:%s" % self.getnameinfo()
   228 
   246 
       
   247 # mapping of AF -> sockaddr, user-modifyable
       
   248 SOCKADDR_BY_FAMILY = {
       
   249     libc.AF_INET:   sockaddr_in,
       
   250     libc.AF_INET6:  sockaddr_in6,
       
   251 }
       
   252 
       
   253 # build a sockaddr from the given sockaddr struct, based on sa_family
       
   254 cdef sockaddr build_sockaddr (libc.sockaddr *sa, size_t sa_len) :
       
   255     # lookup correct class to use
       
   256     addr_type = SOCKADDR_BY_FAMILY[sa.sa_family]
       
   257     
       
   258     # construct with defaults
       
   259     cdef sockaddr addr = addr_type()
       
   260 
       
   261     # store
       
   262     addr._set_sockaddr(sa, sa_len)
       
   263 
       
   264     return addr
       
   265 
       
   266 cdef class addrinfo :
       
   267     
       
   268     cdef _init_addrinfo (self, libc.addrinfo *ai) :
       
   269         #ai.flags = c_ai.ai_flags
       
   270         self.family = ai.ai_family
       
   271         self.socktype = ai.ai_socktype
       
   272         self.protocol = ai.ai_protocol
       
   273         self.addr = build_sockaddr(ai.ai_addr, ai.ai_addrlen)
       
   274         self.canonname = ai.ai_canonname if ai.ai_canonname else None
       
   275 
       
   276     def __str__ (self) :
       
   277         return "family=%d, socktype=%d, protocol=%d, addr=%s, canonname=%s" % (self.family, self.socktype, self.protocol, self.addr, self.canonname)
       
   278 
       
   279 cdef addrinfo build_addrinfo (libc.addrinfo *c_ai) :
       
   280     cdef addrinfo ai = addrinfo()
       
   281     
       
   282     ai._init_addrinfo(c_ai)
       
   283 
       
   284     return ai
       
   285 
       
   286 cdef class endpoint :
       
   287 
       
   288     def __init__ (self, hostname=None, service=None) :
       
   289         """
       
   290             Construct with the given hostname/service, either of which may be None.
       
   291 
       
   292             A hostname of None implies all valid local addresses (with AI_PASSIVE), and a service of None implies an
       
   293             ephemeral port.
       
   294 
       
   295                 hostname        - the literal address or DNS hostname or anything else that GAI supports
       
   296                 service         - the numeric port or service name
       
   297         """
       
   298 
       
   299         self.hostname = str(hostname)
       
   300         self.service = str(service)
       
   301 
       
   302     cpdef getaddrinfo (self, int family, int socktype, int protocol = 0, int flags = libc.AI_PASSIVE) :
       
   303         """
       
   304             Look up our hostname/service using the given socket parameters, and return a sequence of addrinfo objects.
       
   305         """
       
   306         
       
   307         # XXX: Cython doesn't support proper compound value literals...
       
   308         cdef libc.addrinfo hints
       
   309         
       
   310         libc.memset(&hints, 0, sizeof(hints))
       
   311         hints.ai_flags          = flags
       
   312         hints.ai_family         = family
       
   313         hints.ai_socktype       = socktype
       
   314         hints.ai_protocol       = protocol
       
   315 
       
   316         cdef libc.addrinfo *res, *r
       
   317         cdef int err
       
   318         cdef object ret = []
       
   319 
       
   320         cdef char *hostname = NULL
       
   321         cdef char *service = NULL
       
   322 
       
   323         if self.hostname is not None :
       
   324             hostname = self.hostname
       
   325         
       
   326         if self.service is not None :
       
   327             service = self.service
       
   328 
       
   329         # operate!
       
   330         err = libc.c_getaddrinfo(hostname, service, &hints, &res)
       
   331 
       
   332         try :
       
   333             if err :
       
   334                 # XXX: raise a GAIError
       
   335                 raise Exception(libc.gai_strerror(err))
       
   336             
       
   337             # gather results
       
   338             r = res
       
   339 
       
   340             while r :
       
   341                 ret.append(build_addrinfo(r))
       
   342 
       
   343                 r = r.ai_next
       
   344             
       
   345             # ok
       
   346             return ret
       
   347 
       
   348         finally :
       
   349             libc.c_freeaddrinfo(res)
       
   350 
       
   351     def __str__ (self) :
       
   352         return "hostname=%s, service=%s" % (self.hostname, self.service)
       
   353