##// END OF EJS Templates
osutil: implement pure version of recvfds() for PyPy...
Yuya Nishihara -
r27474:e517a89c default
parent child Browse files
Show More
@@ -7,8 +7,12 b''
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):
@@ -59,8 +63,87 b' def listdir(path, stat=False, skip=None)'
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
General Comments 0
You need to be logged in to leave comments. Login now