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)