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