Mercurial > hg
comparison mercurial/cext/osutil.c @ 49275:c6a3243567b6
chg: replace mercurial.util.recvfds() by simpler pure Python implementation
On Python 3, we have socket.socket.recvmsg(). This makes it possible to receive
FDs in pure Python code. The new code behaves like the previous
implementations, except that it’s more strict about the format of the ancillary
data. This works because we know in which format the FDs are passed.
Because the code is (and always has been) specific to chg (payload is 1 byte,
number of passed FDs is limited) and we now have only one implementation and
the code is very short, I decided to stop exposing a function in
mercurial.util.
Note on terminology: The SCM_RIGHTS mechanism is used to share open file
descriptions to another process over a socket. The sending side passes an array
of file descriptors and the receiving side receives an array of file
descriptors. The file descriptors are different in general on both sides but
refer to the same open file descriptions. The two terms are often conflated,
even in the official documentation. That’s why I used “FD” above, which could
mean both “file descriptor” and “file description”.
author | Manuel Jacob <me@manueljacob.de> |
---|---|
date | Thu, 02 Jun 2022 23:57:56 +0200 |
parents | 2ef3b7d30cc1 |
children | b619ba39d10a |
comparison
equal
deleted
inserted
replaced
49273:34020d1f1635 | 49275:c6a3243567b6 |
---|---|
683 bail: | 683 bail: |
684 Py_DECREF(stats); | 684 Py_DECREF(stats); |
685 return NULL; | 685 return NULL; |
686 } | 686 } |
687 | 687 |
688 /* | |
689 * recvfds() simply does not release GIL during blocking io operation because | |
690 * command server is known to be single-threaded. | |
691 * | |
692 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc. | |
693 * Currently, recvfds() is not supported on these platforms. | |
694 */ | |
695 #ifdef CMSG_LEN | |
696 | |
697 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize) | |
698 { | |
699 char dummy[1]; | |
700 struct iovec iov = {dummy, sizeof(dummy)}; | |
701 struct msghdr msgh = {0}; | |
702 struct cmsghdr *cmsg; | |
703 | |
704 msgh.msg_iov = &iov; | |
705 msgh.msg_iovlen = 1; | |
706 msgh.msg_control = cbuf; | |
707 msgh.msg_controllen = (socklen_t)cbufsize; | |
708 if (recvmsg(sockfd, &msgh, 0) < 0) | |
709 return -1; | |
710 | |
711 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; | |
712 cmsg = CMSG_NXTHDR(&msgh, cmsg)) { | |
713 if (cmsg->cmsg_level != SOL_SOCKET || | |
714 cmsg->cmsg_type != SCM_RIGHTS) | |
715 continue; | |
716 *rfds = (int *)CMSG_DATA(cmsg); | |
717 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); | |
718 } | |
719 | |
720 *rfds = cbuf; | |
721 return 0; | |
722 } | |
723 | |
724 static PyObject *recvfds(PyObject *self, PyObject *args) | |
725 { | |
726 int sockfd; | |
727 int *rfds = NULL; | |
728 ssize_t rfdscount, i; | |
729 char cbuf[256]; | |
730 PyObject *rfdslist = NULL; | |
731 | |
732 if (!PyArg_ParseTuple(args, "i", &sockfd)) | |
733 return NULL; | |
734 | |
735 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf)); | |
736 if (rfdscount < 0) | |
737 return PyErr_SetFromErrno(PyExc_OSError); | |
738 | |
739 rfdslist = PyList_New(rfdscount); | |
740 if (!rfdslist) | |
741 goto bail; | |
742 for (i = 0; i < rfdscount; i++) { | |
743 PyObject *obj = PyLong_FromLong(rfds[i]); | |
744 if (!obj) | |
745 goto bail; | |
746 PyList_SET_ITEM(rfdslist, i, obj); | |
747 } | |
748 return rfdslist; | |
749 | |
750 bail: | |
751 Py_XDECREF(rfdslist); | |
752 return NULL; | |
753 } | |
754 | |
755 #endif /* CMSG_LEN */ | |
756 | |
757 /* allow disabling setprocname via compiler flags */ | 688 /* allow disabling setprocname via compiler flags */ |
758 #ifndef SETPROCNAME_USE_NONE | 689 #ifndef SETPROCNAME_USE_NONE |
759 #if defined(HAVE_SETPROCTITLE) | 690 #if defined(HAVE_SETPROCTITLE) |
760 /* setproctitle is the first choice - available in FreeBSD */ | 691 /* setproctitle is the first choice - available in FreeBSD */ |
761 #define SETPROCNAME_USE_SETPROCTITLE | 692 #define SETPROCNAME_USE_SETPROCTITLE |
1283 "On error, this function may raise either a WindowsError or an IOError."}, | 1214 "On error, this function may raise either a WindowsError or an IOError."}, |
1284 #else | 1215 #else |
1285 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS, | 1216 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS, |
1286 "stat a series of files or symlinks\n" | 1217 "stat a series of files or symlinks\n" |
1287 "Returns None for non-existent entries and entries of other types.\n"}, | 1218 "Returns None for non-existent entries and entries of other types.\n"}, |
1288 #ifdef CMSG_LEN | |
1289 {"recvfds", (PyCFunction)recvfds, METH_VARARGS, | |
1290 "receive list of file descriptors via socket\n"}, | |
1291 #endif | |
1292 #ifndef SETPROCNAME_USE_NONE | 1219 #ifndef SETPROCNAME_USE_NONE |
1293 {"setprocname", (PyCFunction)setprocname, METH_VARARGS, | 1220 {"setprocname", (PyCFunction)setprocname, METH_VARARGS, |
1294 "set process title (best-effort)\n"}, | 1221 "set process title (best-effort)\n"}, |
1295 #endif | 1222 #endif |
1296 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS) | 1223 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS) |