Import Upstream version 0.2
Martín Ferrari
7 years ago
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 2, June 1991 | |
2 | ||
3 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., | |
4 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
5 | Everyone is permitted to copy and distribute verbatim copies | |
6 | of this license document, but changing it is not allowed. | |
7 | ||
8 | Preamble | |
9 | ||
10 | The licenses for most software are designed to take away your | |
11 | freedom to share and change it. By contrast, the GNU General Public | |
12 | License is intended to guarantee your freedom to share and change free | |
13 | software--to make sure the software is free for all its users. This | |
14 | General Public License applies to most of the Free Software | |
15 | Foundation's software and to any other program whose authors commit to | |
16 | using it. (Some other Free Software Foundation software is covered by | |
17 | the GNU Lesser General Public License instead.) You can apply it to | |
18 | your programs, too. | |
19 | ||
20 | When we speak of free software, we are referring to freedom, not | |
21 | price. Our General Public Licenses are designed to make sure that you | |
22 | have the freedom to distribute copies of free software (and charge for | |
23 | this service if you wish), that you receive source code or can get it | |
24 | if you want it, that you can change the software or use pieces of it | |
25 | in new free programs; and that you know you can do these things. | |
26 | ||
27 | To protect your rights, we need to make restrictions that forbid | |
28 | anyone to deny you these rights or to ask you to surrender the rights. | |
29 | These restrictions translate to certain responsibilities for you if you | |
30 | distribute copies of the software, or if you modify it. | |
31 | ||
32 | For example, if you distribute copies of such a program, whether | |
33 | gratis or for a fee, you must give the recipients all the rights that | |
34 | you have. You must make sure that they, too, receive or can get the | |
35 | source code. And you must show them these terms so they know their | |
36 | rights. | |
37 | ||
38 | We protect your rights with two steps: (1) copyright the software, and | |
39 | (2) offer you this license which gives you legal permission to copy, | |
40 | distribute and/or modify the software. | |
41 | ||
42 | Also, for each author's protection and ours, we want to make certain | |
43 | that everyone understands that there is no warranty for this free | |
44 | software. If the software is modified by someone else and passed on, we | |
45 | want its recipients to know that what they have is not the original, so | |
46 | that any problems introduced by others will not reflect on the original | |
47 | authors' reputations. | |
48 | ||
49 | Finally, any free program is threatened constantly by software | |
50 | patents. We wish to avoid the danger that redistributors of a free | |
51 | program will individually obtain patent licenses, in effect making the | |
52 | program proprietary. To prevent this, we have made it clear that any | |
53 | patent must be licensed for everyone's free use or not licensed at all. | |
54 | ||
55 | The precise terms and conditions for copying, distribution and | |
56 | modification follow. | |
57 | ||
58 | GNU GENERAL PUBLIC LICENSE | |
59 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
60 | ||
61 | 0. This License applies to any program or other work which contains | |
62 | a notice placed by the copyright holder saying it may be distributed | |
63 | under the terms of this General Public License. The "Program", below, | |
64 | refers to any such program or work, and a "work based on the Program" | |
65 | means either the Program or any derivative work under copyright law: | |
66 | that is to say, a work containing the Program or a portion of it, | |
67 | either verbatim or with modifications and/or translated into another | |
68 | language. (Hereinafter, translation is included without limitation in | |
69 | the term "modification".) Each licensee is addressed as "you". | |
70 | ||
71 | Activities other than copying, distribution and modification are not | |
72 | covered by this License; they are outside its scope. The act of | |
73 | running the Program is not restricted, and the output from the Program | |
74 | is covered only if its contents constitute a work based on the | |
75 | Program (independent of having been made by running the Program). | |
76 | Whether that is true depends on what the Program does. | |
77 | ||
78 | 1. You may copy and distribute verbatim copies of the Program's | |
79 | source code as you receive it, in any medium, provided that you | |
80 | conspicuously and appropriately publish on each copy an appropriate | |
81 | copyright notice and disclaimer of warranty; keep intact all the | |
82 | notices that refer to this License and to the absence of any warranty; | |
83 | and give any other recipients of the Program a copy of this License | |
84 | along with the Program. | |
85 | ||
86 | You may charge a fee for the physical act of transferring a copy, and | |
87 | you may at your option offer warranty protection in exchange for a fee. | |
88 | ||
89 | 2. You may modify your copy or copies of the Program or any portion | |
90 | of it, thus forming a work based on the Program, and copy and | |
91 | distribute such modifications or work under the terms of Section 1 | |
92 | above, provided that you also meet all of these conditions: | |
93 | ||
94 | a) You must cause the modified files to carry prominent notices | |
95 | stating that you changed the files and the date of any change. | |
96 | ||
97 | b) You must cause any work that you distribute or publish, that in | |
98 | whole or in part contains or is derived from the Program or any | |
99 | part thereof, to be licensed as a whole at no charge to all third | |
100 | parties under the terms of this License. | |
101 | ||
102 | c) If the modified program normally reads commands interactively | |
103 | when run, you must cause it, when started running for such | |
104 | interactive use in the most ordinary way, to print or display an | |
105 | announcement including an appropriate copyright notice and a | |
106 | notice that there is no warranty (or else, saying that you provide | |
107 | a warranty) and that users may redistribute the program under | |
108 | these conditions, and telling the user how to view a copy of this | |
109 | License. (Exception: if the Program itself is interactive but | |
110 | does not normally print such an announcement, your work based on | |
111 | the Program is not required to print an announcement.) | |
112 | ||
113 | These requirements apply to the modified work as a whole. If | |
114 | identifiable sections of that work are not derived from the Program, | |
115 | and can be reasonably considered independent and separate works in | |
116 | themselves, then this License, and its terms, do not apply to those | |
117 | sections when you distribute them as separate works. But when you | |
118 | distribute the same sections as part of a whole which is a work based | |
119 | on the Program, the distribution of the whole must be on the terms of | |
120 | this License, whose permissions for other licensees extend to the | |
121 | entire whole, and thus to each and every part regardless of who wrote it. | |
122 | ||
123 | Thus, it is not the intent of this section to claim rights or contest | |
124 | your rights to work written entirely by you; rather, the intent is to | |
125 | exercise the right to control the distribution of derivative or | |
126 | collective works based on the Program. | |
127 | ||
128 | In addition, mere aggregation of another work not based on the Program | |
129 | with the Program (or with a work based on the Program) on a volume of | |
130 | a storage or distribution medium does not bring the other work under | |
131 | the scope of this License. | |
132 | ||
133 | 3. You may copy and distribute the Program (or a work based on it, | |
134 | under Section 2) in object code or executable form under the terms of | |
135 | Sections 1 and 2 above provided that you also do one of the following: | |
136 | ||
137 | a) Accompany it with the complete corresponding machine-readable | |
138 | source code, which must be distributed under the terms of Sections | |
139 | 1 and 2 above on a medium customarily used for software interchange; or, | |
140 | ||
141 | b) Accompany it with a written offer, valid for at least three | |
142 | years, to give any third party, for a charge no more than your | |
143 | cost of physically performing source distribution, a complete | |
144 | machine-readable copy of the corresponding source code, to be | |
145 | distributed under the terms of Sections 1 and 2 above on a medium | |
146 | customarily used for software interchange; or, | |
147 | ||
148 | c) Accompany it with the information you received as to the offer | |
149 | to distribute corresponding source code. (This alternative is | |
150 | allowed only for noncommercial distribution and only if you | |
151 | received the program in object code or executable form with such | |
152 | an offer, in accord with Subsection b above.) | |
153 | ||
154 | The source code for a work means the preferred form of the work for | |
155 | making modifications to it. For an executable work, complete source | |
156 | code means all the source code for all modules it contains, plus any | |
157 | associated interface definition files, plus the scripts used to | |
158 | control compilation and installation of the executable. However, as a | |
159 | special exception, the source code distributed need not include | |
160 | anything that is normally distributed (in either source or binary | |
161 | form) with the major components (compiler, kernel, and so on) of the | |
162 | operating system on which the executable runs, unless that component | |
163 | itself accompanies the executable. | |
164 | ||
165 | If distribution of executable or object code is made by offering | |
166 | access to copy from a designated place, then offering equivalent | |
167 | access to copy the source code from the same place counts as | |
168 | distribution of the source code, even though third parties are not | |
169 | compelled to copy the source along with the object code. | |
170 | ||
171 | 4. You may not copy, modify, sublicense, or distribute the Program | |
172 | except as expressly provided under this License. Any attempt | |
173 | otherwise to copy, modify, sublicense or distribute the Program is | |
174 | void, and will automatically terminate your rights under this License. | |
175 | However, parties who have received copies, or rights, from you under | |
176 | this License will not have their licenses terminated so long as such | |
177 | parties remain in full compliance. | |
178 | ||
179 | 5. You are not required to accept this License, since you have not | |
180 | signed it. However, nothing else grants you permission to modify or | |
181 | distribute the Program or its derivative works. These actions are | |
182 | prohibited by law if you do not accept this License. Therefore, by | |
183 | modifying or distributing the Program (or any work based on the | |
184 | Program), you indicate your acceptance of this License to do so, and | |
185 | all its terms and conditions for copying, distributing or modifying | |
186 | the Program or works based on it. | |
187 | ||
188 | 6. Each time you redistribute the Program (or any work based on the | |
189 | Program), the recipient automatically receives a license from the | |
190 | original licensor to copy, distribute or modify the Program subject to | |
191 | these terms and conditions. You may not impose any further | |
192 | restrictions on the recipients' exercise of the rights granted herein. | |
193 | You are not responsible for enforcing compliance by third parties to | |
194 | this License. | |
195 | ||
196 | 7. If, as a consequence of a court judgment or allegation of patent | |
197 | infringement or for any other reason (not limited to patent issues), | |
198 | conditions are imposed on you (whether by court order, agreement or | |
199 | otherwise) that contradict the conditions of this License, they do not | |
200 | excuse you from the conditions of this License. If you cannot | |
201 | distribute so as to satisfy simultaneously your obligations under this | |
202 | License and any other pertinent obligations, then as a consequence you | |
203 | may not distribute the Program at all. For example, if a patent | |
204 | license would not permit royalty-free redistribution of the Program by | |
205 | all those who receive copies directly or indirectly through you, then | |
206 | the only way you could satisfy both it and this License would be to | |
207 | refrain entirely from distribution of the Program. | |
208 | ||
209 | If any portion of this section is held invalid or unenforceable under | |
210 | any particular circumstance, the balance of the section is intended to | |
211 | apply and the section as a whole is intended to apply in other | |
212 | circumstances. | |
213 | ||
214 | It is not the purpose of this section to induce you to infringe any | |
215 | patents or other property right claims or to contest validity of any | |
216 | such claims; this section has the sole purpose of protecting the | |
217 | integrity of the free software distribution system, which is | |
218 | implemented by public license practices. Many people have made | |
219 | generous contributions to the wide range of software distributed | |
220 | through that system in reliance on consistent application of that | |
221 | system; it is up to the author/donor to decide if he or she is willing | |
222 | to distribute software through any other system and a licensee cannot | |
223 | impose that choice. | |
224 | ||
225 | This section is intended to make thoroughly clear what is believed to | |
226 | be a consequence of the rest of this License. | |
227 | ||
228 | 8. If the distribution and/or use of the Program is restricted in | |
229 | certain countries either by patents or by copyrighted interfaces, the | |
230 | original copyright holder who places the Program under this License | |
231 | may add an explicit geographical distribution limitation excluding | |
232 | those countries, so that distribution is permitted only in or among | |
233 | countries not thus excluded. In such case, this License incorporates | |
234 | the limitation as if written in the body of this License. | |
235 | ||
236 | 9. The Free Software Foundation may publish revised and/or new versions | |
237 | of the General Public License from time to time. Such new versions will | |
238 | be similar in spirit to the present version, but may differ in detail to | |
239 | address new problems or concerns. | |
240 | ||
241 | Each version is given a distinguishing version number. If the Program | |
242 | specifies a version number of this License which applies to it and "any | |
243 | later version", you have the option of following the terms and conditions | |
244 | either of that version or of any later version published by the Free | |
245 | Software Foundation. If the Program does not specify a version number of | |
246 | this License, you may choose any version ever published by the Free Software | |
247 | Foundation. | |
248 | ||
249 | 10. If you wish to incorporate parts of the Program into other free | |
250 | programs whose distribution conditions are different, write to the author | |
251 | to ask for permission. For software which is copyrighted by the Free | |
252 | Software Foundation, write to the Free Software Foundation; we sometimes | |
253 | make exceptions for this. Our decision will be guided by the two goals | |
254 | of preserving the free status of all derivatives of our free software and | |
255 | of promoting the sharing and reuse of software generally. | |
256 | ||
257 | NO WARRANTY | |
258 | ||
259 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
260 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
261 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
262 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |
263 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
264 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |
265 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |
266 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |
267 | REPAIR OR CORRECTION. | |
268 | ||
269 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
270 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
271 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |
272 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |
273 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |
274 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |
275 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |
276 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |
277 | POSSIBILITY OF SUCH DAMAGES. | |
278 | ||
279 | END OF TERMS AND CONDITIONS | |
280 | ||
281 | How to Apply These Terms to Your New Programs | |
282 | ||
283 | If you develop a new program, and you want it to be of the greatest | |
284 | possible use to the public, the best way to achieve this is to make it | |
285 | free software which everyone can redistribute and change under these terms. | |
286 | ||
287 | To do so, attach the following notices to the program. It is safest | |
288 | to attach them to the start of each source file to most effectively | |
289 | convey the exclusion of warranty; and each file should have at least | |
290 | the "copyright" line and a pointer to where the full notice is found. | |
291 | ||
292 | <one line to give the program's name and a brief idea of what it does.> | |
293 | Copyright (C) <year> <name of author> | |
294 | ||
295 | This program is free software; you can redistribute it and/or modify | |
296 | it under the terms of the GNU General Public License as published by | |
297 | the Free Software Foundation; either version 2 of the License, or | |
298 | (at your option) any later version. | |
299 | ||
300 | This program is distributed in the hope that it will be useful, | |
301 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
302 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
303 | GNU General Public License for more details. | |
304 | ||
305 | You should have received a copy of the GNU General Public License along | |
306 | with this program; if not, write to the Free Software Foundation, Inc., | |
307 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
308 | ||
309 | Also add information on how to contact you by electronic and paper mail. | |
310 | ||
311 | If the program is interactive, make it output a short notice like this | |
312 | when it starts in an interactive mode: | |
313 | ||
314 | Gnomovision version 69, Copyright (C) year name of author | |
315 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
316 | This is free software, and you are welcome to redistribute it | |
317 | under certain conditions; type `show c' for details. | |
318 | ||
319 | The hypothetical commands `show w' and `show c' should show the appropriate | |
320 | parts of the General Public License. Of course, the commands you use may | |
321 | be called something other than `show w' and `show c'; they could even be | |
322 | mouse-clicks or menu items--whatever suits your program. | |
323 | ||
324 | You should also get your employer (if you work as a programmer) or your | |
325 | school, if any, to sign a "copyright disclaimer" for the program, if | |
326 | necessary. Here is a sample; alter the names: | |
327 | ||
328 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |
329 | `Gnomovision' (which makes passes at compilers) written by James Hacker. | |
330 | ||
331 | <signature of Ty Coon>, 1 April 1989 | |
332 | Ty Coon, President of Vice | |
333 | ||
334 | This General Public License does not permit incorporating your program into | |
335 | proprietary programs. If your program is a subroutine library, you may | |
336 | consider it more useful to permit linking proprietary applications with the | |
337 | library. If this is what you want to do, use the GNU Lesser General | |
338 | Public License instead of this License. |
0 | SRC = src | |
1 | TEST = t | |
2 | BUILDDIR = build | |
3 | DISTDIR = dist | |
4 | ||
5 | # Gah | |
6 | SUBBUILDDIR = $(shell python -c 'import distutils.util, sys; print "lib.%s-%s" % (distutils.util.get_platform(), sys.version[0:3])') | |
7 | BUILDDIR := $(BUILDDIR)/$(SUBBUILDDIR) | |
8 | ||
9 | COVERAGE = $(or $(shell which coverage), $(shell which python-coverage), \ | |
10 | coverage) | |
11 | ||
12 | all: | |
13 | ./setup.py build | |
14 | ||
15 | install: all | |
16 | ./setup.py install | |
17 | ||
18 | test: all | |
19 | retval=0; \ | |
20 | for i in `find "$(TEST)" -perm -u+x -type f`; do \ | |
21 | echo $$i; \ | |
22 | PYTHONPATH="$(BUILDDIR):$$PYTHONPATH" $$i || retval=$$?; \ | |
23 | done; exit $$retval | |
24 | ||
25 | coverage: all | |
26 | rm -f .coverage | |
27 | for i in `find "$(TEST)" -perm -u+x -type f`; do \ | |
28 | set -e; \ | |
29 | PYTHONPATH="$(BUILDDIR):$$PYTHONPATH" $(COVERAGE) -x $$i; \ | |
30 | done | |
31 | $(COVERAGE) -r -m `find "$(BUILDDIR)" -name \\*.py -type f` | |
32 | rm -f .coverage | |
33 | ||
34 | clean: | |
35 | ./setup.py clean | |
36 | rm -f `find -name \*.pyc` .coverage | |
37 | ||
38 | distclean: clean | |
39 | rm -rf "$(DISTDIR)" | |
40 | ||
41 | dist: | |
42 | ./setup.py sdist | |
43 | ||
44 | .PHONY: clean distclean dist test coverage install |
0 | Metadata-Version: 1.0 | |
1 | Name: python-passfd | |
2 | Version: 0.2 | |
3 | Summary: Python functions to pass file descriptors across UNIX domain sockets | |
4 | Home-page: http://code.google.com/p/python-passfd/ | |
5 | Author: Martin Ferrari | |
6 | Author-email: martin.ferrari@gmail.com | |
7 | License: GPLv2 | |
8 | Description: This simple extension provides two functions to pass and receive file | |
9 | descriptors across UNIX domain sockets, using the BSD-4.3+ sendmsg() and | |
10 | recvmsg() interfaces. | |
11 | ||
12 | Direct bindings to sendmsg and recvmsg are not provided, as the API does | |
13 | not map nicely into Python. | |
14 | ||
15 | Please note that this only supports BSD-4.3+ style file descriptor | |
16 | passing, and was only tested on Linux. Patches are welcomed! | |
17 | ||
18 | For more information, see one of the R. Stevens' books: | |
19 | - Richard Stevens: Unix Network Programming, Prentice Hall, 1990; | |
20 | chapter 6.10 | |
21 | ||
22 | - Richard Stevens: Advanced Programming in the UNIX Environment, | |
23 | Addison-Wesley, 1993; chapter 15.3 | |
24 | ||
25 | Platform: Linux |
0 | #!/usr/bin/env python | |
1 | # vim: set fileencoding=utf-8 | |
2 | # vim: ts=4:sw=4:et:ai:sts=4 | |
3 | from distutils.core import setup, Extension | |
4 | import sys | |
5 | sys.path.append("src") | |
6 | import passfd | |
7 | ||
8 | module1 = Extension('_passfd', sources = ['src/passfd.c']) | |
9 | ||
10 | setup( | |
11 | name = 'python-passfd', | |
12 | version = '0.2', | |
13 | description = 'Python functions to pass file descriptors across ' + | |
14 | 'UNIX domain sockets', | |
15 | long_description = passfd.__doc__, | |
16 | author = 'Martin Ferrari', | |
17 | author_email = 'martin.ferrari@gmail.com', | |
18 | url = 'http://code.google.com/p/python-passfd/', | |
19 | license = 'GPLv2', | |
20 | platforms = 'Linux', | |
21 | package_dir = {'': 'src'}, | |
22 | ext_modules = [module1], | |
23 | py_modules = ['passfd']) |
0 | /* vim:ts=4:sw=4:et:ai:sts=4 | |
1 | * | |
2 | * passfd.c: Functions to pass file descriptors across UNIX domain sockets. | |
3 | * | |
4 | * Please note that this only supports BSD-4.3+ style file descriptor passing, | |
5 | * and was only tested on Linux. Patches are welcomed! | |
6 | * | |
7 | * Copyright © 2010 Martín Ferrari <martin.ferrari@gmail.com> | |
8 | * | |
9 | * Inspired by Socket::PassAccessRights, which is: | |
10 | * Copyright (c) 2000 Sampo Kellomaki <sampo@iki.fi> | |
11 | * | |
12 | * For more information, see one of the R. Stevens' books: | |
13 | * - Richard Stevens: Unix Network Programming, Prentice Hall, 1990; | |
14 | * chapter 6.10 | |
15 | * | |
16 | * - Richard Stevens: Advanced Programming in the UNIX Environment, | |
17 | * Addison-Wesley, 1993; chapter 15.3 | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or modify it | |
20 | * under the terms of the GNU General Public License as published by the Free | |
21 | * Software Foundation; either version 2 of the License, or (at your option) | |
22 | * any later version. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
25 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
26 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
27 | * more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License along with | |
30 | * this program; if not, write to the Free Software Foundation, Inc., 51 | |
31 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
32 | */ | |
33 | ||
34 | #include <Python.h> | |
35 | #ifndef _GNU_SOURCE | |
36 | # define _GNU_SOURCE | |
37 | #endif | |
38 | #include <sys/types.h> | |
39 | #include <sys/socket.h> | |
40 | #include <unistd.h> | |
41 | ||
42 | int _sendfd(int sock, int fd, size_t len, const void *msg); | |
43 | int _recvfd(int sock, size_t *len, void *buf); | |
44 | ||
45 | /* Python wrapper for _sendfd */ | |
46 | static PyObject * | |
47 | sendfd(PyObject *self, PyObject *args) { | |
48 | const char *message; | |
49 | char *buf; | |
50 | int ret, sock, fd, message_len; | |
51 | ||
52 | if(!PyArg_ParseTuple(args, "iis#", &sock, &fd, &message, &message_len)) | |
53 | return NULL; | |
54 | ||
55 | /* I don't know if I need to make a copy of the message buffer for thread | |
56 | * safety, but let's do it just in case... */ | |
57 | buf = strndup(message, (size_t)message_len); | |
58 | if(buf == NULL) | |
59 | return PyErr_SetFromErrno(PyExc_OSError); | |
60 | ||
61 | Py_BEGIN_ALLOW_THREADS; | |
62 | ret = _sendfd(sock, fd, message_len, message); | |
63 | Py_END_ALLOW_THREADS; | |
64 | ||
65 | free(buf); | |
66 | if(ret == -1) | |
67 | return PyErr_SetFromErrno(PyExc_OSError); | |
68 | return Py_BuildValue("i", ret); | |
69 | } | |
70 | ||
71 | /* Python wrapper for _recvfd */ | |
72 | static PyObject * | |
73 | recvfd(PyObject *self, PyObject *args) { | |
74 | char *buffer; | |
75 | int ret, sock, buffersize = 4096; | |
76 | size_t _buffersize; | |
77 | PyObject *retval; | |
78 | ||
79 | if(!PyArg_ParseTuple(args, "i|i", &sock, &buffersize)) | |
80 | return NULL; | |
81 | ||
82 | if((buffer = malloc(buffersize)) == NULL) | |
83 | return PyErr_SetFromErrno(PyExc_OSError); | |
84 | ||
85 | _buffersize = buffersize; | |
86 | ||
87 | Py_BEGIN_ALLOW_THREADS; | |
88 | ret = _recvfd(sock, &_buffersize, buffer); | |
89 | Py_END_ALLOW_THREADS; | |
90 | ||
91 | buffersize = (int)_buffersize; | |
92 | if(ret == -1) { | |
93 | free(buffer); | |
94 | return PyErr_SetFromErrno(PyExc_OSError); | |
95 | } | |
96 | retval = Py_BuildValue("is#", ret, buffer, buffersize); | |
97 | free(buffer); | |
98 | return retval; | |
99 | } | |
100 | ||
101 | static PyMethodDef methods[] = { | |
102 | {"sendfd", sendfd, METH_VARARGS, "rv = sendfd(sock, fd, message)"}, | |
103 | {"recvfd", recvfd, METH_VARARGS, "(fd, message) = recvfd(sock, " | |
104 | "buffersize = 4096)"}, | |
105 | {NULL, NULL, 0, NULL} | |
106 | }; | |
107 | ||
108 | PyMODINIT_FUNC init_passfd(void) { | |
109 | PyObject *m; | |
110 | m = Py_InitModule("_passfd", methods); | |
111 | if (m == NULL) | |
112 | return; | |
113 | } | |
114 | ||
115 | /* Size of the cmsg including one file descriptor */ | |
116 | #define CMSG_SIZE CMSG_SPACE(sizeof(int)) | |
117 | ||
118 | /* | |
119 | * _sendfd(): send a message and piggyback a file descriptor. | |
120 | * | |
121 | * Note that the file descriptor cannot be sent by itself, at least one byte of | |
122 | * payload needs to be sent. | |
123 | * | |
124 | * Parameters: | |
125 | * sock: AF_UNIX socket | |
126 | * fd: file descriptor to pass | |
127 | * len: length of the message | |
128 | * msg: the message itself | |
129 | * | |
130 | * Return value: | |
131 | * On success, sendfd returns the number of characters from the message sent, | |
132 | * the file descriptor information is not taken into account. If there was no | |
133 | * message to send, 0 is returned. On error, -1 is returned, and errno is set | |
134 | * appropriately. | |
135 | * | |
136 | */ | |
137 | int _sendfd(int sock, int fd, size_t len, const void *msg) { | |
138 | struct iovec iov[1]; | |
139 | struct msghdr msgh; | |
140 | char buf[CMSG_SIZE]; | |
141 | struct cmsghdr *h; | |
142 | int ret; | |
143 | ||
144 | /* At least one byte needs to be sent, for some reason (?) */ | |
145 | if(len < 1) | |
146 | return 0; | |
147 | ||
148 | memset(&iov[0], 0, sizeof(struct iovec)); | |
149 | memset(&msgh, 0, sizeof(struct msghdr)); | |
150 | memset(buf, 0, CMSG_SIZE); | |
151 | ||
152 | msgh.msg_name = NULL; | |
153 | msgh.msg_namelen = 0; | |
154 | ||
155 | msgh.msg_iov = iov; | |
156 | msgh.msg_iovlen = 1; | |
157 | ||
158 | msgh.msg_control = buf; | |
159 | msgh.msg_controllen = CMSG_SIZE; | |
160 | msgh.msg_flags = 0; | |
161 | ||
162 | /* Message to be sent */ | |
163 | iov[0].iov_base = (void *)msg; | |
164 | iov[0].iov_len = len; | |
165 | ||
166 | /* Control data */ | |
167 | h = CMSG_FIRSTHDR(&msgh); | |
168 | h->cmsg_len = CMSG_LEN(sizeof(int)); | |
169 | h->cmsg_level = SOL_SOCKET; | |
170 | h->cmsg_type = SCM_RIGHTS; | |
171 | ((int *)CMSG_DATA(h))[0] = fd; | |
172 | ||
173 | ret = sendmsg(sock, &msgh, 0); | |
174 | return ret; | |
175 | } | |
176 | /* | |
177 | * _recvfd(): receive a message and a file descriptor. | |
178 | * | |
179 | * Parameters: | |
180 | * sock: AF_UNIX socket | |
181 | * len: pointer to the length of the message buffer, modified on return | |
182 | * buf: buffer to contain the received buffer | |
183 | * | |
184 | * If len is 0 or buf is NULL, the received message is stored in a temporary | |
185 | * buffer and discarded later. | |
186 | * | |
187 | * Return value: | |
188 | * On success, recvfd returns the received file descriptor, and len points to | |
189 | * the size of the received message. | |
190 | * If recvmsg fails, -1 is returned, and errno is set appropriately. | |
191 | * If the received data does not carry exactly one file descriptor, -2 is | |
192 | * returned. If the received file descriptor is not valid, -3 is returned. | |
193 | * | |
194 | */ | |
195 | int _recvfd(int sock, size_t *len, void *buf) { | |
196 | struct iovec iov[1]; | |
197 | struct msghdr msgh; | |
198 | char cmsgbuf[CMSG_SIZE]; | |
199 | char extrabuf[4096]; | |
200 | struct cmsghdr *h; | |
201 | int st, fd; | |
202 | ||
203 | if(*len < 1 || buf == NULL) { | |
204 | /* For some reason, again, one byte needs to be received. (it would not | |
205 | * block?) */ | |
206 | iov[0].iov_base = extrabuf; | |
207 | iov[0].iov_len = sizeof(extrabuf); | |
208 | } else { | |
209 | iov[0].iov_base = buf; | |
210 | iov[0].iov_len = *len; | |
211 | } | |
212 | ||
213 | msgh.msg_name = NULL; | |
214 | msgh.msg_namelen = 0; | |
215 | ||
216 | msgh.msg_iov = iov; | |
217 | msgh.msg_iovlen = 1; | |
218 | ||
219 | msgh.msg_control = cmsgbuf; | |
220 | msgh.msg_controllen = CMSG_SIZE; | |
221 | msgh.msg_flags = 0; | |
222 | ||
223 | st = recvmsg(sock, &msgh, 0); | |
224 | if(st < 0) | |
225 | return -1; | |
226 | ||
227 | *len = st; | |
228 | h = CMSG_FIRSTHDR(&msgh); | |
229 | /* Check if we received what we expected */ | |
230 | if(h == NULL | |
231 | || h->cmsg_len != CMSG_LEN(sizeof(int)) | |
232 | || h->cmsg_level != SOL_SOCKET | |
233 | || h->cmsg_type != SCM_RIGHTS) { | |
234 | return -2; | |
235 | } | |
236 | fd = ((int *)CMSG_DATA(h))[0]; | |
237 | if(fd < 0) | |
238 | return -3; | |
239 | return fd; | |
240 | } |
0 | #!/usr/bin/env python | |
1 | # vim: set fileencoding=utf-8 | |
2 | # vim: ts=4:sw=4:et:ai:sts=4 | |
3 | ||
4 | # passfd.py: Python library to pass file descriptors across UNIX domain sockets. | |
5 | '''This simple extension provides two functions to pass and receive file | |
6 | descriptors across UNIX domain sockets, using the BSD-4.3+ sendmsg() and | |
7 | recvmsg() interfaces. | |
8 | ||
9 | Direct bindings to sendmsg and recvmsg are not provided, as the API does | |
10 | not map nicely into Python. | |
11 | ||
12 | Please note that this only supports BSD-4.3+ style file descriptor | |
13 | passing, and was only tested on Linux. Patches are welcomed! | |
14 | ||
15 | For more information, see one of the R. Stevens' books: | |
16 | - Richard Stevens: Unix Network Programming, Prentice Hall, 1990; | |
17 | chapter 6.10 | |
18 | ||
19 | - Richard Stevens: Advanced Programming in the UNIX Environment, | |
20 | Addison-Wesley, 1993; chapter 15.3 | |
21 | ''' | |
22 | ||
23 | # | |
24 | # Please note that this only supports BSD-4.3+ style file descriptor passing, | |
25 | # and was only tested on Linux. Patches are welcomed! | |
26 | # | |
27 | # Copyright © 2010 Martín Ferrari <martin.ferrari@gmail.com> | |
28 | # | |
29 | # Inspired by Socket::PassAccessRights, which is: | |
30 | # Copyright (c) 2000 Sampo Kellomaki <sampo@iki.fi> | |
31 | # | |
32 | # For more information, see one of the R. Stevens' books: | |
33 | # - Richard Stevens: Unix Network Programming, Prentice Hall, 1990; | |
34 | # chapter 6.10 | |
35 | # | |
36 | # - Richard Stevens: Advanced Programming in the UNIX Environment, | |
37 | # Addison-Wesley, 1993; chapter 15.3 | |
38 | # | |
39 | # | |
40 | # This program is free software; you can redistribute it and/or modify it | |
41 | # under the terms of the GNU General Public License as published by the Free | |
42 | # Software Foundation; either version 2 of the License, or (at your option) | |
43 | # any later version. | |
44 | # | |
45 | # This program is distributed in the hope that it will be useful, but WITHOUT | |
46 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
47 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
48 | # more details. | |
49 | # | |
50 | # You should have received a copy of the GNU General Public License along with | |
51 | # this program; if not, write to the Free Software Foundation, Inc., 51 | |
52 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
53 | # | |
54 | ||
55 | import os, socket | |
56 | ||
57 | def __check_socket(sock): | |
58 | if hasattr(sock, 'family') and sock.family != socket.AF_UNIX: | |
59 | raise ValueError("Only AF_UNIX sockets are allowed") | |
60 | ||
61 | if hasattr(sock, 'fileno'): | |
62 | sock = sock.fileno() | |
63 | ||
64 | if not isinstance(sock, int): | |
65 | raise TypeError("An socket object or file descriptor was expected") | |
66 | ||
67 | return sock | |
68 | ||
69 | def __check_fd(fd): | |
70 | try: | |
71 | fd = fd.fileno() | |
72 | except AttributeError: | |
73 | pass | |
74 | if not isinstance(fd, int): | |
75 | raise TypeError("An file object or file descriptor was expected") | |
76 | ||
77 | return fd | |
78 | ||
79 | def sendfd(sock, fd, message = "NONE"): | |
80 | """Sends a message and piggybacks a file descriptor through a Unix | |
81 | domain socket. | |
82 | ||
83 | Note that the file descriptor cannot be sent by itself, at least | |
84 | one byte of payload needs to be sent also. | |
85 | ||
86 | Parameters: | |
87 | sock: socket object or file descriptor for an AF_UNIX socket | |
88 | fd: file object or file descriptor to pass | |
89 | message: message to send | |
90 | ||
91 | Return value: | |
92 | On success, sendfd returns the number of bytes sent, not including | |
93 | the file descriptor nor the control data. If there was no message | |
94 | to send, 0 is returned.""" | |
95 | ||
96 | import _passfd | |
97 | return _passfd.sendfd(__check_socket(sock), __check_fd(fd), message) | |
98 | ||
99 | def recvfd(sock, msg_buf = 4096): | |
100 | """Receive a message and a file descriptor from a Unix domain socket. | |
101 | ||
102 | Parameters: | |
103 | sock: file descriptor or socket object for an AF_UNIX socket | |
104 | buffersize: maximum message size to receive | |
105 | ||
106 | Return value: | |
107 | On success, recvfd returns a tuple containing the received | |
108 | file descriptor and message. If recvmsg fails, an OSError exception | |
109 | is raised. If the received data does not carry exactly one file | |
110 | descriptor, or if the received file descriptor is not valid, | |
111 | RuntimeError is raised.""" | |
112 | ||
113 | import _passfd | |
114 | (ret, msg) = _passfd.recvfd(__check_socket(sock), msg_buf) | |
115 | ||
116 | # -1 should raise OSError | |
117 | if ret == -2: | |
118 | raise RuntimeError("The message received did not contain exactly one" + | |
119 | " file descriptor") | |
120 | if ret == -3: | |
121 | raise RuntimeError("The received file descriptor is not valid") | |
122 | assert ret >= 0 | |
123 | ||
124 | return (ret, msg) |
0 | #!/usr/bin/env python | |
1 | # vim: set fileencoding=utf-8 | |
2 | # vim: ts=4:sw=4:et:ai:sts=4 | |
3 | ||
4 | # Copyright © 2010 Martín Ferrari <martin.ferrari@gmail.com> | |
5 | # | |
6 | # This program is free software; you can redistribute it and/or modify it | |
7 | # under the terms of the GNU General Public License as published by the Free | |
8 | # Software Foundation; either version 2 of the License, or (at your option) | |
9 | # any later version. | |
10 | # | |
11 | # This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | # more details. | |
15 | # | |
16 | # You should have received a copy of the GNU General Public License along with | |
17 | # this program; if not, write to the Free Software Foundation, Inc., 51 | |
18 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | # | |
20 | ||
21 | import os, unittest, socket, sys, threading | |
22 | from passfd import sendfd, recvfd | |
23 | import _passfd | |
24 | ||
25 | class TestPassfd(unittest.TestCase): | |
26 | def readfd_test(self, fd): | |
27 | s = os.read(fd, 512) | |
28 | self.assertEquals(s, "\0" * 512) | |
29 | ||
30 | def vrfy_recv(self, tuple, msg): | |
31 | self.readfd_test(tuple[0]) | |
32 | self.assertEquals(tuple[1], msg) | |
33 | ||
34 | def parent_tests(self, s, dgram = False): | |
35 | # First message is not even sent | |
36 | s.send("1") | |
37 | self.vrfy_recv(recvfd(s), "a") | |
38 | s.send("2") | |
39 | self.vrfy_recv(recvfd(s), "\0") | |
40 | s.send("3") | |
41 | self.vrfy_recv(recvfd(s), "foobar") | |
42 | s.send("4") | |
43 | self.vrfy_recv(recvfd(s, msg_buf = 11), "long string") # is long | |
44 | if not dgram: | |
45 | self.assertEquals(s.recv(8), " is long") # re-sync | |
46 | s.send("5") | |
47 | self.assertEquals(s.recv(100), "foobar") | |
48 | s.send("6") | |
49 | self.assertRaises(RuntimeError, recvfd, s) # No fd received | |
50 | # | |
51 | s.send("7") | |
52 | f, m = recvfd(s) | |
53 | self.assertRaises(OSError, os.fdopen, f, "w") | |
54 | s.send("8") | |
55 | (f, msg) = recvfd(s) | |
56 | self.assertEquals(msg, "writing") | |
57 | os.write(f, "foo") | |
58 | s.send("9") | |
59 | ||
60 | def child_tests(self, s, dgram = False): | |
61 | f = file("/dev/zero") | |
62 | assert sendfd(s, f, "") == 0 | |
63 | s.recv(1) | |
64 | assert sendfd(s, f, "a") == 1 | |
65 | s.recv(1) | |
66 | assert sendfd(s, f, "\0") == 1 | |
67 | s.recv(1) | |
68 | assert sendfd(s, f, "foobar") == 6 | |
69 | s.recv(1) | |
70 | assert sendfd(s, f, "long string is long") == 19 | |
71 | # The other side will recv() instead of recvmsg(), this fd would be | |
72 | # lost. I couldn't find any specification on this semantic | |
73 | s.recv(1) | |
74 | assert sendfd(s, f, "foobar") == 6 | |
75 | s.recv(1) | |
76 | assert s.send("barbaz") == 6 | |
77 | # Try to write! | |
78 | s.recv(1) | |
79 | assert sendfd(s, f, "writing") == 7 | |
80 | s.recv(1) | |
81 | f = file("/dev/null", "w") | |
82 | assert sendfd(s, f, "writing") == 7 | |
83 | s.recv(1) | |
84 | ||
85 | def test_sanity_checks(self): | |
86 | self.assertRaises(TypeError, recvfd, "foo") | |
87 | s = socket.socket(socket.AF_INET) | |
88 | self.assertRaises(ValueError, recvfd, s) | |
89 | ||
90 | (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) | |
91 | f = file("/dev/zero") | |
92 | sendfd(s0, f) | |
93 | recvfd(s1) | |
94 | ||
95 | # Using integers | |
96 | sendfd(s0.fileno(), f.fileno()) | |
97 | recvfd(s1.fileno()) | |
98 | ||
99 | self.assertRaises(TypeError, sendfd, s0, "foo") | |
100 | # Assuming fd 255 is not valid | |
101 | self.assertRaises(OSError, sendfd, s0, 255) | |
102 | ||
103 | def test_passfd_stream(self): | |
104 | (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) | |
105 | pid = os.fork() | |
106 | if pid == 0: | |
107 | s0.close() | |
108 | self.child_tests(s1) | |
109 | s1.close() | |
110 | os._exit(0) | |
111 | ||
112 | s1.close() | |
113 | self.parent_tests(s0) | |
114 | s0.close() | |
115 | ||
116 | self.assertEquals(os.waitpid(pid, 0)[1], 0) | |
117 | ||
118 | def test_passfd_dgram(self): | |
119 | (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM, 0) | |
120 | pid = os.fork() | |
121 | if pid == 0: | |
122 | s0.close() | |
123 | self.child_tests(s1, dgram = True) | |
124 | s1.close() | |
125 | os._exit(0) | |
126 | ||
127 | s1.close() | |
128 | self.parent_tests(s0, dgram = True) | |
129 | s0.close() | |
130 | ||
131 | self.assertEquals(os.waitpid(pid, 0)[1], 0) | |
132 | ||
133 | def test_threading(self): | |
134 | # Check that the GIL is correctly released before blocking | |
135 | (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) | |
136 | ||
137 | def run_server(s): | |
138 | self.child_tests(s) | |
139 | s.close() | |
140 | ||
141 | t = threading.Thread(target = run_server, args = (s1,)) | |
142 | t.start() | |
143 | self.parent_tests(s0) | |
144 | s0.close() | |
145 | t.join() | |
146 | ||
147 | if __name__ == '__main__': | |
148 | unittest.main() | |
149 |