##// END OF EJS Templates
chg: replace mercurial.util.recvfds() by simpler pure Python implementation...
Manuel Jacob -
r50170:c6a32435 default
parent child Browse files
Show More
@@ -685,75 +685,6 bail:
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)
@@ -1285,10 +1216,6 static PyMethodDef methods[] = {
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"},
@@ -18,7 +18,6 class stat:
18 def listdir(path: bytes, st: bool, skip: bool) -> List[stat]: ...
18 def listdir(path: bytes, st: bool, skip: bool) -> List[stat]: ...
19 def posixfile(name: AnyStr, mode: bytes, buffering: int) -> IO: ...
19 def posixfile(name: AnyStr, mode: bytes, buffering: int) -> IO: ...
20 def statfiles(names: Sequence[bytes]) -> List[stat]: ...
20 def statfiles(names: Sequence[bytes]) -> List[stat]: ...
21 def recvfds(sockfd: int) -> List[int]: ...
22 def setprocname(name: bytes) -> None: ...
21 def setprocname(name: bytes) -> None: ...
23 def getfstype(path: bytes) -> bytes: ...
22 def getfstype(path: bytes) -> bytes: ...
24 def getfsmountpoint(path: bytes) -> bytes: ...
23 def getfsmountpoint(path: bytes) -> bytes: ...
@@ -389,7 +389,17 class chgcmdserver(commandserver.server)
389 # tell client to sendmsg() with 1-byte payload, which makes it
389 # tell client to sendmsg() with 1-byte payload, which makes it
390 # distinctive from "attachio\n" command consumed by client.read()
390 # distinctive from "attachio\n" command consumed by client.read()
391 self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
391 self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
392 clientfds = util.recvfds(self.clientsock.fileno())
392
393 data, ancdata, msg_flags, address = self.clientsock.recvmsg(1, 256)
394 assert len(ancdata) == 1
395 cmsg_level, cmsg_type, cmsg_data = ancdata[0]
396 assert cmsg_level == socket.SOL_SOCKET
397 assert cmsg_type == socket.SCM_RIGHTS
398 # memoryview.cast() was added in typeshed 61600d68772a, but pytype
399 # still complains
400 # pytype: disable=attribute-error
401 clientfds = memoryview(cmsg_data).cast('i').tolist()
402 # pytype: enable=attribute-error
393 self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
403 self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
394
404
395 ui = self.ui
405 ui = self.ui
@@ -9,7 +9,6
9 import ctypes
9 import ctypes
10 import ctypes.util
10 import ctypes.util
11 import os
11 import os
12 import socket
13 import stat as statmod
12 import stat as statmod
14
13
15 from ..pycompat import getattr
14 from ..pycompat import getattr
@@ -71,102 +70,6 def listdir(path, stat=False, skip=None)
71 if not pycompat.iswindows:
70 if not pycompat.iswindows:
72 posixfile = open
71 posixfile = open
73
72
74 _SCM_RIGHTS = 0x01
75 _socklen_t = ctypes.c_uint
76
77 if pycompat.sysplatform.startswith(b'linux'):
78 # socket.h says "the type should be socklen_t but the definition of
79 # the kernel is incompatible with this."
80 _cmsg_len_t = ctypes.c_size_t
81 _msg_controllen_t = ctypes.c_size_t
82 _msg_iovlen_t = ctypes.c_size_t
83 else:
84 _cmsg_len_t = _socklen_t
85 _msg_controllen_t = _socklen_t
86 _msg_iovlen_t = ctypes.c_int
87
88 class _iovec(ctypes.Structure):
89 _fields_ = [
90 (u'iov_base', ctypes.c_void_p),
91 (u'iov_len', ctypes.c_size_t),
92 ]
93
94 class _msghdr(ctypes.Structure):
95 _fields_ = [
96 (u'msg_name', ctypes.c_void_p),
97 (u'msg_namelen', _socklen_t),
98 (u'msg_iov', ctypes.POINTER(_iovec)),
99 (u'msg_iovlen', _msg_iovlen_t),
100 (u'msg_control', ctypes.c_void_p),
101 (u'msg_controllen', _msg_controllen_t),
102 (u'msg_flags', ctypes.c_int),
103 ]
104
105 class _cmsghdr(ctypes.Structure):
106 _fields_ = [
107 (u'cmsg_len', _cmsg_len_t),
108 (u'cmsg_level', ctypes.c_int),
109 (u'cmsg_type', ctypes.c_int),
110 (u'cmsg_data', ctypes.c_ubyte * 0),
111 ]
112
113 _libc = ctypes.CDLL(ctypes.util.find_library(u'c'), use_errno=True)
114 _recvmsg = getattr(_libc, 'recvmsg', None)
115 if _recvmsg:
116 _recvmsg.restype = getattr(ctypes, 'c_ssize_t', ctypes.c_long)
117 _recvmsg.argtypes = (
118 ctypes.c_int,
119 ctypes.POINTER(_msghdr),
120 ctypes.c_int,
121 )
122 else:
123 # recvmsg isn't always provided by libc; such systems are unsupported
124 def _recvmsg(sockfd, msg, flags):
125 raise NotImplementedError(b'unsupported platform')
126
127 def _CMSG_FIRSTHDR(msgh):
128 if msgh.msg_controllen < ctypes.sizeof(_cmsghdr):
129 return
130 cmsgptr = ctypes.cast(msgh.msg_control, ctypes.POINTER(_cmsghdr))
131 return cmsgptr.contents
132
133 # The pure version is less portable than the native version because the
134 # handling of socket ancillary data heavily depends on C preprocessor.
135 # Also, some length fields are wrongly typed in Linux kernel.
136 def recvfds(sockfd):
137 """receive list of file descriptors via socket"""
138 dummy = (ctypes.c_ubyte * 1)()
139 iov = _iovec(ctypes.cast(dummy, ctypes.c_void_p), ctypes.sizeof(dummy))
140 cbuf = ctypes.create_string_buffer(256)
141 msgh = _msghdr(
142 None,
143 0,
144 ctypes.pointer(iov),
145 1,
146 ctypes.cast(cbuf, ctypes.c_void_p),
147 ctypes.sizeof(cbuf),
148 0,
149 )
150 r = _recvmsg(sockfd, ctypes.byref(msgh), 0)
151 if r < 0:
152 e = ctypes.get_errno()
153 raise OSError(e, os.strerror(e))
154 # assumes that the first cmsg has fds because it isn't easy to write
155 # portable CMSG_NXTHDR() with ctypes.
156 cmsg = _CMSG_FIRSTHDR(msgh)
157 if not cmsg:
158 return []
159 if (
160 cmsg.cmsg_level != socket.SOL_SOCKET
161 or cmsg.cmsg_type != _SCM_RIGHTS
162 ):
163 return []
164 rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int))
165 rfdscount = (
166 cmsg.cmsg_len - _cmsghdr.cmsg_data.offset
167 ) // ctypes.sizeof(ctypes.c_int)
168 return [rfds[i] for i in pycompat.xrange(rfdscount)]
169
170
73
171 else:
74 else:
172 import msvcrt
75 import msvcrt
@@ -156,11 +156,6 compengines = compression.compengines
156 SERVERROLE = compression.SERVERROLE
156 SERVERROLE = compression.SERVERROLE
157 CLIENTROLE = compression.CLIENTROLE
157 CLIENTROLE = compression.CLIENTROLE
158
158
159 try:
160 recvfds = osutil.recvfds
161 except AttributeError:
162 pass
163
164 # Python compatibility
159 # Python compatibility
165
160
166 _notset = object()
161 _notset = object()
General Comments 0
You need to be logged in to leave comments. Login now