# HG changeset patch # User Tero Marttila # Date 1250454720 -10800 # Node ID c44754cc1ffe57fe0e49e1f90d5dcc761d8ffaca # Parent a1091632a8a7675c8fed407b2b494d1b9e2341ff some recv magic, still no PyString_Resize, though diff -r a1091632a8a7 -r c44754cc1ffe qmsk/net/libc.pxd --- a/qmsk/net/libc.pxd Sun Aug 16 21:54:46 2009 +0300 +++ b/qmsk/net/libc.pxd Sun Aug 16 23:32:00 2009 +0300 @@ -42,6 +42,7 @@ int close (int fd) cdef extern from "alloca.h" : + # XXX: this is unsafe because there is it may fail nastily for allocations that won't fit on the stack - SIGSEGV void* alloca (size_t size) cdef extern from "sys/uio.h" : diff -r a1091632a8a7 -r c44754cc1ffe qmsk/net/py.pxd --- a/qmsk/net/py.pxd Sun Aug 16 21:54:46 2009 +0300 +++ b/qmsk/net/py.pxd Sun Aug 16 23:32:00 2009 +0300 @@ -1,17 +1,25 @@ -cimport qmsk.net.libc as libc +from qmsk.net.libc cimport ssize_t, errno cdef extern from "Python.h" : struct PyObject : pass ## string stuff - int PyObject_AsCharBuffer (object obj, char **buf, libc.ssize_t *len) except -1 + int PyObject_AsCharBuffer (object obj, char **buf, ssize_t *len) except -1 + + object PyString_FromStringAndSize (char *v, ssize_t len) + char* PyString_AS_STRING (object) except NULL + int _PyString_Resize (PyObject **string, ssize_t newsize) except -1 ## except setting PyObject* PyErr_SetFromErrno (PyObject *type) PyObject *PyExc_OSError +## custom haxes +#cdef extern from "_py.c" : +# object py_string_resize (object string, ssize_t new_size) + # raise OSError with errno # XXX: doesn't do anything with func cdef int raise_errno (char *func) except -1 diff -r a1091632a8a7 -r c44754cc1ffe qmsk/net/socket/platform.pxd --- a/qmsk/net/socket/platform.pxd Sun Aug 16 21:54:46 2009 +0300 +++ b/qmsk/net/socket/platform.pxd Sun Aug 16 23:32:00 2009 +0300 @@ -120,7 +120,7 @@ ssize_t send (int fd, void *buf, size_t n, int flags) ssize_t recv (int fd, void *buf, size_t n, int flags) ssize_t sendto (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) - ssize_t recvfrom (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) + ssize_t recvfrom (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t *addr_len) ssize_t sendmsg (int fd, msghdr *msg, int flags) ssize_t recvmsg (int fd, msghdr *msg, int flags) diff -r a1091632a8a7 -r c44754cc1ffe qmsk/net/socket/socket.pyx --- a/qmsk/net/socket/socket.pyx Sun Aug 16 21:54:46 2009 +0300 +++ b/qmsk/net/socket/socket.pyx Sun Aug 16 23:32:00 2009 +0300 @@ -22,6 +22,7 @@ if buf is not None : # XXX: test that except works right + # XXX: this complains about const... py.PyObject_AsCharBuffer(buf, buf_ptr, &tmp_len) # XXX: ensure that this is >= 0 @@ -66,6 +67,13 @@ if self.fd < 0 : raise_errno('socket') + def fileno (self) : + """ + Returns the OS-level file desriptor for this socket as an integer + """ + + return self.fd + def bind (self, sockaddr addr) : """ Bind this socket to the given local socket address. The given sockaddr should be of the same or a @@ -128,19 +136,17 @@ socket must be a connection-based socket (SOCK_STREAM/SOCK_SEQPACKET) and in the passive listening mode (.listen()). - This returns a (sock, sockaddr) tuple: + This returns a (sock, src_addr) tuple: sock - the newly created sock, corresponding to the incoming connection - sockaddr - the remote address of the incoming connection + src_addr - the remote address of the incoming connection """ # prep the sockaddr that we will return cdef platform.sockaddr_storage ss cdef platform.socklen_t ss_len = sizeof(ss) - cdef socket_t sock_fd - # accept() - sock_fd = platform.accept(self.fd, &ss, &ss_len) + cdef socket_t sock_fd = platform.accept(self.fd, &ss, &ss_len) if sock_fd < 0 : raise_errno('accept') @@ -156,9 +162,9 @@ raise # prep the new addr - sock_addr = build_sockaddr( &ss, ss_len) + cdef sockaddr src_addr = build_sockaddr( &ss, ss_len) - return sock_obj, sock_addr + return sock_obj, src_addr def send (self, object buf, int flags = 0) : """ @@ -323,7 +329,131 @@ else : return ret + + def recv (self, size_t len, int flags = 0) : + """ + Recieve a message, reading and returning at most `len` bytes. + len - size of buffer to use for recv + flags - (optional) MSG_* flags to use for recv() + + Returns the recieved data as a newly allocated string of the correct length. + """ + + # alloc a new return str + # XXX: len overflow... + cdef object str = py.PyString_FromStringAndSize(NULL, len) + cdef char *buf = py.PyString_AS_STRING(str) + + # recv() + cdef libc.ssize_t ret = platform.recv(self.fd, buf, len, flags) + + if ret < 0 : + raise_errno('recv') + + # XXX: figure out how to call _PyString_Resize + return str[:ret] + + def recvfrom (self, size_t len, int flags = 0) : + """ + Recieve a message, reading at most `len` bytes, also returning the source address. + + len - size of buffer to use for recv + flags - (optional) MSG_* flags to use for recvfrom() + + Returns the recieved data and the source address as a (buf, src_addr) tuple : + buf - a newly allocated string containing the recieved data, of the correct length + src_addr - the source address the message was recieved from + """ + + # alloc a new return str + # XXX: len overflow... + cdef object str = py.PyString_FromStringAndSize(NULL, len) + cdef char *buf = py.PyString_AS_STRING(str) + + # prep the sockaddr that we will return + cdef platform.sockaddr_storage ss + cdef platform.socklen_t ss_len = sizeof(ss) + + # recvfrom() + cdef libc.ssize_t ret = platform.recvfrom(self.fd, buf, len, flags, &ss, &ss_len) + + if ret < 0 : + raise_errno('recv') + + # prep the new addr + cdef sock_addr = build_sockaddr( &ss, ss_len) + + # XXX: figure out how to call _PyString_Resize + return str[:ret], sock_addr + + def recvmsg (self, bint recv_addr = True, object iov_lens = None, size_t control_len = 0, int flags = 0) : + """ + Recieve a message along with some extra data. + + recv_addr - ask for and return a sockaddr for the source address of the message? + lenv - (optional) sequence of buffer sizes to use for the message data iov + control_len - (optional) amount of auxiliary data to recieve + flags - (optional) flags to pass to recvmsg() + + Returns a (name, iov, control, flags) tuple : + name - the source address of the message, or None + iov - sequence of strings containing the recieved data, each at most lenv[x] bytes long + control - string containing recieved control message, if any + flags - recieved flags + """ + + cdef platform.msghdr msg + + libc.memset(&msg, 0, sizeof(msg)) + + # prep the sockaddr that we will return + cdef platform.sockaddr_storage ss + + # ask for a name? + if recv_addr : + msg.msg_name = &ss + msg.msg_namelen = sizeof(ss) + + # build iov? + if iov_lens : + # XXX: implement + pass + + # build control buffer? + if control_len : + # XXX: implement + pass + + # recvmsg() + cdef libc.ssize_t ret = platform.recvmsg(self.fd, &msg, flags) + + if ret < 0 : + raise_errno('recvmsg') + + # name? + cdef sockaddr name = None + + if msg.msg_name and msg.msg_namelen : + name = build_sockaddr( msg.msg_name, msg.msg_namelen) + + # iov? + cdef object iov = None + + if ret : + assert msg.msg_iov and msg.msg_iovlen + + # XXX: implement + pass + + # control? + cdef object control = None + + if msg.msg_control and msg.msg_controllen : + # XXX: implement + pass + + return name, iov, control, msg.msg_flags def shutdown (self, how) : """