qmsk/net/socket/socket.pyx
changeset 13 a1091632a8a7
parent 12 314d47bdd4d9
child 14 c44754cc1ffe
equal deleted inserted replaced
12:314d47bdd4d9 13:a1091632a8a7
    35         raise ValueError(buf)
    35         raise ValueError(buf)
    36 
    36 
    37 # XXX: do some GIL-releasin'
    37 # XXX: do some GIL-releasin'
    38 cdef class socket :
    38 cdef class socket :
    39 
    39 
    40     def __init__ (self, int fd = -1) :
    40     def __cinit__ (self) :
    41         """
    41         """
    42             Construct this socket with the given fd, or -1 to mark it as fd-less
    42             Initialize the socket to set fd to -1, so that we dont't try and close stdin too often :)
    43         """
    43         """
    44 
    44 
    45         self.fd = fd
    45         self.fd = -1
    46 
    46 
    47     def socket (self, int family = platform.AF_INET, int socktype = platform.SOCK_STREAM, int protocol = 0) :
    47     def __init__ (self, int family = platform.AF_INET, int socktype = platform.SOCK_STREAM, int protocol = 0, int fd = -1) :
    48         """
    48         """
    49             Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol.
    49             Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol,
       
    50             unless the fd argument is given as >= 0, in which case it used directly.
    50 
    51 
    51                 family      - one of AF_*
    52                 family      - one of AF_*
    52                 socktype    - one of SOCK_*
    53                 socktype    - one of SOCK_*
    53                 protocol    - one of IPPROTO_* or zero to select default
    54                 protocol    - one of IPPROTO_* or zero to select default
    54         """
    55         """
    55 
    56 
    56         if self.fd >= 0 :
    57         if fd >= 0 :
    57             raise Exception("Socket fd already exists")
    58             # given fd
    58         
    59             self.fd = fd
    59         # socket()
    60 
    60         self.fd = platform.socket(family, socktype, protocol)
    61         else :
       
    62             # socket()
       
    63             self.fd = platform.socket(family, socktype, protocol)
    61         
    64         
    62         # trap
    65         # trap
    63         if self.fd < 0 :
    66         if self.fd < 0 :
    64             raise_errno('socket')
    67             raise_errno('socket')
    65 
    68 
   139         # accept()
   142         # accept()
   140         sock_fd = platform.accept(self.fd, <platform.sockaddr *> &ss, &ss_len)
   143         sock_fd = platform.accept(self.fd, <platform.sockaddr *> &ss, &ss_len)
   141 
   144 
   142         if sock_fd < 0 :
   145         if sock_fd < 0 :
   143             raise_errno('accept')
   146             raise_errno('accept')
   144 
   147         
   145         # prep the new socket
   148         try :
   146         sock_obj = socket(sock_fd)
   149             # prep the new socket
       
   150             sock_obj = socket(sock_fd)
       
   151 
       
   152         except :
       
   153             # XXX: don't leak the socket fd? How does socket.__init__ handle this?
       
   154             platform.close(sock_fd)
       
   155 
       
   156             raise
   147 
   157 
   148         # prep the new addr
   158         # prep the new addr
   149         sock_addr = build_sockaddr(<platform.sockaddr *> &ss, ss_len)
   159         sock_addr = build_sockaddr(<platform.sockaddr *> &ss, ss_len)
   150 
   160 
   151         return sock_obj, sock_addr
   161         return sock_obj, sock_addr
   301         
   311         
   302         # fill in the iovecs
   312         # fill in the iovecs
   303         for i, buf in enumerate(iov) :
   313         for i, buf in enumerate(iov) :
   304             iovec = &iov_list[i]
   314             iovec = &iov_list[i]
   305                 
   315                 
   306                 
       
   307             parse_buf(&iovec.iov_base, &iovec.iov_len, buf, 1)
   316             parse_buf(&iovec.iov_base, &iovec.iov_len, buf, 1)
   308             
   317             
   309         # sendmsg()
   318         # sendmsg()
   310         ret = libc.writev(self.fd, iov_list, iov_count)
   319         ret = libc.writev(self.fd, iov_list, iov_count)
   311 
   320 
   312         if ret < 0 :
   321         if ret < 0 :
   313             raise_errno('writev')
   322             raise_errno('writev')
   314 
   323 
   315         else :
   324         else :
   316             return ret
   325             return ret
   317  
   326 
       
   327 
       
   328     def shutdown (self, how) :
       
   329         """
       
   330             Shutdown part of a full-duplex connection. 
       
   331 
       
   332                 how         - one of SHUT_*
       
   333 
       
   334             This does not affect this socket's fd.
       
   335         """
       
   336         
       
   337         # shutdown()
       
   338         if platform.shutdown(self.fd, how) :
       
   339             raise_errno('shutdown')
       
   340 
       
   341     def close (self) :
       
   342         """
       
   343             Close the socket fd if we have one, invalidating it if succesful.
       
   344 
       
   345             Note that this will raise an error and keep the fd if the system close() returns an error.
       
   346 
       
   347             Calling this again after a succesfull close() does nothing.
       
   348 
       
   349             XXX: SO_LINGER/blocking?
       
   350 
       
   351             >>> s = socket()
       
   352             >>> s.fd >= 0
       
   353             True
       
   354             >>> s.close()
       
   355             >>> s.fd >= 0
       
   356             False
       
   357             >>> s.close()
       
   358         """
       
   359         
       
   360         # ignore if already closed
       
   361         if self.fd < 0 :
       
   362             return
       
   363         
       
   364         # close()
       
   365         if libc.close(self.fd) :
       
   366             raise_errno('close')
       
   367         
       
   368         # invalidate
       
   369         self.fd = -1
       
   370     
       
   371     def __dealloc__ (self) :
       
   372         """
       
   373             Close the socket fd if one is set, ignoring any errors from close
       
   374         """
       
   375 
       
   376         if self.fd >= 0 :
       
   377             if libc.close(self.fd) :
       
   378                 # XXX: at least warn... ?
       
   379                 pass
       
   380