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:
Martin Blais 2006-05-26 12:03:27 +00:00
parent 1b94940165
commit 2856e5f390
6 changed files with 550 additions and 220 deletions

View File

@ -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()

View File

@ -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 ])

View File

@ -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()

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}