mirror of https://github.com/python/cpython
Support for buffer protocol for socket and struct.
* Added socket.recv_buf() and socket.recvfrom_buf() methods, that use the buffer protocol (send and sendto already did). * Added struct.pack_to(), that is the corresponding buffer compatible method to unpack_from(). * Fixed minor typos in arraymodule.
This commit is contained in:
parent
1b94940165
commit
2856e5f390
|
@ -140,7 +140,9 @@ class _socketobject(object):
|
|||
|
||||
__doc__ = _realsocket.__doc__
|
||||
|
||||
__slots__ = ["_sock", "send", "recv", "sendto", "recvfrom",
|
||||
__slots__ = ["_sock",
|
||||
"recv", "recv_buf", "recvfrom_buf",
|
||||
"send", "sendto", "recvfrom",
|
||||
"__weakref__"]
|
||||
|
||||
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
|
||||
|
@ -149,8 +151,10 @@ class _socketobject(object):
|
|||
self._sock = _sock
|
||||
self.send = self._sock.send
|
||||
self.recv = self._sock.recv
|
||||
self.recv_buf = self._sock.recv_buf
|
||||
self.sendto = self._sock.sendto
|
||||
self.recvfrom = self._sock.recvfrom
|
||||
self.recvfrom_buf = self._sock.recvfrom_buf
|
||||
|
||||
def close(self):
|
||||
self._sock = _closedsocket()
|
||||
|
|
|
@ -9,6 +9,7 @@ import time
|
|||
import thread, threading
|
||||
import Queue
|
||||
import sys
|
||||
import array
|
||||
from weakref import proxy
|
||||
|
||||
PORT = 50007
|
||||
|
@ -852,8 +853,38 @@ class TestLinuxAbstractNamespace(unittest.TestCase):
|
|||
self.assertRaises(socket.error, s.bind, address)
|
||||
|
||||
|
||||
class BufferIOTest(SocketConnectedTest):
|
||||
"""
|
||||
Test the buffer versions of socket.recv() and socket.send().
|
||||
"""
|
||||
def __init__(self, methodName='runTest'):
|
||||
SocketConnectedTest.__init__(self, methodName=methodName)
|
||||
|
||||
def testRecvBuf(self):
|
||||
buf = array.array('c', ' '*1024)
|
||||
nbytes = self.cli_conn.recv_buf(buf)
|
||||
self.assertEqual(nbytes, len(MSG))
|
||||
msg = buf.tostring()[:len(MSG)]
|
||||
self.assertEqual(msg, MSG)
|
||||
|
||||
def _testRecvBuf(self):
|
||||
buf = buffer(MSG)
|
||||
self.serv_conn.send(buf)
|
||||
|
||||
def testRecvFromBuf(self):
|
||||
buf = array.array('c', ' '*1024)
|
||||
nbytes, addr = self.cli_conn.recvfrom_buf(buf)
|
||||
self.assertEqual(nbytes, len(MSG))
|
||||
msg = buf.tostring()[:len(MSG)]
|
||||
self.assertEqual(msg, MSG)
|
||||
|
||||
def _testRecvFromBuf(self):
|
||||
buf = buffer(MSG)
|
||||
self.serv_conn.send(buf)
|
||||
|
||||
def test_main():
|
||||
tests = [GeneralModuleTests, BasicTCPTest, TCPTimeoutTest, TestExceptions]
|
||||
tests = [GeneralModuleTests, BasicTCPTest, TCPTimeoutTest, TestExceptions,
|
||||
BufferIOTest]
|
||||
if sys.platform != 'mac':
|
||||
tests.extend([ BasicUDPTest, UDPTimeoutTest ])
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
from test.test_support import TestFailed, verbose, verify
|
||||
import test.test_support
|
||||
import struct
|
||||
import array
|
||||
import unittest
|
||||
|
||||
import sys
|
||||
ISBIGENDIAN = sys.byteorder == "big"
|
||||
|
@ -438,31 +441,6 @@ def test_705836():
|
|||
|
||||
test_705836()
|
||||
|
||||
def test_unpack_from():
|
||||
test_string = 'abcd01234'
|
||||
fmt = '4s'
|
||||
s = struct.Struct(fmt)
|
||||
for cls in (str, buffer):
|
||||
data = cls(test_string)
|
||||
assert s.unpack_from(data) == ('abcd',)
|
||||
assert s.unpack_from(data, 2) == ('cd01',)
|
||||
assert s.unpack_from(data, 4) == ('0123',)
|
||||
for i in xrange(6):
|
||||
assert s.unpack_from(data, i) == (data[i:i+4],)
|
||||
for i in xrange(6, len(test_string) + 1):
|
||||
simple_err(s.unpack_from, data, i)
|
||||
for cls in (str, buffer):
|
||||
data = cls(test_string)
|
||||
assert struct.unpack_from(fmt, data) == ('abcd',)
|
||||
assert struct.unpack_from(fmt, data, 2) == ('cd01',)
|
||||
assert struct.unpack_from(fmt, data, 4) == ('0123',)
|
||||
for i in xrange(6):
|
||||
assert struct.unpack_from(fmt, data, i) == (data[i:i+4],)
|
||||
for i in xrange(6, len(test_string) + 1):
|
||||
simple_err(struct.unpack_from, fmt, data, i)
|
||||
|
||||
test_unpack_from()
|
||||
|
||||
def test_1229380():
|
||||
for endian in ('', '>', '<'):
|
||||
for cls in (int, long):
|
||||
|
@ -478,3 +456,60 @@ def test_1229380():
|
|||
if 0:
|
||||
# TODO: bug #1229380
|
||||
test_1229380()
|
||||
|
||||
class PackBufferTestCase(unittest.TestCase):
|
||||
"""
|
||||
Test the packing methods that work on buffers.
|
||||
"""
|
||||
|
||||
def test_unpack_from( self ):
|
||||
test_string = 'abcd01234'
|
||||
fmt = '4s'
|
||||
s = struct.Struct(fmt)
|
||||
for cls in (str, buffer):
|
||||
data = cls(test_string)
|
||||
self.assertEquals(s.unpack_from(data), ('abcd',))
|
||||
self.assertEquals(s.unpack_from(data, 2), ('cd01',))
|
||||
self.assertEquals(s.unpack_from(data, 4), ('0123',))
|
||||
for i in xrange(6):
|
||||
self.assertEquals(s.unpack_from(data, i), (data[i:i+4],))
|
||||
for i in xrange(6, len(test_string) + 1):
|
||||
simple_err(s.unpack_from, data, i)
|
||||
for cls in (str, buffer):
|
||||
data = cls(test_string)
|
||||
self.assertEquals(struct.unpack_from(fmt, data), ('abcd',))
|
||||
self.assertEquals(struct.unpack_from(fmt, data, 2), ('cd01',))
|
||||
self.assertEquals(struct.unpack_from(fmt, data, 4), ('0123',))
|
||||
for i in xrange(6):
|
||||
self.assertEquals(struct.unpack_from(fmt, data, i),
|
||||
(data[i:i+4],))
|
||||
for i in xrange(6, len(test_string) + 1):
|
||||
simple_err(struct.unpack_from, fmt, data, i)
|
||||
|
||||
def test_pack_to( self ):
|
||||
test_string = 'Reykjavik rocks, eow!'
|
||||
writable_buf = array.array('c', ' '*100)
|
||||
fmt = '21s'
|
||||
s = struct.Struct(fmt)
|
||||
|
||||
# Test without offset
|
||||
s.pack_to(writable_buf, 0, test_string)
|
||||
from_buf = writable_buf.tostring()[:len(test_string)]
|
||||
self.assertEquals(from_buf, test_string)
|
||||
|
||||
# Test with offset.
|
||||
s.pack_to(writable_buf, 10, test_string)
|
||||
from_buf = writable_buf.tostring()[:len(test_string)+10]
|
||||
self.assertEquals(from_buf, (test_string[:10] + test_string))
|
||||
|
||||
# Go beyond boundaries.
|
||||
small_buf = array.array('c', ' '*10)
|
||||
self.assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
|
||||
self.assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
|
||||
|
||||
def test_main():
|
||||
test.test_support.run_unittest(PackBufferTestCase)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ static PyTypeObject PyStructType;
|
|||
typedef int Py_ssize_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* PY_USE_INT_WHEN_POSSIBLE is an experimental flag that changes the
|
||||
struct API to return int instead of long when possible. This is
|
||||
often a significant performance improvement. */
|
||||
|
@ -24,7 +25,6 @@ typedef int Py_ssize_t;
|
|||
|
||||
|
||||
/* The translation function for each format character is table driven */
|
||||
|
||||
typedef struct _formatdef {
|
||||
char format;
|
||||
int size;
|
||||
|
@ -1315,50 +1315,36 @@ s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
return s_unpack_internal(soself, buffer + offset);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(s_pack__doc__,
|
||||
"pack(v1, v2, ...) -> string\n\
|
||||
\n\
|
||||
Return a string containing values v1, v2, ... packed according to this\n\
|
||||
Struct's format. See struct.__doc__ for more on format strings.");
|
||||
|
||||
static PyObject *
|
||||
s_pack(PyObject *self, PyObject *args)
|
||||
/*
|
||||
* Guts of the pack function.
|
||||
*
|
||||
* Takes a struct object, a tuple of arguments, and offset in that tuple of
|
||||
* argument for where to start processing the arguments for packing, and a
|
||||
* character buffer for writing the packed string. The caller must insure
|
||||
* that the buffer may contain the required length for packing the arguments.
|
||||
* 0 is returned on success, 1 is returned if there is an error.
|
||||
*
|
||||
*/
|
||||
static int
|
||||
s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
|
||||
{
|
||||
PyStructObject *soself;
|
||||
PyObject *result;
|
||||
char *restart;
|
||||
formatcode *code;
|
||||
Py_ssize_t i;
|
||||
|
||||
soself = (PyStructObject *)self;
|
||||
assert(PyStruct_Check(self));
|
||||
assert(soself->s_codes != NULL);
|
||||
if (args == NULL || !PyTuple_Check(args) ||
|
||||
PyTuple_GET_SIZE(args) != soself->s_len)
|
||||
{
|
||||
PyErr_Format(StructError,
|
||||
"pack requires exactly %d arguments", soself->s_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = PyString_FromStringAndSize((char *)NULL, soself->s_size);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
restart = PyString_AS_STRING(result);
|
||||
memset(restart, '\0', soself->s_size);
|
||||
i = 0;
|
||||
|
||||
memset(buf, '\0', soself->s_size);
|
||||
i = offset;
|
||||
for (code = soself->s_codes; code->fmtdef != NULL; code++) {
|
||||
Py_ssize_t n;
|
||||
PyObject *v;
|
||||
const formatdef *e = code->fmtdef;
|
||||
char *res = restart + code->offset;
|
||||
char *res = buf + code->offset;
|
||||
if (e->format == 's') {
|
||||
v = PyTuple_GET_ITEM(args, i++);
|
||||
if (!PyString_Check(v)) {
|
||||
PyErr_SetString(StructError,
|
||||
"argument for 's' must be a string");
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
n = PyString_GET_SIZE(v);
|
||||
if (n > code->size)
|
||||
|
@ -1370,7 +1356,7 @@ s_pack(PyObject *self, PyObject *args)
|
|||
if (!PyString_Check(v)) {
|
||||
PyErr_SetString(StructError,
|
||||
"argument for 'p' must be a string");
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
n = PyString_GET_SIZE(v);
|
||||
if (n > (code->size - 1))
|
||||
|
@ -1383,16 +1369,109 @@ s_pack(PyObject *self, PyObject *args)
|
|||
} else {
|
||||
v = PyTuple_GET_ITEM(args, i++);
|
||||
if (e->pack(res, v, e) < 0)
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
|
||||
PyDoc_STRVAR(s_pack__doc__,
|
||||
"pack(v1, v2, ...) -> string\n\
|
||||
\n\
|
||||
Return a string containing values v1, v2, ... packed according to this\n\
|
||||
Struct's format. See struct.__doc__ for more on format strings.");
|
||||
|
||||
static PyObject *
|
||||
s_pack(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyStructObject *soself;
|
||||
PyObject *result;
|
||||
|
||||
/* Validate arguments. */
|
||||
soself = (PyStructObject *)self;
|
||||
assert(PyStruct_Check(self));
|
||||
assert(soself->s_codes != NULL);
|
||||
if (args == NULL || !PyTuple_Check(args) ||
|
||||
PyTuple_GET_SIZE(args) != soself->s_len)
|
||||
{
|
||||
PyErr_Format(StructError,
|
||||
"pack requires exactly %d arguments", soself->s_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate a new string */
|
||||
result = PyString_FromStringAndSize((char *)NULL, soself->s_size);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Call the guts */
|
||||
if ( s_pack_internal(soself, args, 0, PyString_AS_STRING(result)) != 0 ) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(s_pack_to__doc__,
|
||||
"pack_to(buffer, offset, v1, v2, ...)\n\
|
||||
\n\
|
||||
Pack the values v2, v2, ... according to this Struct's format, write \n\
|
||||
the packed bytes into the given buffer at the given offset. Note that \n\
|
||||
the offset is not an optional argument. See struct.__doc__ for \n\
|
||||
more on format strings.");
|
||||
|
||||
static PyObject *
|
||||
s_pack_to(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyStructObject *soself;
|
||||
char *buffer;
|
||||
Py_ssize_t buffer_len, offset;
|
||||
|
||||
/* Validate arguments. +1 is for the first arg as buffer. */
|
||||
soself = (PyStructObject *)self;
|
||||
assert(PyStruct_Check(self));
|
||||
assert(soself->s_codes != NULL);
|
||||
if (args == NULL || !PyTuple_Check(args) ||
|
||||
PyTuple_GET_SIZE(args) != (soself->s_len + 2))
|
||||
{
|
||||
PyErr_Format(StructError,
|
||||
"pack_to requires exactly %d arguments",
|
||||
(soself->s_len + 2));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extract a writable memory buffer from the first argument */
|
||||
if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0),
|
||||
(void**)&buffer, &buffer_len) == -1 ) {
|
||||
return NULL;
|
||||
}
|
||||
assert( buffer_len >= 0 );
|
||||
|
||||
/* Extract the offset from the first argument */
|
||||
offset = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
|
||||
|
||||
/* Support negative offsets. */
|
||||
if (offset < 0)
|
||||
offset += buffer_len;
|
||||
|
||||
/* Check boundaries */
|
||||
if (offset < 0 || (buffer_len - offset) < soself->s_size) {
|
||||
PyErr_Format(StructError,
|
||||
"pack_to requires a buffer of at least %d bytes",
|
||||
soself->s_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Call the guts */
|
||||
if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1400,6 +1479,7 @@ fail:
|
|||
|
||||
static struct PyMethodDef s_methods[] = {
|
||||
{"pack", (PyCFunction)s_pack, METH_VARARGS, s_pack__doc__},
|
||||
{"pack_to", (PyCFunction)s_pack_to, METH_VARARGS, s_pack_to__doc__},
|
||||
{"unpack", (PyCFunction)s_unpack, METH_O, s_unpack__doc__},
|
||||
{"unpack_from", (PyCFunction)s_unpack_from, METH_KEYWORDS, s_unpack_from__doc__},
|
||||
{NULL, NULL} /* sentinel */
|
||||
|
|
|
@ -1975,9 +1975,9 @@ static PyTypeObject Arraytype = {
|
|||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)array_repr, /* tp_repr */
|
||||
0, /* tp_as _number*/
|
||||
&array_as_sequence, /* tp_as _sequence*/
|
||||
&array_as_mapping, /* tp_as _mapping*/
|
||||
0, /* tp_as_number*/
|
||||
&array_as_sequence, /* tp_as_sequence*/
|
||||
&array_as_mapping, /* tp_as_mapping*/
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
|
|
|
@ -104,7 +104,10 @@ gettimeout() -- return timeout or None\n\
|
|||
listen(n) -- start listening for incoming connections\n\
|
||||
makefile([mode, [bufsize]]) -- return a file object for the socket [*]\n\
|
||||
recv(buflen[, flags]) -- receive data\n\
|
||||
recvfrom(buflen[, flags]) -- receive data and sender's address\n\
|
||||
recv_buf(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\
|
||||
recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\
|
||||
recvfrom_buf(buffer[, nbytes, [, flags])\n\
|
||||
-- receive data and sender\'s address (into a buffer)\n\
|
||||
sendall(data[, flags]) -- send all data\n\
|
||||
send(data[, flags]) -- send data, may not send all of it\n\
|
||||
sendto(data[, flags], addr) -- send data to a given address\n\
|
||||
|
@ -205,7 +208,7 @@ shutdown(how) -- shut down traffic in one or both directions\n\
|
|||
functions are declared correctly if compiling with
|
||||
MIPSPro 7.x in ANSI C mode (default) */
|
||||
|
||||
/* XXX Using _SGIAPI is the wrong thing,
|
||||
/* XXX Using _SGIAPI is the wrong thing,
|
||||
but I don't know what the right thing is. */
|
||||
#undef _SGIAPI /* to avoid warning */
|
||||
#define _SGIAPI 1
|
||||
|
@ -223,8 +226,8 @@ shutdown(how) -- shut down traffic in one or both directions\n\
|
|||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
/* Irix 6.5 fails to define this variable at all. This is needed
|
||||
for both GCC and SGI's compiler. I'd say that the SGI headers
|
||||
/* Irix 6.5 fails to define this variable at all. This is needed
|
||||
for both GCC and SGI's compiler. I'd say that the SGI headers
|
||||
are just busted. Same thing for Solaris. */
|
||||
#if (defined(__sgi) || defined(sun)) && !defined(INET_ADDRSTRLEN)
|
||||
#define INET_ADDRSTRLEN 16
|
||||
|
@ -1194,10 +1197,10 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
|||
args->ob_type->tp_name);
|
||||
return 0;
|
||||
}
|
||||
if (!PyArg_ParseTuple(args, "eti:getsockaddrarg",
|
||||
if (!PyArg_ParseTuple(args, "eti:getsockaddrarg",
|
||||
"idna", &host, &port))
|
||||
return 0;
|
||||
result = setipaddr(host, (struct sockaddr *)addr,
|
||||
result = setipaddr(host, (struct sockaddr *)addr,
|
||||
sizeof(*addr), AF_INET);
|
||||
PyMem_Free(host);
|
||||
if (result < 0)
|
||||
|
@ -1225,12 +1228,12 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
|||
args->ob_type->tp_name);
|
||||
return 0;
|
||||
}
|
||||
if (!PyArg_ParseTuple(args, "eti|ii",
|
||||
if (!PyArg_ParseTuple(args, "eti|ii",
|
||||
"idna", &host, &port, &flowinfo,
|
||||
&scope_id)) {
|
||||
return 0;
|
||||
}
|
||||
result = setipaddr(host, (struct sockaddr *)addr,
|
||||
result = setipaddr(host, (struct sockaddr *)addr,
|
||||
sizeof(*addr), AF_INET6);
|
||||
PyMem_Free(host);
|
||||
if (result < 0)
|
||||
|
@ -1839,7 +1842,7 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
|
|||
int res_size = sizeof res;
|
||||
/* It must be in the exception set */
|
||||
assert(FD_ISSET(s->sock_fd, &fds_exc));
|
||||
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
|
||||
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
|
||||
(char *)&res, &res_size))
|
||||
/* getsockopt also clears WSAGetLastError,
|
||||
so reset it back. */
|
||||
|
@ -2135,95 +2138,126 @@ The mode and buffersize arguments are as for the built-in open() function.");
|
|||
|
||||
#endif /* NO_DUP */
|
||||
|
||||
/*
|
||||
* This is the guts of the recv() and recv_buf() methods, which reads into a
|
||||
* char buffer. If you have any inc/def ref to do to the objects that contain
|
||||
* the buffer, do it in the caller. This function returns the number of bytes
|
||||
* succesfully read. If there was an error, it returns -1. Note that it is
|
||||
* also possible that we return a number of bytes smaller than the request
|
||||
* bytes.
|
||||
*/
|
||||
static int
|
||||
sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
||||
{
|
||||
int timeout, outlen = 0;
|
||||
#ifdef __VMS
|
||||
int remaining, nread;
|
||||
char *read_buf;
|
||||
#endif
|
||||
|
||||
if (!IS_SELECTABLE(s)) {
|
||||
select_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef __VMS
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select(s, 0);
|
||||
if (!timeout)
|
||||
outlen = recv(s->sock_fd, cbuf, len, flags);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (timeout) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return -1;
|
||||
}
|
||||
if (outlen < 0) {
|
||||
/* Note: the call to errorhandler() ALWAYS indirectly returned
|
||||
NULL, so ignore its return value */
|
||||
s->errorhandler();
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
read_buf = cbuf;
|
||||
remaining = len;
|
||||
while (remaining != 0) {
|
||||
unsigned int segment;
|
||||
|
||||
segment = remaining /SEGMENT_SIZE;
|
||||
if (segment != 0) {
|
||||
segment = SEGMENT_SIZE;
|
||||
}
|
||||
else {
|
||||
segment = remaining;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select(s, 0);
|
||||
if (!timeout)
|
||||
nread = recv(s->sock_fd, read_buf, segment, flags);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (timeout) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return -1;
|
||||
}
|
||||
if (nread < 0) {
|
||||
s->errorhandler();
|
||||
return -1;
|
||||
}
|
||||
if (nread != remaining) {
|
||||
read_buf += nread;
|
||||
break;
|
||||
}
|
||||
|
||||
remaining -= segment;
|
||||
read_buf += segment;
|
||||
}
|
||||
outlen = read_buf - cbuf;
|
||||
#endif /* !__VMS */
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
|
||||
/* s.recv(nbytes [,flags]) method */
|
||||
|
||||
static PyObject *
|
||||
sock_recv(PySocketSockObject *s, PyObject *args)
|
||||
{
|
||||
int len, n = 0, flags = 0, timeout;
|
||||
int recvlen, flags = 0, outlen;
|
||||
PyObject *buf;
|
||||
#ifdef __VMS
|
||||
int read_length;
|
||||
char *read_buf;
|
||||
#endif
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags))
|
||||
if (!PyArg_ParseTuple(args, "i|i:recv", &recvlen, &flags))
|
||||
return NULL;
|
||||
|
||||
if (len < 0) {
|
||||
if (recvlen < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"negative buffersize in recv");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = PyString_FromStringAndSize((char *) 0, len);
|
||||
/* Allocate a new string. */
|
||||
buf = PyString_FromStringAndSize((char *) 0, recvlen);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!IS_SELECTABLE(s))
|
||||
return select_error();
|
||||
|
||||
#ifndef __VMS
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select(s, 0);
|
||||
if (!timeout)
|
||||
n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (timeout) {
|
||||
/* Call the guts */
|
||||
outlen = sock_recv_guts(s, PyString_AsString(buf), recvlen, flags);
|
||||
if (outlen < 0) {
|
||||
/* An error occured, release the string and return an
|
||||
error. */
|
||||
Py_DECREF(buf);
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return NULL;
|
||||
}
|
||||
if (n < 0) {
|
||||
Py_DECREF(buf);
|
||||
return s->errorhandler();
|
||||
}
|
||||
if (n != len)
|
||||
_PyString_Resize(&buf, n);
|
||||
#else
|
||||
read_buf = PyString_AsString(buf);
|
||||
read_length = len;
|
||||
while (read_length != 0) {
|
||||
unsigned int segment;
|
||||
|
||||
segment = read_length /SEGMENT_SIZE;
|
||||
if (segment != 0) {
|
||||
segment = SEGMENT_SIZE;
|
||||
}
|
||||
else {
|
||||
segment = read_length;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select(s, 0);
|
||||
if (!timeout)
|
||||
n = recv(s->sock_fd, read_buf, segment, flags);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (timeout) {
|
||||
Py_DECREF(buf);
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
if (outlen != recvlen) {
|
||||
/* We did not read as many bytes as we anticipated, resize the
|
||||
string if possible and be succesful. */
|
||||
if (_PyString_Resize(&buf, outlen) < 0)
|
||||
/* Oopsy, not so succesful after all. */
|
||||
return NULL;
|
||||
}
|
||||
if (n < 0) {
|
||||
Py_DECREF(buf);
|
||||
return s->errorhandler();
|
||||
}
|
||||
if (n != read_length) {
|
||||
read_buf += n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_length -= segment;
|
||||
read_buf += segment;
|
||||
}
|
||||
if (_PyString_Resize(&buf, (read_buf - PyString_AsString(buf))) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* !__VMS */
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -2236,29 +2270,90 @@ at least one byte is available or until the remote end is closed. When\n\
|
|||
the remote end is closed and all data is read, return the empty string.");
|
||||
|
||||
|
||||
/* s.recvfrom(nbytes [,flags]) method */
|
||||
/* s.recv_buf(buffer, [nbytes [,flags]]) method */
|
||||
|
||||
static PyObject *
|
||||
sock_recvfrom(PySocketSockObject *s, PyObject *args)
|
||||
static PyObject*
|
||||
sock_recv_buf(PySocketSockObject *s, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"buffer", "nbytes", "flags", 0};
|
||||
|
||||
int recvlen = 0, flags = 0, readlen;
|
||||
char *buf;
|
||||
int buflen;
|
||||
|
||||
/* Get the buffer's memory */
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|ii:recv", kwlist,
|
||||
&buf, &buflen, &recvlen, &flags))
|
||||
return NULL;
|
||||
assert(buf != 0 && buflen > 0);
|
||||
|
||||
if (recvlen < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"negative buffersize in recv");
|
||||
return NULL;
|
||||
}
|
||||
if (recvlen == 0) {
|
||||
/* If nbytes was not specified, use the buffer's length */
|
||||
recvlen = buflen;
|
||||
}
|
||||
|
||||
/* Check if the buffer is large enough */
|
||||
if (buflen < recvlen) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"buffer too small for requested bytes");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Call the guts */
|
||||
readlen = sock_recv_guts(s, buf, recvlen, flags);
|
||||
if (readlen < 0) {
|
||||
/* Return an error. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the number of bytes read. Note that we do not do anything
|
||||
special here in the case that readlen < recvlen. */
|
||||
return PyInt_FromLong(readlen);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(recv_buf_doc,
|
||||
"recv_buf(buffer, [nbytes[, flags]]) -> nbytes_read\n\
|
||||
\n\
|
||||
A version of recv() that stores its data into a buffer rather than creating \n\
|
||||
a new string. Receive up to buffersize bytes from the socket. If buffersize \n\
|
||||
is not specified (or 0), receive up to the size available in the given buffer.\n\
|
||||
\n\
|
||||
See recv() for documentation about the flags.");
|
||||
|
||||
|
||||
/*
|
||||
* This is the guts of the recv() and recv_buf() methods, which reads into a
|
||||
* char buffer. If you have any inc/def ref to do to the objects that contain
|
||||
* the buffer, do it in the caller. This function returns the number of bytes
|
||||
* succesfully read. If there was an error, it returns -1. Note that it is
|
||||
* also possible that we return a number of bytes smaller than the request
|
||||
* bytes.
|
||||
*
|
||||
* 'addr' is a return value for the address object. Note that you must decref
|
||||
* it yourself.
|
||||
*/
|
||||
static int
|
||||
sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags,
|
||||
PyObject** addr)
|
||||
{
|
||||
sock_addr_t addrbuf;
|
||||
PyObject *buf = NULL;
|
||||
PyObject *addr = NULL;
|
||||
PyObject *ret = NULL;
|
||||
int len, n = 0, flags = 0, timeout;
|
||||
int n = 0, timeout;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags))
|
||||
return NULL;
|
||||
*addr = NULL;
|
||||
|
||||
if (!getsockaddrlen(s, &addrlen))
|
||||
return NULL;
|
||||
buf = PyString_FromStringAndSize((char *) 0, len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
if (!IS_SELECTABLE(s))
|
||||
return select_error();
|
||||
if (!IS_SELECTABLE(s)) {
|
||||
select_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
memset(&addrbuf, 0, addrlen);
|
||||
|
@ -2266,41 +2361,71 @@ sock_recvfrom(PySocketSockObject *s, PyObject *args)
|
|||
if (!timeout) {
|
||||
#ifndef MS_WINDOWS
|
||||
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
|
||||
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
|
||||
n = recvfrom(s->sock_fd, cbuf, len, flags,
|
||||
(struct sockaddr *) &addrbuf, &addrlen);
|
||||
#else
|
||||
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
|
||||
n = recvfrom(s->sock_fd, cbuf, len, flags,
|
||||
(void *) &addrbuf, &addrlen);
|
||||
#endif
|
||||
#else
|
||||
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
|
||||
n = recvfrom(s->sock_fd, cbuf, len, flags,
|
||||
(struct sockaddr *) &addrbuf, &addrlen);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (timeout) {
|
||||
Py_DECREF(buf);
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
if (n < 0) {
|
||||
Py_DECREF(buf);
|
||||
return s->errorhandler();
|
||||
s->errorhandler();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n != len && _PyString_Resize(&buf, n) < 0)
|
||||
if (!(*addr = makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf,
|
||||
addrlen, s->sock_proto)))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* s.recvfrom(nbytes [,flags]) method */
|
||||
|
||||
static PyObject *
|
||||
sock_recvfrom(PySocketSockObject *s, PyObject *args)
|
||||
{
|
||||
PyObject *buf = NULL;
|
||||
PyObject *addr = NULL;
|
||||
PyObject *ret = NULL;
|
||||
int recvlen, outlen, flags = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i:recvfrom", &recvlen, &flags))
|
||||
return NULL;
|
||||
|
||||
if (!(addr = makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf,
|
||||
addrlen, s->sock_proto)))
|
||||
buf = PyString_FromStringAndSize((char *) 0, recvlen);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
outlen = sock_recvfrom_guts(s, PyString_AS_STRING(buf),
|
||||
recvlen, flags, &addr);
|
||||
if (outlen < 0) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
if (outlen != recvlen) {
|
||||
/* We did not read as many bytes as we anticipated, resize the
|
||||
string if possible and be succesful. */
|
||||
if (_PyString_Resize(&buf, outlen) < 0)
|
||||
/* Oopsy, not so succesful after all. */
|
||||
goto finally;
|
||||
}
|
||||
|
||||
ret = PyTuple_Pack(2, buf, addr);
|
||||
|
||||
finally:
|
||||
Py_XDECREF(addr);
|
||||
Py_XDECREF(buf);
|
||||
Py_XDECREF(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2309,6 +2434,57 @@ PyDoc_STRVAR(recvfrom_doc,
|
|||
\n\
|
||||
Like recv(buffersize, flags) but also return the sender's address info.");
|
||||
|
||||
|
||||
/* s.recvfrom_buf(buffer[, nbytes [,flags]]) method */
|
||||
|
||||
static PyObject *
|
||||
sock_recvfrom_buf(PySocketSockObject *s, PyObject *args, PyObject* kwds)
|
||||
{
|
||||
static char *kwlist[] = {"buffer", "nbytes", "flags", 0};
|
||||
|
||||
int recvlen = 0, flags = 0, readlen;
|
||||
char *buf;
|
||||
int buflen;
|
||||
|
||||
PyObject *addr = NULL;
|
||||
PyObject *ret = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|ii:recvfrom", kwlist,
|
||||
&buf, &buflen, &recvlen, &flags))
|
||||
return NULL;
|
||||
assert(buf != 0 && buflen > 0);
|
||||
|
||||
if (recvlen < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"negative buffersize in recv");
|
||||
return NULL;
|
||||
}
|
||||
if (recvlen == 0) {
|
||||
/* If nbytes was not specified, use the buffer's length */
|
||||
recvlen = buflen;
|
||||
}
|
||||
|
||||
readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr);
|
||||
if (readlen < 0) {
|
||||
/* Return an error */
|
||||
goto finally;
|
||||
}
|
||||
|
||||
/* Return the number of bytes read and the address. Note that we do
|
||||
not do anything special here in the case that readlen < recvlen. */
|
||||
ret = PyTuple_Pack(2, PyInt_FromLong(readlen), addr);
|
||||
|
||||
finally:
|
||||
Py_XDECREF(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(recvfrom_buf_doc,
|
||||
"recvfrom_buf(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\
|
||||
\n\
|
||||
Like recv_buf(buffer[, nbytes[, flags]]) but also return the sender's address info.");
|
||||
|
||||
|
||||
/* s.send(data [,flags]) method */
|
||||
|
||||
static PyObject *
|
||||
|
@ -2503,59 +2679,63 @@ of the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR).");
|
|||
/* List of methods for socket objects */
|
||||
|
||||
static PyMethodDef sock_methods[] = {
|
||||
{"accept", (PyCFunction)sock_accept, METH_NOARGS,
|
||||
accept_doc},
|
||||
{"bind", (PyCFunction)sock_bind, METH_O,
|
||||
bind_doc},
|
||||
{"close", (PyCFunction)sock_close, METH_NOARGS,
|
||||
close_doc},
|
||||
{"connect", (PyCFunction)sock_connect, METH_O,
|
||||
connect_doc},
|
||||
{"connect_ex", (PyCFunction)sock_connect_ex, METH_O,
|
||||
connect_ex_doc},
|
||||
{"accept", (PyCFunction)sock_accept, METH_NOARGS,
|
||||
accept_doc},
|
||||
{"bind", (PyCFunction)sock_bind, METH_O,
|
||||
bind_doc},
|
||||
{"close", (PyCFunction)sock_close, METH_NOARGS,
|
||||
close_doc},
|
||||
{"connect", (PyCFunction)sock_connect, METH_O,
|
||||
connect_doc},
|
||||
{"connect_ex", (PyCFunction)sock_connect_ex, METH_O,
|
||||
connect_ex_doc},
|
||||
#ifndef NO_DUP
|
||||
{"dup", (PyCFunction)sock_dup, METH_NOARGS,
|
||||
dup_doc},
|
||||
{"dup", (PyCFunction)sock_dup, METH_NOARGS,
|
||||
dup_doc},
|
||||
#endif
|
||||
{"fileno", (PyCFunction)sock_fileno, METH_NOARGS,
|
||||
fileno_doc},
|
||||
{"fileno", (PyCFunction)sock_fileno, METH_NOARGS,
|
||||
fileno_doc},
|
||||
#ifdef HAVE_GETPEERNAME
|
||||
{"getpeername", (PyCFunction)sock_getpeername,
|
||||
METH_NOARGS, getpeername_doc},
|
||||
{"getpeername", (PyCFunction)sock_getpeername,
|
||||
METH_NOARGS, getpeername_doc},
|
||||
#endif
|
||||
{"getsockname", (PyCFunction)sock_getsockname,
|
||||
METH_NOARGS, getsockname_doc},
|
||||
{"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS,
|
||||
getsockopt_doc},
|
||||
{"listen", (PyCFunction)sock_listen, METH_O,
|
||||
listen_doc},
|
||||
{"getsockname", (PyCFunction)sock_getsockname,
|
||||
METH_NOARGS, getsockname_doc},
|
||||
{"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS,
|
||||
getsockopt_doc},
|
||||
{"listen", (PyCFunction)sock_listen, METH_O,
|
||||
listen_doc},
|
||||
#ifndef NO_DUP
|
||||
{"makefile", (PyCFunction)sock_makefile, METH_VARARGS,
|
||||
makefile_doc},
|
||||
{"makefile", (PyCFunction)sock_makefile, METH_VARARGS,
|
||||
makefile_doc},
|
||||
#endif
|
||||
{"recv", (PyCFunction)sock_recv, METH_VARARGS,
|
||||
recv_doc},
|
||||
{"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS,
|
||||
recvfrom_doc},
|
||||
{"send", (PyCFunction)sock_send, METH_VARARGS,
|
||||
send_doc},
|
||||
{"sendall", (PyCFunction)sock_sendall, METH_VARARGS,
|
||||
sendall_doc},
|
||||
{"sendto", (PyCFunction)sock_sendto, METH_VARARGS,
|
||||
sendto_doc},
|
||||
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
|
||||
setblocking_doc},
|
||||
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
|
||||
settimeout_doc},
|
||||
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
|
||||
gettimeout_doc},
|
||||
{"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS,
|
||||
setsockopt_doc},
|
||||
{"shutdown", (PyCFunction)sock_shutdown, METH_O,
|
||||
shutdown_doc},
|
||||
{"recv", (PyCFunction)sock_recv, METH_VARARGS,
|
||||
recv_doc},
|
||||
{"recv_buf", (PyCFunction)sock_recv_buf, METH_VARARGS | METH_KEYWORDS,
|
||||
recv_buf_doc},
|
||||
{"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS,
|
||||
recvfrom_doc},
|
||||
{"recvfrom_buf", (PyCFunction)sock_recvfrom_buf, METH_VARARGS | METH_KEYWORDS,
|
||||
recvfrom_buf_doc},
|
||||
{"send", (PyCFunction)sock_send, METH_VARARGS,
|
||||
send_doc},
|
||||
{"sendall", (PyCFunction)sock_sendall, METH_VARARGS,
|
||||
sendall_doc},
|
||||
{"sendto", (PyCFunction)sock_sendto, METH_VARARGS,
|
||||
sendto_doc},
|
||||
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
|
||||
setblocking_doc},
|
||||
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
|
||||
settimeout_doc},
|
||||
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
|
||||
gettimeout_doc},
|
||||
{"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS,
|
||||
setsockopt_doc},
|
||||
{"shutdown", (PyCFunction)sock_shutdown, METH_O,
|
||||
shutdown_doc},
|
||||
#ifdef RISCOS
|
||||
{"sleeptaskw", (PyCFunction)sock_sleeptaskw, METH_O,
|
||||
sleeptaskw_doc},
|
||||
{"sleeptaskw", (PyCFunction)sock_sleeptaskw, METH_O,
|
||||
sleeptaskw_doc},
|
||||
#endif
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
@ -3401,7 +3581,7 @@ socket_inet_aton(PyObject *self, PyObject *args)
|
|||
if (strcmp(ip_addr, "255.255.255.255") == 0) {
|
||||
packed_addr = 0xFFFFFFFF;
|
||||
} else {
|
||||
|
||||
|
||||
packed_addr = inet_addr(ip_addr);
|
||||
|
||||
if (packed_addr == INADDR_NONE) { /* invalid address */
|
||||
|
@ -3476,7 +3656,7 @@ socket_inet_pton(PyObject *self, PyObject *args)
|
|||
"can't use AF_INET6, IPv6 is disabled");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
retval = inet_pton(af, ip, packed);
|
||||
if (retval < 0) {
|
||||
|
@ -3499,7 +3679,7 @@ socket_inet_pton(PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(inet_ntop_doc,
|
||||
"inet_ntop(af, packed_ip) -> string formatted IP address\n\
|
||||
\n\
|
||||
|
@ -3517,7 +3697,7 @@ socket_inet_ntop(PyObject *self, PyObject *args)
|
|||
#else
|
||||
char ip[INET_ADDRSTRLEN + 1];
|
||||
#endif
|
||||
|
||||
|
||||
/* Guarantee NUL-termination for PyString_FromString() below */
|
||||
memset((void *) &ip[0], '\0', sizeof(ip));
|
||||
|
||||
|
@ -3595,7 +3775,7 @@ socket_getaddrinfo(PyObject *self, PyObject *args)
|
|||
} else if (PyString_Check(hobj)) {
|
||||
hptr = PyString_AsString(hobj);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"getaddrinfo() argument 1 must be string or None");
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue