[Python-checkins] r46162 - in python/branches/blais-bytebuf: Lib/socket.py Lib/test/test_socket.py Modules/socketmodule.c

martin.blais python-checkins at python.org
Wed May 24 13:11:28 CEST 2006


Author: martin.blais
Date: Wed May 24 13:11:27 2006
New Revision: 46162

Modified:
   python/branches/blais-bytebuf/Lib/socket.py
   python/branches/blais-bytebuf/Lib/test/test_socket.py
   python/branches/blais-bytebuf/Modules/socketmodule.c
Log:
Implemented recvfrom_buf

Modified: python/branches/blais-bytebuf/Lib/socket.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/socket.py	(original)
+++ python/branches/blais-bytebuf/Lib/socket.py	Wed May 24 13:11:27 2006
@@ -140,7 +140,9 @@
 
     __doc__ = _realsocket.__doc__
 
-    __slots__ = ["_sock", "send", "recv", "recv_buf", "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):
@@ -152,6 +154,7 @@
         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()

Modified: python/branches/blais-bytebuf/Lib/test/test_socket.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/test/test_socket.py	(original)
+++ python/branches/blais-bytebuf/Lib/test/test_socket.py	Wed May 24 13:11:27 2006
@@ -866,24 +866,25 @@
         buf = array.array('c', ' '*1024)
         nbytes = self.cli_conn.recv_buf(buf)
         self.assertEqual(nbytes, len(MSG))
-        trunc = buf.tostring()[:len(MSG)]
-        self.assertEqual(trunc, MSG)
+        msg = buf.tostring()[:len(MSG)]
+        self.assertEqual(msg, MSG)
 
     def _testRecv(self):
         # Send using a read-only buffer.
         buf = buffer(MSG)
         self.serv_conn.send(buf)
 
-    def testRecvBB(self):
-        # Receive into the buffer of an array class.
+    def testRecv2(self):
+        # Receive into a bytebuf.
         buf = bytebuf.bytebuf(1024)
         nbytes = self.cli_conn.recv_buf(buf)
         self.assertEqual(nbytes, len(MSG))
-        trunc = str(buf)[:len(MSG)]
-        self.assertEqual(trunc, MSG)
+        msg = str(buf)[:len(MSG)]
+        self.assertEqual(msg, MSG)
 
-    def _testRecvBB(self):
-        # Send using a read-only buffer.
+    def _testRecv2(self):
+        # Send using a bytebuf.
+## FIXME: todo
 ##         buf = bytebuf.bytebuf(MSG)
         self.serv_conn.send(MSG)
 
@@ -897,13 +898,31 @@
 ##     def _testOverFlowRecv(self):
 ##         self.serv_conn.send(MSG)
 
-##     def testRecvFrom(self):
-##         # Testing large recvfrom() over TCP
-##         msg, addr = self.cli_conn.recvfrom(1024)
-##         self.assertEqual(msg, MSG)
+    def testRecvFrom(self):
+        # Testing large recvfrom() over TCP
+        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 _testRecvFrom(self):
-##         self.serv_conn.send(MSG)
+    def _testRecvFrom(self):
+        buf = buffer(MSG)
+        self.serv_conn.send(buf)
+
+    def testRecvFrom2(self):
+        # Testing large recvfrom() over TCP
+        buf = bytebuf.bytebuf(1024)
+        nbytes, addr = self.cli_conn.recvfrom_buf(buf)
+        self.assertEqual(nbytes, len(MSG))
+        msg = str(buf)[:len(MSG)]
+        self.assertEqual(msg, MSG)
+
+    def _testRecvFrom2(self):
+        # Send using a bytebuf.
+## FIXME: todo
+##         buf = bytebuf.bytebuf(MSG)
+        self.serv_conn.send(MSG)
 
 ##     def testOverFlowRecvFrom(self):
 ##         # Testing recvfrom() in chunks over TCP

Modified: python/branches/blais-bytebuf/Modules/socketmodule.c
==============================================================================
--- python/branches/blais-bytebuf/Modules/socketmodule.c	(original)
+++ python/branches/blais-bytebuf/Modules/socketmodule.c	Wed May 24 13:11:27 2006
@@ -104,7 +104,10 @@
 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 @@
    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 @@
 #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 @@
 				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 @@
 				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 @@
 					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. */
@@ -2323,29 +2326,34 @@
 See recv() for documentation about the flags.");
 
 
-/* s.recvfrom(nbytes [,flags]) method */
-
-static PyObject *
-sock_recvfrom(PySocketSockObject *s, PyObject *args)
+/*
+ * 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);
@@ -2353,41 +2361,71 @@
 	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;
 }
 
@@ -2396,6 +2434,57 @@
 \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 *
@@ -2590,61 +2679,63 @@
 /* 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},
-	{"recv_buf",	(PyCFunction)sock_recv_buf, METH_VARARGS | METH_KEYWORDS,
-			recv_buf_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 */
 };
@@ -3490,7 +3581,7 @@
 	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 */
@@ -3565,7 +3656,7 @@
 				"can't use AF_INET6, IPv6 is disabled");
 		return NULL;
 	}
-#endif 
+#endif
 
 	retval = inet_pton(af, ip, packed);
 	if (retval < 0) {
@@ -3588,7 +3679,7 @@
 		return NULL;
 	}
 }
-	
+
 PyDoc_STRVAR(inet_ntop_doc,
 "inet_ntop(af, packed_ip) -> string formatted IP address\n\
 \n\
@@ -3606,7 +3697,7 @@
 #else
 	char ip[INET_ADDRSTRLEN + 1];
 #endif
-	
+
 	/* Guarantee NUL-termination for PyString_FromString() below */
 	memset((void *) &ip[0], '\0', sizeof(ip));
 
@@ -3684,7 +3775,7 @@
 	} 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;
 	}


More information about the Python-checkins mailing list