[pypy-commit] pypy py3.5: Merged in py3.5-sendmsg-recvmsg (pull request #562)
rlamy
pypy.commits at gmail.com
Thu Aug 31 07:51:16 EDT 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.5
Changeset: r92286:d12c25571050
Date: 2017-08-31 11:50 +0000
http://bitbucket.org/pypy/pypy/changeset/d12c25571050/
Log: Merged in py3.5-sendmsg-recvmsg (pull request #562)
Implement socket.sendmsg()/.recvmsg()
diff --git a/pypy/module/_socket/__init__.py b/pypy/module/_socket/__init__.py
--- a/pypy/module/_socket/__init__.py
+++ b/pypy/module/_socket/__init__.py
@@ -34,6 +34,7 @@
ntohs ntohl htons htonl inet_aton inet_ntoa inet_pton inet_ntop
getaddrinfo getnameinfo
getdefaulttimeout setdefaulttimeout
+ CMSG_SPACE CMSG_LEN
""".split():
if (name in ('inet_pton', 'inet_ntop', 'socketpair') and
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -327,6 +327,42 @@
for (family, socktype, protocol, canonname, addr) in lst]
return space.newlist(lst1)
+ at unwrap_spec(size=int)
+def CMSG_SPACE(space, size):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param space:
+ :param size: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required size. The value is memory alligned
+ """
+ if size < 0:
+ raise oefmt(space.w_OverflowError,
+ "CMSG_SPACE() argument out of range")
+ retval = rsocket.CMSG_SPACE(size)
+ if retval == 0:
+ raise oefmt(space.w_OverflowError,
+ "CMSG_SPACE() argument out of range")
+ return space.newint(retval)
+
+ at unwrap_spec(len=int)
+def CMSG_LEN(space, len):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param space:
+ :param len: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required size. The value is not mem alligned.
+ """
+ if len < 0:
+ raise oefmt(space.w_OverflowError,
+ "CMSG_LEN() argument out of range")
+ retval = rsocket.CMSG_LEN(len)
+ if retval == 0:
+ raise oefmt(space.w_OverflowError,
+ "CMSG_LEN() argument out of range")
+ return space.newint(retval)
+
def getdefaulttimeout(space):
"""getdefaulttimeout() -> timeout
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -446,6 +446,52 @@
converted_error(space, e, eintr_retry=True)
return space.newtuple([space.newbytes(data), w_addr])
+ @unwrap_spec(message_size=int, ancbufsize=int, flags=int)
+ def recvmsg_w(self, space, message_size, ancbufsize=0, flags=0):
+ """
+ recvmsg(message_size[, ancbufsize[, flags]]) -> (message, ancillary, flags, address)
+ Receive normal data (up to bufsize bytes) and ancillary data from the socket.
+ The ancbufsize argument sets the size in bytes of the internal buffer used to receive the ancillary data;
+ it defaults to 0, meaning that no ancillary data will be received.
+ Appropriate buffer sizes for ancillary data can be calculated using CMSG_SPACE() or CMSG_LEN(),
+ and items which do not fit into the buffer might be truncated or discarded.
+ The flags argument defaults to 0 and has the same meaning as for recv().
+ The ancdata item is a list of zero or more tuples (cmsg_level, cmsg_type, cmsg_data):
+ cmsg_level and cmsg_type are integers specifying the protocol level and protocol-specific type respectively,
+ and cmsg_data is a bytes object holding the associated data.
+
+ :param space: Non useable parameter. It represents the object space.
+ :param message_size: Maximum size of the message to be received
+ :param ancbufsize: Maximum size of the ancillary data to be received
+ :param flags: Receive flag. For more details, please check the Unix manual
+ :return: a tuple consisting of the message, the ancillary data, return flag and the address.
+ """
+ if message_size < 0:
+ raise oefmt(space.w_ValueError, "negative buffer size in recvmsg()")
+ if ancbufsize < 0:
+ raise oefmt(space.w_ValueError, "invalid ancillary data buffer length")
+ while True:
+ try:
+ recvtup = self.sock.recvmsg(message_size, ancbufsize, flags)
+ w_message = space.newbytes(recvtup[0])
+ anclist = []
+ for l in recvtup[1]:
+ tup = space.newtuple([space.newint(l[0]), space.newint(l[1]), space.newbytes(l[2])])
+ anclist.append(tup)
+
+ w_anc = space.newlist(anclist)
+
+ w_flag = space.newint(recvtup[2])
+ if (recvtup[3] is not None):
+ w_address = addr_as_object(recvtup[3], self.sock.fd, space)
+ else:
+ w_address = space.w_None
+ rettup = space.newtuple([w_message, w_anc, w_flag, w_address])
+ break
+ except SocketError as e:
+ converted_error(space, e, eintr_retry=True)
+ return rettup
+
@unwrap_spec(data='bufferstr', flags=int)
def send_w(self, space, data, flags=0):
"""send(data[, flags]) -> count
@@ -501,6 +547,67 @@
converted_error(space, e, eintr_retry=True)
return space.newint(count)
+ @unwrap_spec(flags=int)
+ def sendmsg_w(self, space, w_data, w_ancillary=None, flags=0 ,w_address=None):
+ """
+ sendmsg(data[,ancillary[,flags[,address]]]) -> bytes_sent
+ Send normal and ancillary data to the socket, gathering the non-ancillary data
+ from a series of buffers and concatenating it into a single message.
+ The ancdata argument specifies the ancillary data (control messages) as an iterable of zero or more tuples
+ (cmsg_level, cmsg_type, cmsg_data), where cmsg_level and cmsg_type are integers specifying the protocol level
+ and protocol-specific type respectively, and cmsg_data is a bytes-like object holding the associated data.
+ :param space: Represents the object space.
+ :param w_data: The message(s). needs to be a bytes like object
+ :param w_ancillary: needs to be a sequence object Can remain unspecified.
+ :param w_flags: needs to be an integer. Can remain unspecified.
+ :param w_address: needs to be a bytes-like object Can remain unspecified.
+ :return: Bytes sent from the message
+ """
+ # Get the flag and address from the object space
+ while True:
+ try:
+ address = None
+ if not space.is_none(w_address):
+ address = self.addr_from_object(space, w_address)
+
+ # find data's type in the ObjectSpace and get a list of string out of it.
+ data = []
+ data_iter = space.unpackiterable(w_data)
+ for i in data_iter:
+ data.append(space.readbuf_w(i).as_str())
+
+ # find the ancillary's type in the ObjectSpace and get a list of tuples out of it.
+ ancillary = []
+ if w_ancillary is not None:
+ anc_iter = space.unpackiterable(w_ancillary)
+ for w_i in anc_iter:
+ if not space.isinstance_w(w_i, space.w_tuple):
+ raise oefmt(space.w_TypeError, "[sendmsg() ancillary data items]() argument must be sequence")
+ if space.len_w(w_i) == 3:
+ intemtup = space.unpackiterable(w_i)
+ level = space.int_w(intemtup[0])
+ type = space.int_w(intemtup[1])
+ cont = space.readbuf_w(intemtup[2]).as_str()
+ tup = (level, type, cont)
+ ancillary.append(tup)
+ else:
+ raise oefmt(space.w_TypeError,
+ "[sendmsg() ancillary data items]() argument must be sequence of length 3")
+
+ count = self.sock.sendmsg(data, ancillary, flags, address)
+ if count < 0:
+ if (count == -1000):
+ raise oefmt(space.w_OSError, "sending multiple control messages not supported")
+ if (count == -1001):
+ raise oefmt(space.w_OSError, "ancillary data item too large")
+ if (count == -1002):
+ raise oefmt(space.w_OSError, "too much ancillary data")
+ break
+ except SocketError as e:
+ converted_error(space, e, eintr_retry=True)
+
+ return space.newint(count)
+
@unwrap_spec(flag=int)
def setblocking_w(self, flag):
"""setblocking(flag)
@@ -772,7 +879,7 @@
socketmethodnames = """
_accept bind close connect connect_ex fileno detach
getpeername getsockname getsockopt gettimeout listen
-recv recvfrom send sendall sendto setblocking
+recv recvfrom recvmsg send sendall sendto sendmsg setblocking
setsockopt settimeout shutdown _reuse _drop recv_into recvfrom_into
""".split()
if hasattr(rsocket._c, 'WSAIoctl'):
@@ -813,6 +920,8 @@
sendall(data[, flags]) -- send all data
send(data[, flags]) -- send data, may not send all of it
sendto(data[, flags], addr) -- send data to a given address
+sendmsg(messages[, ancillary[, flags[, address]]]) -- send data and ancillary payload in a packet. May specifiy flags or the address
+recvmsg(message_size,[ ancillary_size,[ flags]]) -- receive data and ancillary payload. Return a tup of message, ancdata, flags and address
setblocking(0 | 1) -- set or clear the blocking I/O flag
setsockopt(level, optname, value) -- set socket options
settimeout(None | float) -- set or clear the timeout
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -2,6 +2,7 @@
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.tool import rffi_platform as platform
from rpython.rtyper.lltypesystem.rffi import CCHARP
+from rpython.rlib import jit
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator.platform import platform as target_platform
@@ -190,6 +191,8 @@
IPX_TYPE
+SCM_RIGHTS
+
POLLIN POLLPRI POLLOUT POLLERR POLLHUP POLLNVAL
POLLRDNORM POLLRDBAND POLLWRNORM POLLWEBAND POLLMSG
@@ -260,6 +263,7 @@
sockaddr_ptr = lltype.Ptr(lltype.ForwardReference())
addrinfo_ptr = lltype.Ptr(lltype.ForwardReference())
+
# struct types
CConfig.sockaddr = platform.Struct('struct sockaddr',
[('sa_family', rffi.INT),
@@ -343,6 +347,650 @@
[('ifr_ifindex', rffi.INT),
('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))])
+# insert handler for sendmsg / recvmsg here
+if _POSIX:
+ includes = ['stddef.h',
+ 'sys/socket.h',
+ 'unistd.h',
+ 'string.h',
+ 'stdlib.h',
+ 'errno.h',
+ 'limits.h',
+ 'stdio.h',
+ 'sys/types.h',
+ 'netinet/in.h',
+ 'arpa/inet.h']
+ separate_module_sources = ['''
+
+ // special defines for returning from recvmsg
+ #define BAD_MSG_SIZE_GIVEN -10000
+ #define BAD_ANC_SIZE_GIVEN -10001
+ #define MAL_ANC -10002
+
+ // special defines for returning from sendmsg
+ #define MUL_MSGS_NOT_SUP -1000
+ #define ANC_DATA_TOO_LARGE -1001
+ #define ANC_DATA_TOO_LARGEX -1002
+
+ /*
+ Even though you could, theoretically, receive more than one message, IF you set the socket option,
+ CPython has hardcoded the message number to 1, and implemented the option to receive more then 1 in a
+ different socket method: recvmsg_into
+ */
+ #define MSG_IOVLEN 1 // CPython has hardcoded this as well.
+ #if INT_MAX > 0x7fffffff
+ #define SOCKLEN_T_LIMIT 0x7fffffff
+ #else
+ #define SOCKLEN_T_LIMIT INT_MAX
+ #endif
+
+ // ################################################################################################
+ // Recvmsg implementation and associated functions
+
+ // Taken from CPython. Determines the minimum memory space required for the ancillary data.
+ #ifdef CMSG_SPACE
+ static int
+ cmsg_min_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t space)
+ {
+ size_t cmsg_offset;
+ static const size_t cmsg_len_end = (offsetof(struct cmsghdr, cmsg_len) +
+ sizeof(cmsgh->cmsg_len));
+
+ /* Note that POSIX allows msg_controllen to be of signed type. */
+ if (cmsgh == NULL || msg->msg_control == NULL)
+ return 0;
+ /* Note that POSIX allows msg_controllen to be of a signed type. This is
+ annoying under OS X as it's unsigned there and so it triggers a
+ tautological comparison warning under Clang when compared against 0.
+ Since the check is valid on other platforms, silence the warning under
+ Clang. */
+ #ifdef __clang__
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wtautological-compare"
+ #endif
+ #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wtype-limits"
+ #endif
+ if (msg->msg_controllen < 0)
+ return 0;
+ #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
+ #pragma GCC diagnostic pop
+ #endif
+ #ifdef __clang__
+ #pragma clang diagnostic pop
+ #endif
+ if (space < cmsg_len_end)
+ space = cmsg_len_end;
+ cmsg_offset = (char *)cmsgh - (char *)msg->msg_control;
+ return (cmsg_offset <= (size_t)-1 - space &&
+ cmsg_offset + space <= msg->msg_controllen);
+ }
+ #endif
+
+ // Taken from CPython.
+ #ifdef CMSG_LEN
+ /* If pointer CMSG_DATA(cmsgh) is in buffer msg->msg_control, set
+ *space to number of bytes following it in the buffer and return
+ true; otherwise, return false. Assumes cmsgh, msg->msg_control and
+ msg->msg_controllen are valid. */
+ static int
+ get_cmsg_data_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *space)
+ {
+ size_t data_offset;
+ char *data_ptr;
+
+ if ((data_ptr = (char *)CMSG_DATA(cmsgh)) == NULL)
+ return 0;
+ data_offset = data_ptr - (char *)msg->msg_control;
+ if (data_offset > msg->msg_controllen)
+ return 0;
+ *space = msg->msg_controllen - data_offset;
+ return 1;
+ }
+
+ // Taken from CPython.
+ /* If cmsgh is invalid or not contained in the buffer pointed to by
+ msg->msg_control, return -1. If cmsgh is valid and its associated
+ data is entirely contained in the buffer, set *data_len to the
+ length of the associated data and return 0. If only part of the
+ associated data is contained in the buffer but cmsgh is otherwise
+ valid, set *data_len to the length contained in the buffer and
+ return 1. */
+ static int
+ get_cmsg_data_len(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *data_len)
+ {
+ size_t space, cmsg_data_len;
+
+ if (!cmsg_min_space(msg, cmsgh, CMSG_LEN(0)) ||
+ cmsgh->cmsg_len < CMSG_LEN(0))
+ return -1;
+ cmsg_data_len = cmsgh->cmsg_len - CMSG_LEN(0);
+ if (!get_cmsg_data_space(msg, cmsgh, &space))
+ return -1;
+ if (space >= cmsg_data_len) {
+ *data_len = cmsg_data_len;
+ return 0;
+ }
+ *data_len = space;
+ return 1;
+ }
+ #endif /* CMSG_LEN */
+
+ /*
+ Structure meant to hold the information received after a recvmsg is performed.
+ Essentially it holds: the address, the message, the ancillary data and the return flags.
+ I use this structure for 2 main reasons:
+ - keep things ordered
+ - some of the ancillary parameters need to be int not long (rffi SignedP is actually long*),
+ therefore I cannot use the parameters directly
+ */
+ struct recvmsg_info
+ {
+ struct sockaddr* address; // address fields
+ socklen_t addrlen;
+ int* length_of_messages; // message fields
+ char** messages;
+ int no_of_messages;
+ int size_of_ancillary; // ancillary fields
+ int* levels;
+ int* types;
+ char** file_descr;
+ int* descr_per_ancillary;
+ int retflag; // return flag field
+ };
+
+ /*
+ Wrapper function over recvmsg. Since it returns a lot of data,
+ in a structure that is hard to parse in rffi, it was implemented in C.
+ All the parameters, save the socket fd, message_size, ancillary_size
+ will be malloc'd and/or modified.
+ */
+ RPY_EXTERN
+ int recvmsg_implementation(
+ int socket_fd,
+ int message_size,
+ int ancillary_size,
+ int flags,
+ struct sockaddr* address,
+ socklen_t* addrlen,
+ long** length_of_messages,
+ char** messages,
+ long* no_of_messages,
+ long* size_of_ancillary,
+ long** levels,
+ long** types,
+ char** file_descr,
+ long** descr_per_ancillary,
+ long* retflag)
+
+ {
+
+ struct sockaddr* recvd_address;
+ socklen_t recvd_addrlen;
+ struct msghdr msg = {0};
+ void *controlbuf = NULL;
+ struct cmsghdr *cmsgh;
+ int cmsg_status;
+ struct iovec iov;
+ struct recvmsg_info* retinfo;
+ int error_flag; // variable to be set in case of special errors.
+ int cmsgdatalen = 0;
+
+ // variables that are set to 1, if the message charp has been allocated
+ // and if the ancillary variables have been allocated. To be used in case of failure.
+ int iov_alloc = 0;
+ int anc_alloc = 0;
+
+ retinfo = (struct recvmsg_info*) malloc(sizeof(struct recvmsg_info));
+
+ if (ancillary_size > SOCKLEN_T_LIMIT){
+ error_flag = BAD_ANC_SIZE_GIVEN;
+ goto fail;
+ }
+
+ // Setup the messages iov struct memory
+ iov.iov_base = (char*) malloc(message_size);
+ memset(iov.iov_base, 0, message_size);
+ iov.iov_len = message_size;
+
+ // Setup the ancillary buffer memory
+ controlbuf = malloc(ancillary_size);
+
+ // Setup the recv address memory
+ recvd_addrlen = sizeof(struct sockaddr_storage);
+ recvd_address = (struct sockaddr*) malloc(recvd_addrlen);
+
+ memset(recvd_address, 0,recvd_addrlen);
+
+ // Setup the msghdr struct
+ msg.msg_name = recvd_address;
+ msg.msg_namelen = recvd_addrlen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = MSG_IOVLEN;
+ msg.msg_control = controlbuf;
+ msg.msg_controllen = ancillary_size;
+
+ // Link my structure to the msghdr fields
+ retinfo->address = msg.msg_name;
+ retinfo->length_of_messages = (int*) malloc (MSG_IOVLEN * sizeof(int));
+ retinfo->no_of_messages = MSG_IOVLEN;
+ retinfo->messages = (char**) malloc (MSG_IOVLEN * sizeof(char*));
+ retinfo->messages[0] = msg.msg_iov->iov_base;
+
+ iov_alloc = 1;
+ ssize_t bytes_recvd = 0;
+
+ bytes_recvd = recvmsg(socket_fd, &msg, flags);
+
+ if (bytes_recvd < 0){
+ goto fail;
+ }
+
+ retinfo->addrlen = (socklen_t) msg.msg_namelen;
+ retinfo->length_of_messages[0] = msg.msg_iov->iov_len;
+
+ // Count the ancillary items & allocate the memory
+ int anc_counter = 0;
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+
+ anc_counter++;
+ }
+ retinfo->size_of_ancillary = anc_counter;
+ retinfo->file_descr = (char**) malloc (anc_counter * sizeof(char*));
+ retinfo->levels = (int*) malloc(anc_counter * sizeof(int));
+ retinfo->types = (int*) malloc(anc_counter * sizeof(int));
+ retinfo->descr_per_ancillary = (int*) malloc(anc_counter * sizeof(int));
+ anc_alloc = 1;
+
+ // Extract the ancillary items
+ int i=0;
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+ size_t local_size = 0;
+ cmsg_status = get_cmsg_data_len(&msg, cmsgh, &local_size);
+ if (cmsg_status !=0 ){
+ error_flag = MAL_ANC;
+ goto err_closefds;
+ }
+ retinfo->file_descr[i] = (char*) malloc(local_size);
+ memcpy(retinfo->file_descr[i], CMSG_DATA(cmsgh), local_size);
+ retinfo->levels[i] = cmsgh->cmsg_level;
+ retinfo->types[i] = cmsgh->cmsg_type;
+ retinfo->descr_per_ancillary[i] =local_size;
+ i++;
+
+ }
+ retinfo->retflag = msg.msg_flags;
+
+ // Set the parameters of address
+ memcpy(address,retinfo->address,retinfo->addrlen);
+ *addrlen = retinfo->addrlen;
+
+ // Set the parameters of message
+ no_of_messages[0] = retinfo->no_of_messages;
+ size_of_ancillary[0] = retinfo->size_of_ancillary;
+ *length_of_messages = (long*) malloc (sizeof(long) * retinfo->no_of_messages);
+ //memcpy(*length_of_messages, retinfo->length_of_messages, sizeof(int) * retinfo->no_of_messages);
+ int counter = 0;
+ for (i=0; i< retinfo->no_of_messages; i++){
+ counter += retinfo->length_of_messages[i];
+ length_of_messages[0][i] = retinfo->length_of_messages[i];
+ }
+ memset(*messages, 0, sizeof(char) * counter);
+ counter = 0;
+ for(i=0; i< retinfo->no_of_messages; i++){
+ memcpy(*messages+counter,retinfo->messages[i],retinfo->length_of_messages[i]);
+ counter += retinfo->length_of_messages[i];
+ }
+
+ // Set the parameters of ancillary
+ *levels = (long*) malloc (sizeof(long) * retinfo->size_of_ancillary);
+ *types = (long*) malloc (sizeof(long) * retinfo->size_of_ancillary);
+ *descr_per_ancillary = (long*) malloc (sizeof(long) * retinfo->size_of_ancillary);
+ counter = 0;
+ for (i=0; i < retinfo->size_of_ancillary; i++){
+ counter += retinfo->descr_per_ancillary[i];
+ // Convert the int* to long*
+ levels[0][i] = (long) retinfo->levels[i];
+ types[0][i] = (long) retinfo->types[i];
+ descr_per_ancillary[0][i] = (long) retinfo->descr_per_ancillary[i];
+ }
+ *file_descr = (char*) malloc (sizeof(char) * counter);
+ memset(*file_descr, 0, sizeof(char) * counter);
+ counter = 0;
+ for (i=0; i<retinfo->size_of_ancillary; i++){
+ memcpy(*file_descr+counter,retinfo->file_descr[i], retinfo->descr_per_ancillary[i]);
+ counter += retinfo->descr_per_ancillary[i];
+ }
+
+ // Set the retflag
+ retflag[0] = retinfo->retflag;
+
+ // Free the memory
+ free(retinfo->address);
+ free(retinfo->length_of_messages);
+ free(retinfo->levels);
+ free(retinfo->types);
+ free(retinfo->descr_per_ancillary);
+ for(i = 0; i<retinfo->no_of_messages; i++)
+ free(retinfo->messages[i]);
+ for (i = 0; i < retinfo->size_of_ancillary; i++)
+ free(retinfo->file_descr[i]);
+ free(retinfo->file_descr);
+ free(retinfo->messages);
+ free(retinfo);
+ free(controlbuf);
+
+ return bytes_recvd;
+
+ fail:
+ if (anc_alloc){
+ free(retinfo->file_descr);
+ free(retinfo->levels);
+ free(retinfo->types);
+ free(retinfo->descr_per_ancillary);
+ free(retinfo->length_of_messages);
+ free(retinfo->messages[0]);
+ free(retinfo->messages);
+ free(retinfo->address);
+ free(retinfo);
+ free(controlbuf);
+
+ }else{
+ if (iov_alloc){
+ free(retinfo->length_of_messages);
+ free(retinfo->messages[0]);
+ free(retinfo->messages);
+ free(retinfo->address);
+ free(controlbuf);
+ free(retinfo);
+ }
+ }
+ return error_flag;
+
+ err_closefds:
+ // Special case for UNIX sockets. In case file descriptors are received, they need to be closed.
+ // Taken from CPython
+ #ifdef SCM_RIGHTS
+ /* Close all descriptors coming from SCM_RIGHTS, so they don't leak. */
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+ size_t dataleng;
+ cmsg_status = get_cmsg_data_len(&msg, cmsgh, &dataleng);
+ cmsgdatalen = (int) dataleng;
+ if (cmsg_status < 0)
+ break;
+ if (cmsgh->cmsg_level == SOL_SOCKET &&
+ cmsgh->cmsg_type == SCM_RIGHTS) {
+ size_t numfds;
+ int *fdp;
+
+ numfds = cmsgdatalen / sizeof(int);
+ fdp = (int *)CMSG_DATA(cmsgh);
+ while (numfds-- > 0)
+ close(*fdp++);
+ }
+ if (cmsg_status != 0)
+ break;
+ }
+ #endif /* SCM_RIGHTS */
+ goto fail;
+ }
+
+
+ // ################################################################################################
+ // Sendmsg implementation and associated functions
+
+ #ifdef CMSG_LEN
+ static int
+ get_CMSG_LEN(size_t length, size_t *result)
+ {
+ size_t tmp;
+
+ if (length > (SOCKLEN_T_LIMIT - CMSG_LEN(0)))
+ return 0;
+ tmp = CMSG_LEN(length);
+ if ((tmp > SOCKLEN_T_LIMIT) || (tmp < length))
+ return 0;
+ *result = tmp;
+ return 1;
+ }
+ #endif
+
+ #ifdef CMSG_SPACE
+ /* If length is in range, set *result to CMSG_SPACE(length) and return
+ true; otherwise, return false. */
+ static int
+ get_CMSG_SPACE(size_t length, size_t *result)
+ {
+ size_t tmp;
+
+ /* Use CMSG_SPACE(1) here in order to take account of the padding
+ necessary before *and* after the data. */
+ if (length > (SOCKLEN_T_LIMIT - CMSG_SPACE(1)))
+ return 0;
+ tmp = CMSG_SPACE(length);
+ if ((tmp > SOCKLEN_T_LIMIT) || (tmp < length))
+ return 0;
+ *result = tmp;
+ return 1;
+ }
+ #endif
+
+ /*
+ sendmsg_implementation is a wrapper over sendmsg of the API.
+ It was inspired from the way CPython did their implementation of this.
+ The main reason that it was written in C, is the struct msghdr,
+ which contains the ancillary data in a linked list of cmsghdr structures.
+ It was simpler to use it in C, and then push the simpler types of data via rffi.
+ */
+ RPY_EXTERN
+ int sendmsg_implementation
+ (int socket,
+ struct sockaddr* address,
+ socklen_t addrlen,
+ long* length_of_messages,
+ char** messages,
+ int no_of_messages,
+ long* levels,
+ long* types,
+ char** file_descriptors,
+ long* no_of_fds,
+ int control_length,
+ int flag
+ )
+ {
+
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ void* controlbuf = NULL;
+ int retval;
+ size_t i;
+
+ // Prepare the msghdr structure for the send:
+
+ // Add the address
+ if (address != NULL) {
+ msg.msg_name = address;
+ msg.msg_namelen = addrlen;
+ }
+
+ // Add the message
+ struct iovec *iovs = NULL;
+ if (no_of_messages > 0){
+
+ iovs = (struct iovec*) malloc(no_of_messages * sizeof(struct iovec));
+ memset(iovs, 0, no_of_messages * sizeof(struct iovec));
+ msg.msg_iov = iovs;
+ msg.msg_iovlen = no_of_messages;
+
+ for (i=0; i< no_of_messages; i++){
+ iovs[i].iov_base = messages[i];
+ iovs[i].iov_len = length_of_messages[i];
+ }
+ }
+
+ // Add the ancillary
+ #ifndef CMSG_SPACE
+ if (control_length > 1){
+ free(iovs);
+ return MUL_MSGS_NOT_SUP;
+ }
+ #endif
+ if (control_length > 0){
+
+ //compute the total size of the ancillary
+ //getting the exact amount of space can be tricky and os dependent.
+ size_t total_size_of_ancillary = 0;
+ size_t space;
+ size_t controllen = 0, controllen_last = 0;
+ for (i = 0; i< control_length; i++){
+ total_size_of_ancillary = no_of_fds[i];
+ #ifdef CMSG_SPACE
+ if (!get_CMSG_SPACE(total_size_of_ancillary, &space)) {
+ #else
+ if (!get_CMSG_LEN(total_size_of_ancillary, &space)) {
+ #endif
+ if (iovs != NULL)
+ free(iovs);
+ return ANC_DATA_TOO_LARGE;
+ }
+ controllen +=space;
+ if ((controllen > SOCKLEN_T_LIMIT) || (controllen < controllen_last)) {
+ if (iovs != NULL)
+ free(iovs);
+ return ANC_DATA_TOO_LARGEX;
+ }
+ controllen_last = controllen;
+ }
+
+ controlbuf = malloc(controllen);
+ msg.msg_control= controlbuf;
+ msg.msg_controllen = controllen;
+
+ // memset controlbuf to 0 to avoid trash in the ancillary
+ memset(controlbuf, 0, controllen);
+ cmsg = NULL;
+ for (i = 0; i< control_length; i++){
+ cmsg = (i == 0) ? CMSG_FIRSTHDR(&msg) : CMSG_NXTHDR(&msg, cmsg);
+
+ cmsg->cmsg_level = (int) levels[i];
+ cmsg->cmsg_type = (int) types[i];
+ cmsg->cmsg_len = CMSG_LEN(sizeof(char) * no_of_fds[i]);
+ memcpy(CMSG_DATA(cmsg), file_descriptors[i], sizeof(char) * no_of_fds[i]);
+ }
+
+
+ }
+ // Add the flags
+ msg.msg_flags = flag;
+
+ // Send the data
+ retval = sendmsg(socket, &msg, flag);
+
+ // free everything that was allocated here, and we would not need in rsocket
+ if (iovs != NULL)
+ free(iovs);
+ if (controlbuf !=NULL)
+ free(controlbuf);
+
+ return retval;
+ }
+
+ // ################################################################################################
+ // Wrappers for CMSG_SPACE and CMSG_LEN
+
+ /*
+ These 2 functions are wrappers over sys/socket.h's CMSG_SPACE and CMSG_LEN.
+ They are identical to CPython's.
+ */
+ #ifdef CMSG_SPACE
+ RPY_EXTERN
+ size_t CMSG_SPACE_wrapper(size_t desired_space){
+ size_t result;
+ if (!get_CMSG_SPACE(desired_space, &result)){
+ return 0;
+ }
+ return result;
+ }
+ #endif
+
+ #ifdef CMSG_LEN
+ RPY_EXTERN
+ size_t CMSG_LEN_wrapper(size_t desired_len){
+ size_t result;
+ if (!get_CMSG_LEN(desired_len, &result)){
+ return 0;
+ }
+ return result;
+ }
+ #endif
+
+ // ################################################################################################
+ // Extra functions that I needed
+
+ /*
+ This function is used to memcpy from a char* at an offset.
+ Could not get rffi.c_memcpy to do it at an offset, so I made my own.
+ */
+ RPY_EXTERN
+ int memcpy_from_CCHARP_at_offset_and_size(char* stringfrom, char** stringto, int offset, int size){
+ *stringto = memcpy(*stringto, stringfrom + offset, size);
+ return 0;
+ }
+
+ /*
+ These functions free memory that was allocated in C (sendmsg or recvmsg) was used in rsocket and now needs cleanup
+ */
+ RPY_EXTERN
+ int free_pointer_to_signedp(int** ptrtofree){
+ free(*ptrtofree);
+ return 0;
+ }
+
+ RPY_EXTERN
+ int free_ptr_to_charp(char** ptrtofree){
+ free(*ptrtofree);
+ return 0;
+ }
+
+ ''',]
+
+ post_include_bits =[ "RPY_EXTERN "
+ "int sendmsg_implementation(int socket, struct sockaddr* address, socklen_t addrlen, long* length_of_messages, char** messages, int no_of_messages, long* levels, long* types, char** file_descriptors, long* no_of_fds, int control_length, int flag );\n"
+ "RPY_EXTERN "
+ "int recvmsg_implementation(int socket_fd, int message_size, int ancillary_size, int flags, struct sockaddr* address, socklen_t* addrlen, long** length_of_messages, char** messages, long* no_of_messages, long* size_of_ancillary, long** levels, long** types, char** file_descr, long** descr_per_ancillary, long* flag);\n"
+ "static "
+ "int cmsg_min_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t space);\n"
+ "static "
+ "int get_cmsg_data_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *space);\n"
+ "static "
+ "int get_cmsg_data_len(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *data_len);\n"
+ "static "
+ "int get_CMSG_LEN(size_t length, size_t *result);\n"
+ "static "
+ "int get_CMSG_SPACE(size_t length, size_t *result);\n"
+ "RPY_EXTERN "
+ "size_t CMSG_LEN_wrapper(size_t desired_len);\n"
+ "RPY_EXTERN "
+ "size_t CMSG_SPACE_wrapper(size_t desired_space);\n"
+ "RPY_EXTERN "
+ "int memcpy_from_CCHARP_at_offset_and_size(char* stringfrom, char** stringto, int offset, int size);\n"
+ "RPY_EXTERN "
+ "int free_pointer_to_signedp(int** ptrtofree);\n"
+ "RPY_EXTERN "
+ "int free_ptr_to_charp(char** ptrtofree);\n"
+ ]
+
+
+ compilation_info = ExternalCompilationInfo(
+ includes=includes,
+ separate_module_sources=separate_module_sources,
+ post_include_bits=post_include_bits,
+ )
+
if _WIN32:
CConfig.WSAEVENT = platform.SimpleType('WSAEVENT', rffi.VOIDP)
CConfig.WSANETWORKEVENTS = platform.Struct(
@@ -387,6 +1035,7 @@
sockaddr_ptr.TO.become(cConfig.sockaddr)
addrinfo_ptr.TO.become(cConfig.addrinfo)
+
# fill in missing constants with reasonable defaults
cConfig.NI_MAXHOST = cConfig.NI_MAXHOST or 1025
cConfig.NI_MAXSERV = cConfig.NI_MAXSERV or 32
@@ -571,11 +1220,32 @@
recvfrom = external('recvfrom', [socketfd_type, rffi.VOIDP, size_t,
rffi.INT, sockaddr_ptr, socklen_t_ptr], rffi.INT,
save_err=SAVE_ERR)
+recvmsg = jit.dont_look_inside(rffi.llexternal("recvmsg_implementation",
+ [rffi.INT, rffi.INT, rffi.INT, rffi.INT,sockaddr_ptr, socklen_t_ptr, rffi.SIGNEDPP, rffi.CCHARPP,
+ rffi.SIGNEDP,rffi.SIGNEDP, rffi.SIGNEDPP, rffi.SIGNEDPP, rffi.CCHARPP, rffi.SIGNEDPP, rffi.SIGNEDP],
+ rffi.INT, save_err=SAVE_ERR,
+ compilation_info=compilation_info))
+
+memcpy_from_CCHARP_at_offset = jit.dont_look_inside(rffi.llexternal("memcpy_from_CCHARP_at_offset_and_size",
+ [rffi.CCHARP, rffi.CCHARPP,rffi.INT,rffi.INT],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+freeccharp = jit.dont_look_inside(rffi.llexternal("free_ptr_to_charp",
+ [rffi.CCHARPP],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+freesignedp = jit.dont_look_inside(rffi.llexternal("free_pointer_to_signedp",
+ [rffi.SIGNEDPP],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+
send = external('send', [socketfd_type, rffi.CCHARP, size_t, rffi.INT],
ssize_t, save_err=SAVE_ERR)
sendto = external('sendto', [socketfd_type, rffi.VOIDP, size_t, rffi.INT,
sockaddr_ptr, socklen_t], ssize_t,
save_err=SAVE_ERR)
+sendmsg = jit.dont_look_inside(rffi.llexternal("sendmsg_implementation",
+ [rffi.INT, sockaddr_ptr, socklen_t, rffi.SIGNEDP, rffi.CCHARPP, rffi.INT,
+ rffi.SIGNEDP, rffi.SIGNEDP, rffi.CCHARPP, rffi.SIGNEDP, rffi.INT, rffi.INT],
+ rffi.INT, save_err=SAVE_ERR,
+ compilation_info=compilation_info))
+CMSG_SPACE = jit.dont_look_inside(rffi.llexternal("CMSG_SPACE_wrapper",[size_t], size_t, save_err=SAVE_ERR,compilation_info=compilation_info))
+CMSG_LEN = jit.dont_look_inside(rffi.llexternal("CMSG_LEN_wrapper",[size_t], size_t, save_err=SAVE_ERR,compilation_info=compilation_info))
+
socketshutdown = external('shutdown', [socketfd_type, rffi.INT], rffi.INT,
save_err=SAVE_ERR)
gethostname = external('gethostname', [rffi.CCHARP, rffi.INT], rffi.INT,
diff --git a/rpython/rlib/rsocket.py b/rpython/rlib/rsocket.py
--- a/rpython/rlib/rsocket.py
+++ b/rpython/rlib/rsocket.py
@@ -963,6 +963,126 @@
return (read_bytes, address)
raise self.error_handler()
+ @jit.dont_look_inside
+ def recvmsg(self, message_size, ancbufsize = 0, flags = 0):
+ """
+ Receive up to message_size bytes from a message. Also receives ancillary data.
+ Returns the message, ancillary, flag and address of the sender.
+ :param message_size: Maximum size of the message to be received
+ :param ancbufsize: Maximum size of the ancillary data to be received
+ :param flags: Receive flag. For more details, please check the Unix manual
+ :return: a tuple consisting of the message, the ancillary data, return flag and the address.
+ """
+ if message_size < 0:
+ raise RSocketError("Invalid message size")
+ if ancbufsize < 0:
+ raise RSocketError("invalid ancillary data buffer length")
+
+ self.wait_for_data(False)
+ address, addr_p, addrlen_p = self._addrbuf()
+ len_of_msgs = lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ messages = lltype.malloc(rffi.CCHARPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False )
+ messages[0] = lltype.malloc(rffi.CCHARP.TO, message_size,flavor='raw',track_allocation=True,nonmovable=False)
+ rffi.c_memset(messages[0], 0, message_size)
+ no_of_messages = lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False )
+ no_of_messages[0] = rffi.cast(rffi.SIGNED, 0)
+ size_of_anc = lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False )
+ size_of_anc[0] = rffi.cast(rffi.SIGNED,0)
+ levels = lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ types = lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ file_descr = lltype.malloc(rffi.CCHARPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False )
+ descr_per_anc = lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ retflag = lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False )
+ retflag[0] = rffi.cast(rffi.SIGNED,0)
+
+ # a mask for the SIGNEDP's that need to be cast to int. (long default)
+ reply = _c.recvmsg(self.fd, rffi.cast(lltype.Signed,message_size),
+ rffi.cast(lltype.Signed,ancbufsize),rffi.cast(lltype.Signed,flags),
+ addr_p, addrlen_p, len_of_msgs, messages, no_of_messages,size_of_anc,
+ levels, types,file_descr,descr_per_anc,retflag)
+ if reply >= 0:
+ anc_size = rffi.cast(rffi.SIGNED,size_of_anc[0])
+ returnflag = rffi.cast(rffi.SIGNED,retflag[0])
+ addrlen = rffi.cast(rffi.SIGNED,addrlen_p[0])
+
+ retmsg = rffi.charpsize2str(messages[0],reply)
+
+ offset = 0
+ list_of_tuples = []
+
+ pre_anc = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw', track_allocation=True, nonmovable=False)
+ for i in range(anc_size):
+ level = rffi.cast(rffi.SIGNED, levels[0][i])
+ type = rffi.cast(rffi.SIGNED, types[0][i])
+ bytes_in_anc = rffi.cast(rffi.SIGNED, descr_per_anc[0][i])
+ pre_anc[0] = lltype.malloc(rffi.CCHARP.TO, bytes_in_anc,flavor='raw',track_allocation=True,nonmovable=False)
+ _c.memcpy_from_CCHARP_at_offset(file_descr[0], pre_anc,rffi.cast(rffi.SIGNED,offset), bytes_in_anc)
+ anc = rffi.charpsize2str(pre_anc[0],bytes_in_anc)
+ tup = (level,type, anc)
+ list_of_tuples.append(tup)
+ offset += bytes_in_anc
+ lltype.free(pre_anc[0], flavor='raw')
+
+ if addrlen:
+ address.addrlen = addrlen
+ else:
+ address.unlock()
+ address = None
+
+ rettup = (retmsg,list_of_tuples,returnflag,address)
+
+ if address is not None:
+ address.unlock()
+ # free underlying complexity first
+ _c.freeccharp(file_descr)
+ _c.freesignedp(len_of_msgs)
+ _c.freesignedp(levels)
+ _c.freesignedp(types)
+ _c.freesignedp(descr_per_anc)
+
+ lltype.free(messages[0], flavor='raw')
+ lltype.free(pre_anc,flavor='raw')
+ lltype.free(messages,flavor='raw')
+ lltype.free(file_descr,flavor='raw')
+ lltype.free(len_of_msgs,flavor='raw')
+ lltype.free(no_of_messages, flavor='raw')
+ lltype.free(size_of_anc, flavor='raw')
+ lltype.free(levels, flavor='raw')
+ lltype.free(types, flavor='raw')
+ lltype.free(descr_per_anc, flavor='raw')
+ lltype.free(retflag, flavor='raw')
+ lltype.free(addrlen_p,flavor='raw')
+
+ return rettup
+ else:
+
+ #in case of failure the underlying complexity has already been freed
+ lltype.free(messages[0], flavor='raw')
+ lltype.free(messages, flavor='raw')
+ lltype.free(file_descr, flavor='raw')
+ lltype.free(len_of_msgs, flavor='raw')
+ lltype.free(no_of_messages, flavor='raw')
+ lltype.free(size_of_anc, flavor='raw')
+ lltype.free(levels, flavor='raw')
+ lltype.free(types, flavor='raw')
+ lltype.free(descr_per_anc, flavor='raw')
+ lltype.free(retflag, flavor='raw')
+ lltype.free(addrlen_p, flavor='raw')
+
+ if address is not None:
+ address.unlock()
+ if _c.geterrno() == _c.EINTR:
+ raise last_error()
+ if (reply == -10000):
+ raise RSocketError("Invalid message size")
+ if (reply == -10001):
+ raise RSocketError("Invalid ancillary data buffer length")
+ if (reply == -10002):
+ raise RSocketError("received malformed or improperly truncated ancillary data")
+ raise last_error()
+
+
+
def send_raw(self, dataptr, length, flags=0):
"""Send data from a CCHARP buffer."""
self.wait_for_data(True)
@@ -1009,6 +1129,86 @@
raise self.error_handler()
return res
+ @jit.dont_look_inside
+ def sendmsg(self, messages, ancillary=None, flags=0, address=None):
+ """
+ Send data and ancillary on a socket. For use of ancillary data, please check the Unix manual.
+ Work on connectionless sockets via the address parameter.
+ :param messages: a message that is a list of strings
+ :param ancillary: data to be sent separate from the message body. Needs to be a list of tuples.
+ E.g. [(level,type, bytes),...]. Default None.
+ :param flags: the flag to be set for sendmsg. Please check the Unix manual regarding values. Default 0
+ :param address: address of the recepient. Useful for when sending on connectionless sockets. Default None
+ :return: Bytes sent from the message
+ """
+ need_to_free_address = True
+ if address is None:
+ need_to_free_address = False
+ addr = lltype.nullptr(_c.sockaddr)
+ addrlen = 0
+ else:
+ addr = address.lock()
+ addrlen = address.addrlen
+
+ no_of_messages = len(messages)
+ messages_ptr = lltype.malloc(rffi.CCHARPP.TO,no_of_messages+1,flavor='raw',track_allocation=True,nonmovable=False)
+ messages_length_ptr = lltype.malloc(rffi.SIGNEDP.TO,no_of_messages,flavor='raw',zero=True, track_allocation=True,nonmovable=False)
+ counter = 0
+ for message in messages:
+ messages_ptr[counter] = rffi.str2charp(message)
+ messages_length_ptr[counter] = rffi.cast(rffi.SIGNED, len(message))
+ counter += 1
+ messages_ptr[counter] = lltype.nullptr(rffi.CCHARP.TO)
+ if ancillary is not None:
+ size_of_ancillary = len(ancillary)
+ else:
+ size_of_ancillary = 0
+ levels = lltype.malloc(rffi.SIGNEDP.TO, size_of_ancillary,flavor='raw',zero=True, track_allocation=True,nonmovable=False)
+ types = lltype.malloc(rffi.SIGNEDP.TO, size_of_ancillary,flavor='raw',zero=True, track_allocation=True,nonmovable=False)
+ desc_per_ancillary = lltype.malloc(rffi.SIGNEDP.TO, size_of_ancillary,flavor='raw',zero=True, track_allocation=True,nonmovable=False)
+ file_descr = lltype.malloc(rffi.CCHARPP.TO, size_of_ancillary,flavor='raw', track_allocation=True,nonmovable=False)
+ if ancillary is not None:
+ counter = 0
+ for level, type, content in ancillary:
+ assert isinstance(type,int)
+ assert isinstance(level, int)
+ levels[counter] = rffi.cast(rffi.SIGNED,level)
+ types[counter] = rffi.cast(rffi.SIGNED,type)
+ desc_per_ancillary[counter] = rffi.cast(rffi.SIGNED, (len(content)))
+ file_descr[counter] = rffi.str2charp(content, track_allocation=True)
+ counter +=1
+ else:
+ size_of_ancillary = 0
+ snd_no_msgs = rffi.cast(rffi.SIGNED, no_of_messages)
+ snd_anc_size =rffi.cast(rffi.SIGNED, size_of_ancillary)
+
+
+ bytes_sent = _c.sendmsg(self.fd, addr, addrlen, messages_length_ptr, messages_ptr, snd_no_msgs,levels,types,file_descr,desc_per_ancillary,snd_anc_size,flags)
+
+
+ if need_to_free_address:
+ address.unlock()
+ for i in range(len(messages)):
+ lltype.free(messages_ptr[i], flavor='raw', track_allocation=True)
+ lltype.free(messages_ptr, flavor='raw', track_allocation=True)
+ lltype.free(messages_length_ptr, flavor='raw', track_allocation=True)
+
+ if size_of_ancillary > 0:
+ for i in range(len(ancillary)):
+ lltype.free(file_descr[i], flavor='raw', track_allocation=True)
+ lltype.free(desc_per_ancillary, flavor='raw', track_allocation=True)
+ lltype.free(types, flavor='raw', track_allocation=True)
+ lltype.free(levels, flavor='raw', track_allocation=True)
+ lltype.free(file_descr, flavor='raw', track_allocation=True)
+
+ self.wait_for_data(True)
+ if (bytes_sent < 0) and (bytes_sent!=-1000) and (bytes_sent!=-1001) and (bytes_sent!=-1002):
+ raise last_error()
+
+ return bytes_sent
+
+
+
def setblocking(self, block):
if block:
timeout = -1.0
@@ -1190,6 +1390,31 @@
return (make_socket(fd0, family, type, proto, SocketClass),
make_socket(fd1, family, type, proto, SocketClass))
+if _c._POSIX:
+ def CMSG_LEN( demanded_len):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param demanded_len: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required size. The value is not memory alligned
+ """
+ if demanded_len < 0:
+ return 0
+ result = _c.CMSG_LEN(demanded_len)
+ return result
+
+ def CMSG_SPACE( demanded_size):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param demanded_size: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required size. The value is memory alligned
+ """
+ if demanded_size < 0:
+ return 0
+ result = _c.CMSG_SPACE(demanded_size)
+ return result
+
if _c.WIN32:
def dup(fd, inheritable=True):
with lltype.scoped_alloc(_c.WSAPROTOCOL_INFO, zero=True) as info:
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -752,7 +752,8 @@
# Signed, Signed *
SIGNED = lltype.Signed
-SIGNEDP = lltype.Ptr(lltype.Array(SIGNED, hints={'nolength': True}))
+SIGNEDP = lltype.Ptr(lltype.Array(lltype.Signed, hints={'nolength': True}))
+SIGNEDPP = lltype.Ptr(lltype.Array(SIGNEDP, hints={'nolength': True}))
# various type mapping
More information about the pypy-commit
mailing list