Commit fbe547e6 authored by Xavier Thompson's avatar Xavier Thompson

Implement GIL-free socket API

parent 3a239166
......@@ -3,7 +3,7 @@ cdef extern from "<sys/types.h>" nogil:
cdef extern from "<sys/socket.h>" nogil:
cdef extern from "<sys/socket.h>" namespace "" nogil:
ctypedef long socklen_t
......@@ -55,6 +55,11 @@ cdef extern from "<sys/socket.h>" nogil:
int socketpair(int, int, int, int [2])
cdef extern from "<unistd.h>" namespace "" nogil:
int close(int fd)
cdef extern from "<netdb.h>" nogil:
......
cimport stdlib._socket as _socket
from libc.string cimport memset, memcpy
from libc.stdlib cimport malloc, free
from libc.errno cimport errno
from libc.string cimport memset, memcpy, strerror
from libc.stdlib cimport malloc, free, realloc
from stdlib.string cimport Str
from libcythonplus.list cimport cyplist
......@@ -121,7 +122,7 @@ cdef cypclass Addrinfo:
self.sockaddr = sockaddr
cdef inline cyplist[Addrinfo] getaddrinfo(Str host, Str port, int family, int socktype, int protocol, int flags) nogil except NULL:
cdef inline cyplist[Addrinfo] getaddrinfo(Str host, Str port, int family=0, int socktype=0, int protocol=0, int flags=0) nogil except NULL:
cdef _socket.addrinfo hints
cdef _socket.addrinfo *ai
cdef _socket.addrinfo *p
......@@ -152,4 +153,141 @@ cdef inline cyplist[Addrinfo] getaddrinfo(Str host, Str port, int family, int so
return result
cdef cypclass Socket
cdef inline Socket socket(int family, int socktype, int protocol=0) nogil except NULL:
cdef int sockfd = _socket.socket(family, socktype, protocol)
if sockfd == -1:
with gil:
raise OSError('failed to open socket: ' + strerror(errno).decode())
s = Socket()
s.sockfd = sockfd
s.family = family
s.socktype = socktype
s.protocol = protocol
s.address = NULL
return s
cdef cypclass Socket:
int sockfd
int family
int socktype
int protocol
Sockaddr address
int bind(self, Sockaddr address) except -1:
cdef int status
status = _socket.bind(self.sockfd, address.addr, address.addrlen)
if status == -1:
with gil:
raise OSError('failed to bind socket: ' + strerror(errno).decode())
self.address = address
return status
int connect(self, Sockaddr address) except -1:
cdef int status
status = _socket.connect(self.sockfd, address.addr, address.addrlen)
if status == -1:
with gil:
raise OSError('failed to connect socket: ' + strerror(errno).decode())
self.address = address
return status
int listen(self, int backlog) except -1:
cdef int status
status = _socket.listen(self.sockfd, backlog)
if status == -1:
with gil:
raise OSError('failed to listen to socket: ' + strerror(errno).decode())
return status
Socket accept(self) except NULL:
cdef _socket.sockaddr_storage addr
cdef _socket.socklen_t addrlen
cdef int status
cdef Socket socket
status = _socket.accept(self.sockfd, <_socket.sockaddr *> &addr, &addrlen)
if status == -1:
with gil:
raise OSError('failed to accept from socket: ' + strerror(errno).decode())
socket = Socket()
socket.sockfd = status
socket.family = self.family
socket.socktype = self.socktype
socket.protocol = self.protocol
socket.address = Sockaddr(<_socket.sockaddr *> &addr, addrlen)
return socket
int send(self, Str msg, int flags=0) except -1:
cdef int status
if msg is NULL:
with gil:
raise ValueError('cannot send NULL to socket')
status = _socket.send(self.sockfd, Str.to_c_str(msg), msg.__len__(), flags)
if status == -1:
with gil:
raise OSError('failed to send to socket: ' + strerror(errno).decode())
return status
int sendslice(self, Str msg, int flags=0, size_t start=0, size_t stop=0) except -1:
cdef int status
if msg is NULL:
with gil:
raise ValueError('cannot send NULL to socket')
end = msg.__len__()
if stop == 0:
stop = end
elif stop > end:
with gil:
raise ValueError('slice bounds out of range')
if start >= stop:
with gil:
raise ValueError('slice bounds out of order')
size = stop - start
status = _socket.send(self.sockfd, Str.to_c_str(msg) + start, size, flags)
if status == -1:
with gil:
raise OSError('failed to send to socket: ' + strerror(errno).decode())
return status
int sendall(self, Str msg, int flags=0) except -1:
cdef int sent = self.send(msg, flags)
cdef int size = msg.__len__()
while sent < size:
sent += self.sendslice(msg, flags, sent)
return sent
Str recv(self, int bufsize, int flags=0) except NULL:
cdef int status
cdef char * buf
buf = <char *> malloc(bufsize + 1)
status = _socket.recv(self.sockfd, buf, bufsize, flags)
if status == -1:
free(buf)
with gil:
raise OSError('failed to recv from socket: ' + strerror(errno).decode())
buf[status] = 0
#if status < bufsize:
# newbuf = realloc(buf, status + 1)
# if newbuf is not NULL:
# buf = newbuf
return Str.steal_c_str(buf, status)
int shutdown(self, int how) except -1:
cdef int status
status = _socket.shutdown(self.sockfd, how)
if status == -1:
with gil:
raise OSError('failed to shutdown socket: ' + strerror(errno).decode())
return status
int close(self) except -1:
cdef int status
status = _socket.close(self.sockfd)
if status == -1:
with gil:
raise OSError('failed to close socket: ' + strerror(errno).decode())
return status
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment