Mercurial > public > mercurial-scm > hg
comparison mercurial/pure/osutil.py @ 27474:e517a89c24e1
osutil: implement pure version of recvfds() for PyPy
This is less portable than the C version, but PyPy can't load CPython
extensions. So for now, this will be used on PyPy.
I've tested it on Linux amd64 and Mac OS X.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 17 Dec 2015 23:53:09 +0900 |
parents | 810337ae1b76 |
children | e2aa9c4030c4 |
comparison
equal
deleted
inserted
replaced
27473:34a37a2e03e6 | 27474:e517a89c24e1 |
---|---|
5 # This software may be used and distributed according to the terms of the | 5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2 or any later version. | 6 # GNU General Public License version 2 or any later version. |
7 | 7 |
8 from __future__ import absolute_import | 8 from __future__ import absolute_import |
9 | 9 |
10 import ctypes | |
11 import ctypes.util | |
10 import os | 12 import os |
13 import socket | |
11 import stat as statmod | 14 import stat as statmod |
15 import sys | |
12 | 16 |
13 def _mode_to_kind(mode): | 17 def _mode_to_kind(mode): |
14 if statmod.S_ISREG(mode): | 18 if statmod.S_ISREG(mode): |
15 return statmod.S_IFREG | 19 return statmod.S_IFREG |
16 if statmod.S_ISDIR(mode): | 20 if statmod.S_ISDIR(mode): |
57 result.append((fn, _mode_to_kind(st.st_mode))) | 61 result.append((fn, _mode_to_kind(st.st_mode))) |
58 return result | 62 return result |
59 | 63 |
60 if os.name != 'nt': | 64 if os.name != 'nt': |
61 posixfile = open | 65 posixfile = open |
66 | |
67 _SCM_RIGHTS = 0x01 | |
68 _socklen_t = ctypes.c_uint | |
69 | |
70 if sys.platform == 'linux2': | |
71 # socket.h says "the type should be socklen_t but the definition of | |
72 # the kernel is incompatible with this." | |
73 _cmsg_len_t = ctypes.c_size_t | |
74 _msg_controllen_t = ctypes.c_size_t | |
75 _msg_iovlen_t = ctypes.c_size_t | |
76 else: | |
77 _cmsg_len_t = _socklen_t | |
78 _msg_controllen_t = _socklen_t | |
79 _msg_iovlen_t = ctypes.c_int | |
80 | |
81 class _iovec(ctypes.Structure): | |
82 _fields_ = [ | |
83 ('iov_base', ctypes.c_void_p), | |
84 ('iov_len', ctypes.c_size_t), | |
85 ] | |
86 | |
87 class _msghdr(ctypes.Structure): | |
88 _fields_ = [ | |
89 ('msg_name', ctypes.c_void_p), | |
90 ('msg_namelen', _socklen_t), | |
91 ('msg_iov', ctypes.POINTER(_iovec)), | |
92 ('msg_iovlen', _msg_iovlen_t), | |
93 ('msg_control', ctypes.c_void_p), | |
94 ('msg_controllen', _msg_controllen_t), | |
95 ('msg_flags', ctypes.c_int), | |
96 ] | |
97 | |
98 class _cmsghdr(ctypes.Structure): | |
99 _fields_ = [ | |
100 ('cmsg_len', _cmsg_len_t), | |
101 ('cmsg_level', ctypes.c_int), | |
102 ('cmsg_type', ctypes.c_int), | |
103 ('cmsg_data', ctypes.c_ubyte * 0), | |
104 ] | |
105 | |
106 _libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) | |
107 _recvmsg = _libc.recvmsg | |
108 _recvmsg.restype = ctypes.c_ssize_t | |
109 _recvmsg.argtypes = (ctypes.c_int, ctypes.POINTER(_msghdr), ctypes.c_int) | |
110 | |
111 def _CMSG_FIRSTHDR(msgh): | |
112 if msgh.msg_controllen < ctypes.sizeof(_cmsghdr): | |
113 return | |
114 cmsgptr = ctypes.cast(msgh.msg_control, ctypes.POINTER(_cmsghdr)) | |
115 return cmsgptr.contents | |
116 | |
117 # The pure version is less portable than the native version because the | |
118 # handling of socket ancillary data heavily depends on C preprocessor. | |
119 # Also, some length fields are wrongly typed in Linux kernel. | |
120 def recvfds(sockfd): | |
121 """receive list of file descriptors via socket""" | |
122 dummy = (ctypes.c_ubyte * 1)() | |
123 iov = _iovec(ctypes.cast(dummy, ctypes.c_void_p), ctypes.sizeof(dummy)) | |
124 cbuf = ctypes.create_string_buffer(256) | |
125 msgh = _msghdr(None, 0, | |
126 ctypes.pointer(iov), 1, | |
127 ctypes.cast(cbuf, ctypes.c_void_p), ctypes.sizeof(cbuf), | |
128 0) | |
129 r = _recvmsg(sockfd, ctypes.byref(msgh), 0) | |
130 if r < 0: | |
131 e = ctypes.get_errno() | |
132 raise OSError(e, os.strerror(e)) | |
133 # assumes that the first cmsg has fds because it isn't easy to write | |
134 # portable CMSG_NXTHDR() with ctypes. | |
135 cmsg = _CMSG_FIRSTHDR(msgh) | |
136 if not cmsg: | |
137 return [] | |
138 if (cmsg.cmsg_level != socket.SOL_SOCKET or | |
139 cmsg.cmsg_type != _SCM_RIGHTS): | |
140 return [] | |
141 rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int)) | |
142 rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) / | |
143 ctypes.sizeof(ctypes.c_int)) | |
144 return [rfds[i] for i in xrange(rfdscount)] | |
145 | |
62 else: | 146 else: |
63 import ctypes | |
64 import msvcrt | 147 import msvcrt |
65 | 148 |
66 _kernel32 = ctypes.windll.kernel32 | 149 _kernel32 = ctypes.windll.kernel32 |
67 | 150 |
68 _DWORD = ctypes.c_ulong | 151 _DWORD = ctypes.c_ulong |