File: sendfd.py

package info (click to toggle)
twisted 25.5.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 20,560 kB
  • sloc: python: 203,171; makefile: 200; sh: 92; javascript: 36; xml: 31
file content (85 lines) | stat: -rw-r--r-- 2,944 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

"""
Server-side of an example for sending file descriptors between processes over
UNIX sockets.  This server accepts connections on a UNIX socket and sends one
file descriptor to them, along with the name of the file it is associated with.

To run this example, run this program with two arguments: a path giving a UNIX
socket to listen on (must not exist) and a path to a file to send to clients
which connect (must exist).  For example:

    $ python sendfd.py /tmp/sendfd.sock /etc/motd

It will listen for client connections until stopped (eg, using Control-C).  Most
interesting behavior happens on the client side.

See recvfd.py for the client side of this example.
"""

if __name__ == "__main__":
    import sendfd

    raise SystemExit(sendfd.main())

import sys

from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.python.filepath import FilePath
from twisted.python.log import startLogging


class SendFDProtocol(LineOnlyReceiver):
    def connectionMade(self):
        # Open the desired file and keep a reference to it - keeping it open
        # until we know the other side has it.  Closing it early will prevent
        # it from actually being sent.
        self.fObj = self.factory.content.open()

        # Tell the transport to send it.  It is not necessarily sent when this
        # method returns.  The reactor may need to run for a while longer before
        # that happens.
        self.transport.sendFileDescriptor(self.fObj.fileno())

        # Send along *at least* one byte, since one file descriptor was sent.
        # In this case, send along the name of the file to let the other side
        # have some idea what they're getting.
        encoding = sys.getfilesystemencoding()
        self.sendLine(self.factory.content.path.encode(encoding))

        # Give the other side a minute to deal with this.  If they don't close
        # the connection by then, we will do it for them.
        self.timeoutCall = reactor.callLater(60, self.transport.loseConnection)

    def connectionLost(self, reason):
        # Clean up the file object, it is no longer needed.
        self.fObj.close()
        self.fObj = None

        # Clean up the timeout, if necessary.
        if self.timeoutCall.active():
            self.timeoutCall.cancel()
            self.timeoutCall = None


def main():
    address = FilePath(sys.argv[1])
    content = FilePath(sys.argv[2])

    if address.exists():
        raise SystemExit("Cannot listen on an existing path")

    if not content.isfile():
        raise SystemExit("Content file must exist")

    startLogging(sys.stdout)

    serverFactory = Factory()
    serverFactory.content = content
    serverFactory.protocol = SendFDProtocol

    reactor.listenUNIX(address.path, serverFactory)
    reactor.run()