Index: Lib/socket.py
===================================================================
--- Lib/socket.py	(revision 73434)
+++ Lib/socket.py	(working copy)
@@ -159,14 +159,14 @@
 # All the method names that must be delegated to either the real socket
 # object or the _closedsocket object.
 _delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into",
-                     "send", "sendto")
+                     "recvmsg", "send", "sendto", "sendmsg")
 
 class _closedsocket(object):
     __slots__ = []
     def _dummy(*args):
         raise error(EBADF, 'Bad file descriptor')
     # All _delegate_methods must also be initialized here.
-    send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
+    send = recv = recv_into = sendto = recvfrom = recvfrom_into = recvmsg = sendmsg = _dummy
     __getattr__ = _dummy
 
 # Wrapper around platform socket objects. This implements
Index: Modules/socketmodule.c
===================================================================
--- Modules/socketmodule.c	(revision 73434)
+++ Modules/socketmodule.c	(working copy)
@@ -251,6 +251,9 @@
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#include <sys/stat.h>
+#include <unistd.h>
+#include "structmember.h"
 
 /* Generic socket object definitions and includes */
 #define PySocket_BUILDING_SOCKET
@@ -1840,6 +1843,7 @@
 	int optname;
 	int res;
 	PyObject *buf;
+	char *data;
 	socklen_t buflen = 0;
 
 #ifdef __BEOS__
@@ -1852,6 +1856,36 @@
 			      &level, &optname, &buflen))
 		return NULL;
 
+#ifdef SO_PEERCRED
+	if( level == SOL_SOCKET && optname == SO_PEERCRED ) {
+	    /* Buffer length for struct ucred, ignore parameter. */
+	    buflen = sizeof(int)*3;
+
+	    /* Allocate ucred structure and data buffer. */
+	    if( !( buf = PyType_GenericAlloc((PyTypeObject*)&ucred_type,1) ) )
+		return NULL;
+	    if( !( data = PyMem_Malloc(buflen) ) ) {
+		Py_DECREF(buf);
+		return NULL;
+	    }
+
+	    /* Use getsockopt to retrieve data. */
+	    if( ( res = getsockopt(s->sock_fd,level,optname,data,&buflen) ) < 
+		0 ) {
+		Py_DECREF(buf);
+		return s->errorhandler();
+	    }
+
+	    /* Write it out to object. */
+	    ((PySocketUcredObject*)buf)->uid = ((int*)data)[1];
+	    ((PySocketUcredObject*)buf)->gid = ((int*)data)[2];
+	    ((PySocketUcredObject*)buf)->pid = ((int*)data)[0];
+
+	    /* Free data buffer and return. */
+	    PyMem_Free(data);
+	    return buf;
+	}
+#endif
 	if (buflen == 0) {
 		int flag = 0;
 		socklen_t flagsize = sizeof flag;
@@ -2871,6 +2905,455 @@
 
 #endif
 
+/* This is defined as the normal OS-buffer in the corresponding RFC. */
+#define RECVMSG_MAX_ABUFFER_LEN 10240
+
+static PyObject *
+sock_recvmsg(PySocketSockObject *s, PyObject *args)
+{
+	int res = -1, cmsgdatalen, flags = 0, timeout, recvlen, recvanc = 1, i = 0;
+	int fd, fdtype /* , fdfamily, fdproto for sockets, TODO... */;
+	struct iovec iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsgh;
+	struct stat fdstat;
+	char *fdmode;
+	PyObject *rv = NULL, *rvitem = NULL, *addrarg = NULL, *curitem = NULL,
+		*newitem = NULL;
+
+	/* Initialize iov and msg buffer. */
+	memset((void*)&iov, 0, sizeof(iov));
+	memset((void*)&msg, 0, sizeof(msg));
+
+	/* Parse arguments. Argument are: recv length, address object, flags. */
+	if(!PyArg_ParseTuple(args, "i|Oii:recvmsg",
+	   &recvlen, &addrarg, &recvanc, &flags))
+		goto error;
+
+	/* Create IO Vector from buffer length. */
+	if(recvlen <= 0) {
+		PyErr_SetString(PyExc_ValueError,
+				"receive length must be >= 0.");
+		goto error;
+	}
+
+	iov.iov_base = PyMem_Malloc(recvlen);
+	if(!iov.iov_base) {
+		PyErr_SetString(PyExc_MemoryError,
+				"cannot allocate memory for receive buffer.");
+		goto error;
+	}
+	iov.iov_len = recvlen;
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	/* Parse name parameter. */
+	if(addrarg && addrarg != Py_None)
+		if(!getsockaddrarg(s, addrarg,
+		   (struct sockaddr**)&msg.msg_name,
+		   (int*)&msg.msg_namelen))
+			goto error;
+
+	/* Create buffer for control messages. */
+	if(recvanc) {
+		msg.msg_control = PyMem_Malloc(RECVMSG_MAX_ABUFFER_LEN);
+		if(!msg.msg_control) {
+			PyErr_SetString(PyExc_MemoryError,
+				"cannot allocate memory for ancmsg buffer.");
+			goto error;
+		}
+		msg.msg_controllen = RECVMSG_MAX_ABUFFER_LEN;
+	}
+
+	/* Call function, allowing threads. */
+	Py_BEGIN_ALLOW_THREADS;
+	timeout = internal_select(s, 0);
+	if(!timeout)
+		res = recvmsg(s->sock_fd, &msg,flags);
+	Py_END_ALLOW_THREADS;
+
+	/* Return value was -1, a socket error. */
+	if (timeout) {
+		PyErr_SetString(socket_timeout, "timed out");
+		goto error;
+	} else if(res == -1) {
+		s->errorhandler();
+		goto error;
+	}
+
+	/* Initialize cmsg header pointer. */
+	cmsgh = CMSG_FIRSTHDR(&msg);
+
+	/* Create new return value. */
+	if(!(rv = PyTuple_New(3)))
+		goto cmsg_error;
+
+	/* Create new message string. */
+	if(!(rvitem = PyString_FromStringAndSize((const char*)iov.iov_base,
+	   res)))
+		goto cmsg_error;
+
+	PyTuple_SET_ITEM(rv, 0, rvitem);
+
+	/* Pack control messages. */
+	if(!(rvitem = PyList_New(0)))
+		goto cmsg_error;
+
+	while(cmsgh) {
+		/* Check for data content of cmsg struct. */
+		if((cmsgdatalen = cmsgh->cmsg_len - sizeof(struct cmsghdr))) {
+			/* Did we receive a SCM_RIGHTS message? */
+			if(cmsgh->cmsg_level == SOL_SOCKET &&
+			   cmsgh->cmsg_type == SCM_RIGHTS){
+				/* Create list to store files. */
+				if(!(curitem = PyList_New(0)))
+					goto cmsg_error;
+
+				/* Loop over files and create Python objects for them. */
+				for(; i < cmsgdatalen; i += sizeof(int)) {
+					/* Get file descriptor and type. */
+					fd = *((int*)(CMSG_DATA(cmsgh) + i));
+					if(fstat(fd, &fdstat)) {
+						PyErr_SetString(PyExc_IOError,"stat on desc failed.");
+						goto cmsg_error;
+					}
+
+					/* Check for file descriptor type. */
+					if(S_ISSOCK(fdstat.st_mode)) {
+						/* Get socket parameters.
+						   TODO: Implement, currently noop to do something
+						   sensible. */
+						close(fd);
+						continue;
+					} else if(S_ISDIR(fdstat.st_mode)) {
+						/* We don't support opening directories in Python. Do
+						   something sensible, TODO, don't error for now. */
+						close(fd);
+						continue;
+					} else {
+						/* We got a file(-like descriptor). */
+						/* Get file open flags from file descriptor. */
+						if((fdtype = fcntl(fd, F_GETFL)) == -1) {
+							PyErr_SetString(PyExc_IOError,
+									"could not get flags");
+							goto cmsg_error;
+						}
+
+						/* Check for file type. */
+						if((fdtype & O_RDWR) && (fdtype & O_APPEND))
+							fdmode = "a+";
+						else if((fdtype & O_WRONLY) && (fdtype & O_APPEND))
+							fdmode = "a";
+						else if(fdtype & O_RDWR)
+							fdmode = "r+";
+						else if(fdtype & O_WRONLY)
+							fdmode = "w";
+						else	/* We got some combination which sucks... Just
+							open in reading mode, which should work. */
+							fdmode = "r";
+
+						/* Create new Python file object. */
+						if(!(newitem = PyFile_FromFile(fdopen(fd, fdmode),
+						   "<SCM_RIGHTS file>", fdmode, fclose)))
+							goto cmsg_error;
+					}
+
+					/* And append to list of file objects. */
+					if(PyList_Append(curitem,newitem)) {
+						/* This file is in a fileob already, it's closed by
+						   destroying newitem. */
+						i += sizeof(int);
+						goto cmsg_error;
+					}
+					Py_DECREF(newitem);
+					newitem = NULL;
+				} // for
+#ifdef SCM_CREDENTIALS /* Linux 2.2+ only! */
+			} else if(cmsgh->cmsg_level == SOL_SOCKET &&
+				  cmsgh->cmsg_type == SCM_CREDENTIALS) {
+				/* Allocate new ucred. */
+				if(!(curitem = PyType_GenericAlloc((PyTypeObject*)&ucred_type,
+				   1)))
+					goto cmsg_error;
+
+				/* Store data in it. */
+				((PySocketUcredObject*)curitem)->uid =
+				    ((int*)CMSG_DATA(cmsgh))[1];
+				((PySocketUcredObject*)curitem)->gid =
+				    ((int*)CMSG_DATA(cmsgh))[2];
+				((PySocketUcredObject*)curitem)->pid =
+				    ((int*)CMSG_DATA(cmsgh))[0];
+#endif
+			} else
+				/* We got something else with data. What is this? Don't parse
+				   it. */
+				curitem = Py_BuildValue("iis#", cmsgh->cmsg_level,
+						cmsgh->cmsg_type, CMSG_DATA(cmsgh),
+						cmsgdatalen);
+		} else
+			/* We got something else with no data. What is this? Don't do any
+			   more guesswork. */
+			curitem = Py_BuildValue("iis", cmsgh->cmsg_level,
+					cmsgh->cmsg_type, NULL);
+
+		if(!curitem)
+			goto cmsg_error;
+		if(PyList_Append(rvitem, curitem))
+			goto cmsg_error;
+		Py_DECREF(curitem);
+		curitem = NULL;
+
+		cmsgh = CMSG_NXTHDR(&msg, cmsgh);
+		i = 0;
+	} // while
+
+	PyTuple_SET_ITEM(rv, 1, rvitem);
+
+	/* Append flags to return value. */
+	if(!(rvitem = PyInt_FromLong(msg.msg_flags)))
+		/* By getting here, we are sure that all fds have been properly put
+		   into a list if there were any. We don't have to handle cmsgs
+		   anymore. */
+		goto error;
+		PyTuple_SET_ITEM(rv, 2, rvitem);
+
+	/* Make sure rvitem is zeroed. */
+	rvitem = NULL;
+
+	goto finish;
+
+cmsg_error:
+	while(cmsgh) {
+		/* Close all descriptors coming from SCM_RIGHTS, so they don't leak. */
+		if(cmsgh->cmsg_level == SOL_SOCKET &&
+		   cmsgh->cmsg_type == SCM_RIGHTS) {
+			/* Close all additional descriptors by hand, the rest is handled
+			   by destroying the Python objects referencing them. */
+			cmsgdatalen = cmsgh->cmsg_len - sizeof(struct cmsghdr);
+			for(; i < cmsgdatalen; i += sizeof(int))
+				/* Ignore all errors here, these should close... */
+				close(*((int*)(CMSG_DATA(cmsgh) + i)));
+
+			/* Reset i, which isn't reset by loop. */
+			i = 0;
+		}
+
+		/* Go to next message header. */
+		cmsgh = CMSG_NXTHDR(&msg, cmsgh);
+	}
+
+error:
+	Py_XDECREF(newitem);
+	Py_XDECREF(curitem);
+	Py_XDECREF(rvitem);
+	Py_XDECREF(rv);
+	rv = NULL;
+
+finish:
+	if(iov.iov_base) PyMem_Free(iov.iov_base);
+	if(msg.msg_control) PyMem_Free(msg.msg_control);
+	return rv;
+}
+
+PyDoc_STRVAR(recvmsg_doc,
+"recvmsg(len,[addr,[ancmsg,[flags]]]) ->\n\
+(data,[data,...],msg_flags)\n\
+\n\
+Receive data (and possible ancilliary messages) from the remote end\n\
+of this socket. Ancilliary messages are split into tuples, which are\n\
+then returned as a list. In case no message is available, returns an\n\
+empty list. Otherwise the function is similar to recv().");
+
+#define SENDMSG_MAX_ABUFFER_LEN 10240
+
+static PyObject *
+sock_sendmsg(PySocketSockObject *s, PyObject *args)
+{
+	int res = -1, cmsgdatalen, reallen = 0, flags = 0, timeout, *curfd;
+	struct iovec iov;
+	struct msghdr msg;
+	void *cmsgdata;
+	struct cmsghdr *cmsgh;
+	PyObject *rv = NULL, *addrarg = NULL, *iterarg = NULL, *iter = NULL,
+		 *curitem = NULL, *subiter = NULL, *subcuritem = NULL,
+		 *fileno = NULL;
+
+	memset((void*)&iov,0,sizeof(iov));
+	memset((void*)&msg,0,sizeof(msg));
+
+	if(!PyArg_ParseTuple(args,"s#|OOi:sendmsg",
+	   &iov.iov_base,&iov.iov_len,
+	   &addrarg,&iterarg,&flags))
+		goto error;
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	if(addrarg && addrarg != Py_None)
+		if(!getsockaddrarg(s, addrarg,
+		   (struct sockaddr**)&msg.msg_name, (int*)&msg.msg_namelen))
+			goto error;
+
+	if(iterarg && iterarg != Py_None) {
+		if(!(iter = PyObject_GetIter(iterarg)))
+			goto error;
+
+		msg.msg_control = PyMem_Malloc(SENDMSG_MAX_ABUFFER_LEN);
+		if(!msg.msg_control) {
+			PyErr_SetString(PyExc_MemoryError,
+				    "no memory left for ancillary buffer.");
+			goto error;
+		}
+		msg.msg_controllen = SENDMSG_MAX_ABUFFER_LEN;
+
+		cmsgh = CMSG_FIRSTHDR(&msg);
+		while((curitem = PyIter_Next(iter))) {
+			if(PyObject_IsInstance(curitem, (PyObject*)&ucred_type)) {
+				/* Calculate correct data length. */
+				cmsgdatalen = sizeof(int)*3;
+
+				/* We got a ucred() structure, parse and send. */
+				if(reallen + CMSG_SPACE(cmsgdatalen) >
+				   SENDMSG_MAX_ABUFFER_LEN) {
+					PyErr_SetString(PyExc_ValueError,
+						"too much ancmsg to send.");
+					goto error;
+				}
+
+				/* Set cmsg level and type. */
+				cmsgh->cmsg_level = SOL_SOCKET;
+				cmsgh->cmsg_type = SCM_CREDENTIALS;
+
+				/* Store data into cmsgdata. */
+				((int*)CMSG_DATA(cmsgh))[1] =
+					((PySocketUcredObject*)curitem)->uid;
+				((int*)CMSG_DATA(cmsgh))[2] =
+					((PySocketUcredObject*)curitem)->gid;
+				((int*)CMSG_DATA(cmsgh))[0] =
+					((PySocketUcredObject*)curitem)->pid;
+			} else if(PyArg_ParseTuple(curitem, "iiz#",
+				  &cmsgh->cmsg_level,
+				  &cmsgh->cmsg_type,
+				  &cmsgdata,
+				  &cmsgdatalen)) {
+				/* We got a string message that isn't parsed any further. */
+				/* Check whether the string data is too long. */
+				if(reallen + CMSG_SPACE(cmsgdatalen) >
+				   SENDMSG_MAX_ABUFFER_LEN) {
+					PyErr_SetString(PyExc_ValueError,
+						"too much ancmsg to send.");
+					goto error;
+				}
+
+				/* If we have data, store it into cmsgdata. */
+				if(cmsgdatalen)
+					memcpy(CMSG_DATA(cmsgh), cmsgdata, cmsgdatalen);
+
+			} else {
+				/* First clear error. */
+				PyErr_Clear();
+
+				/* We probably have a list of file(-like) objects with fileno
+				   methods. */
+				if(!(subiter = PyObject_GetIter(curitem)))
+					goto error;
+
+				/* Initialize pointers. */
+				cmsgdatalen = 0;
+				curfd = (int*)CMSG_DATA(cmsgh);
+
+				/* Set cmsg level and type. */
+				cmsgh->cmsg_level = SOL_SOCKET;
+				cmsgh->cmsg_type = SCM_RIGHTS;
+
+				/* Walk over subitems. */
+				while((subcuritem = PyIter_Next(subiter))) {
+					/* Get fileno of subcuritem. */
+					if(!(fileno = PyObject_CallMethod(subcuritem,
+					   "fileno", NULL)))
+						goto error;
+
+					/* Check for size. */
+					cmsgdatalen += sizeof(int);
+					if(reallen + CMSG_SPACE(cmsgdatalen) >
+					    SENDMSG_MAX_ABUFFER_LEN) {
+						PyErr_SetString(PyExc_ValueError,
+						    "too much ancmsg to send.");
+						goto error;
+					}
+
+					/* Store fileno and check for correct conversion. */
+					*curfd = PyInt_AsLong(fileno);
+					curfd++;
+					if(PyErr_Occurred())
+						goto error;
+
+					/* Remove subcuritem. */
+					Py_DECREF(fileno);
+					Py_DECREF(subcuritem);
+					subcuritem = NULL;
+				}
+
+				/* Remove reference to iterator. */
+				Py_DECREF(subiter);
+				subiter = NULL;
+			}
+
+			/* Set message length and update sent length. */
+			cmsgh->cmsg_len = CMSG_LEN(cmsgdatalen);
+			reallen += CMSG_SPACE(cmsgdatalen);
+
+			/* Remove curitem. */
+			Py_DECREF(curitem);
+			curitem = NULL;
+
+			/* Go to next message in buffer. */
+			cmsgh = CMSG_NXTHDR(&msg, cmsgh);
+		} // while
+
+		msg.msg_controllen = reallen;
+	} // if
+
+	Py_BEGIN_ALLOW_THREADS;
+	timeout = internal_select(s, 1);
+	if (!timeout)
+		res = sendmsg(s->sock_fd, &msg, flags);
+	Py_END_ALLOW_THREADS;
+
+	if (timeout) {
+		PyErr_SetString(socket_timeout, "timed out");
+		goto error;
+	} else if( res == -1 )
+		goto sockerror;
+
+	rv = PyInt_FromLong(res);
+	goto finish;
+
+sockerror:
+	s->errorhandler();
+
+error:
+	Py_XDECREF(rv);
+	rv = NULL;
+
+finish:
+	Py_XDECREF(subcuritem);
+	Py_XDECREF(subiter);
+	Py_XDECREF(curitem);
+	Py_XDECREF(iter);
+	if(msg.msg_control) PyMem_Free(msg.msg_control);
+	return rv;
+}
+
+PyDoc_STRVAR(sendmsg_doc,
+"sendmsg(data,[addr,[[(msg-level,msg-type,msg-data),...],[flags]]]) ->\n\
+sendlen\n\
+\n\
+Send data over a socket. You can additionally send ancilliary messages\n\
+over the socket by specifying them as a list (or any other iterable).\n\
+All other parameters are just as they are to sendto().");
+
 /* List of methods for socket objects */
 
 static PyMethodDef sock_methods[] = {
@@ -2932,6 +3415,10 @@
 			  setsockopt_doc},
 	{"shutdown",	  (PyCFunction)sock_shutdown, METH_O,
 			  shutdown_doc},
+	{"recvmsg",	  (PyCFunction)sock_recvmsg, METH_VARARGS,
+			  recvmsg_doc},
+	{"sendmsg",	  (PyCFunction)sock_sendmsg, METH_VARARGS,
+			  sendmsg_doc},
 #ifdef RISCOS
 	{"sleeptaskw",	  (PyCFunction)sock_sleeptaskw, METH_O,
 	 		  sleeptaskw_doc},
@@ -3082,7 +3569,80 @@
 	PyObject_Del,				/* tp_free */
 };
 
+/* Python interface to struct ucred. */
+#ifdef SO_PASSCRED
 
+static int
+ucred_init(PySocketUcredObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"uid","gid","pid",NULL};
+
+    if( !PyArg_ParseTupleAndKeywords(args,kwargs,"iii",kwlist,
+				     &self->uid,&self->gid,&self->pid) )
+        return -1;
+
+    return 0;
+}
+
+static PyMemberDef ucred_members[] = {
+    {"uid",T_INT,offsetof(PySocketUcredObject,uid),READONLY,
+     "User ID of communicating process"},
+    {"gid",T_INT,offsetof(PySocketUcredObject,gid),READONLY,
+     "Group ID of communicating process"},
+    {"pid",T_INT,offsetof(PySocketUcredObject,pid),READONLY,
+     "Process ID of communicating process"},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef ucred_methods[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyTypeObject ucred_type = {
+	PyObject_HEAD_INIT(0)	/* Must fill in type value later */
+	0,					/* ob_size */
+	"_socket.ucred",			/* tp_name */
+	sizeof(PySocketUcredObject),		/* tp_basicsize */
+	0,					/* tp_itemsize */
+	0,		                        /* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,			                /* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	0,                                      /* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+	0,				        /* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	ucred_methods,	       		        /* tp_methods */
+	ucred_members,	       			/* tp_members */
+	0,					/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	(initproc)ucred_init,    		/* tp_init */
+	0,			                /* tp_alloc */
+	PyType_GenericNew,	       		/* tp_new */
+	0,				        /* tp_free */
+};
+
+#endif
+
 /* Python interface to gethostname(). */
 
 /*ARGSUSED*/
@@ -4435,6 +4995,12 @@
 			       (PyObject *)&sock_type) != 0)
 		return;
 
+	if( PyType_Ready(&ucred_type) < 0 )
+	    return;
+	Py_INCREF(&ucred_type);
+	if( PyModule_AddObject(m,"ucred",(PyObject*)&ucred_type) )
+	    return;
+
 #ifdef ENABLE_IPV6
 	has_ipv6 = Py_True;
 #else
@@ -4728,6 +5294,12 @@
 #ifdef	SO_TYPE
 	PyModule_AddIntConstant(m, "SO_TYPE", SO_TYPE);
 #endif
+#ifdef  SO_PASSCRED
+	PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED);
+#endif
+#ifdef  SO_PEERCRED
+	PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED);
+#endif
 
 	/* Maximum number of connections for "listen" */
 #ifdef	SOMAXCONN
@@ -4736,6 +5308,14 @@
 	PyModule_AddIntConstant(m, "SOMAXCONN", 5); /* Common value */
 #endif
 
+	/* Ancilliary message types */
+#ifdef  SCM_RIGHTS
+	PyModule_AddIntConstant(m, "SCM_RIGHTS", SCM_RIGHTS);
+#endif
+#ifdef  SCM_CREDENTIALS
+	PyModule_AddIntConstant(m, "SCM_CREDENTIALS", SCM_CREDENTIALS);
+#endif
+
 	/* Flags for send, recv */
 #ifdef	MSG_OOB
 	PyModule_AddIntConstant(m, "MSG_OOB", MSG_OOB);
Index: Modules/socketmodule.h
===================================================================
--- Modules/socketmodule.h	(revision 73434)
+++ Modules/socketmodule.h	(working copy)
@@ -133,6 +133,15 @@
 					    0.0 means non-blocking */
 } PySocketSockObject;
 
+static PyTypeObject ucred_type;
+
+typedef struct {
+    PyObject_HEAD
+    int uid; /* UID of the communicating process. */
+    int gid; /* GID of the communicating process. */
+    int pid; /* PID of the communicating process. */
+} PySocketUcredObject;
+
 /* --- C API ----------------------------------------------------*/
 
 /* Short explanation of what this C API export mechanism does
