diff -r 314d47bdd4d9 -r a1091632a8a7 qmsk/net/socket/socket.pyx --- a/qmsk/net/socket/socket.pyx Sun Aug 16 21:13:36 2009 +0300 +++ b/qmsk/net/socket/socket.pyx Sun Aug 16 21:54:46 2009 +0300 @@ -37,27 +37,30 @@ # XXX: do some GIL-releasin' cdef class socket : - def __init__ (self, int fd = -1) : + def __cinit__ (self) : """ - Construct this socket with the given fd, or -1 to mark it as fd-less + Initialize the socket to set fd to -1, so that we dont't try and close stdin too often :) """ - self.fd = fd + self.fd = -1 - def socket (self, int family = platform.AF_INET, int socktype = platform.SOCK_STREAM, int protocol = 0) : + def __init__ (self, int family = platform.AF_INET, int socktype = platform.SOCK_STREAM, int protocol = 0, int fd = -1) : """ - Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol. + Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol, + unless the fd argument is given as >= 0, in which case it used directly. family - one of AF_* socktype - one of SOCK_* protocol - one of IPPROTO_* or zero to select default """ - if self.fd >= 0 : - raise Exception("Socket fd already exists") - - # socket() - self.fd = platform.socket(family, socktype, protocol) + if fd >= 0 : + # given fd + self.fd = fd + + else : + # socket() + self.fd = platform.socket(family, socktype, protocol) # trap if self.fd < 0 : @@ -141,9 +144,16 @@ if sock_fd < 0 : raise_errno('accept') + + try : + # prep the new socket + sock_obj = socket(sock_fd) - # prep the new socket - sock_obj = socket(sock_fd) + except : + # XXX: don't leak the socket fd? How does socket.__init__ handle this? + platform.close(sock_fd) + + raise # prep the new addr sock_addr = build_sockaddr( &ss, ss_len) @@ -303,7 +313,6 @@ for i, buf in enumerate(iov) : iovec = &iov_list[i] - parse_buf(&iovec.iov_base, &iovec.iov_len, buf, 1) # sendmsg() @@ -314,4 +323,58 @@ else : return ret - + + + def shutdown (self, how) : + """ + Shutdown part of a full-duplex connection. + + how - one of SHUT_* + + This does not affect this socket's fd. + """ + + # shutdown() + if platform.shutdown(self.fd, how) : + raise_errno('shutdown') + + def close (self) : + """ + Close the socket fd if we have one, invalidating it if succesful. + + Note that this will raise an error and keep the fd if the system close() returns an error. + + Calling this again after a succesfull close() does nothing. + + XXX: SO_LINGER/blocking? + + >>> s = socket() + >>> s.fd >= 0 + True + >>> s.close() + >>> s.fd >= 0 + False + >>> s.close() + """ + + # ignore if already closed + if self.fd < 0 : + return + + # close() + if libc.close(self.fd) : + raise_errno('close') + + # invalidate + self.fd = -1 + + def __dealloc__ (self) : + """ + Close the socket fd if one is set, ignoring any errors from close + """ + + if self.fd >= 0 : + if libc.close(self.fd) : + # XXX: at least warn... ? + pass +