~dustin-spy/twisted/dustin

« back to all changes in this revision

Viewing changes to twisted/internet/udp.py

  • Committer: moshez
  • Date: 2001-09-23 01:44:48 UTC
  • Revision ID: vcs-imports@canonical.com-20010923014448-23d90217b748f28d
First prototype of twisted.names
* Changed udp.Port to simulate connections
  + We need to get rid of .dup() at some point
  + Added UDP into regular echoserv, to show how easy it is
* Added protocol implementation
  + Two different ones, UDP and TCP are not exactly the same
* Added twisted.names
  + Manages resolving

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import socket
25
25
import traceback
26
26
 
 
27
if os.name == 'nt':
 
28
    EWOULDBLOCK = 10035
 
29
else:
 
30
    from errno import EWOULDBLOCK
 
31
 
27
32
# Twisted Imports
28
33
from twisted.protocols import protocol
29
34
from twisted.persisted import styles
31
36
 
32
37
# Sibling Imports
33
38
import abstract
 
39
from main import CONNECTION_LOST, CONNECTION_DONE
 
40
 
 
41
 
 
42
class Connection(abstract.FileDescriptor,
 
43
                 protocol.Transport,
 
44
                 styles.Ephemeral):
 
45
    """This is a UDP virtual connection
 
46
 
 
47
    This transport connects to a given host/port over UDP. By nature
 
48
    of UDP, only outgoing communications are allowed.  If a connection
 
49
    is initiated by a packet arriving at a UDP port, it is up to the
 
50
    port to call dataReceived with that packet.  By default, once data
 
51
    is written once to the connection, it is lost.
 
52
    """
 
53
 
 
54
    keepConnection = 0
 
55
 
 
56
    def __init__(self, skt, protocol, remote, local, sessionno):
 
57
        self.socket = skt
 
58
        self.fileno = skt.fileno
 
59
        self.remote = remote
 
60
        self.protocol = protocol
 
61
        self.local = local
 
62
        self.sessionno = sessionno
 
63
        self.connected = 1
 
64
        self.logstr = "%s,%s,%s (UDP)" % (self.protocol.__class__.__name__, sessionno, self.remote[0])
 
65
 
 
66
    def write(self,data):
 
67
        res = abstract.FileDescriptor.write(self,data)
 
68
        if not self.keepConnection:
 
69
            self.loseConnection()
 
70
        return res
 
71
 
 
72
    def writeSomeData(self, data):
 
73
        """Connection.writeSomeData(data) -> #of bytes written | CONNECTION_LOST
 
74
        This writes as much data as possible to the socket and returns either
 
75
        the number of bytes read (which is positive) or a connection error code
 
76
        (which is negative)
 
77
        """
 
78
        if len(data) > 0:
 
79
            try:
 
80
                return self.socket.sendto(data, self.remote)
 
81
            except socket.error, se:
 
82
                if se.args[0] == EWOULDBLOCK:
 
83
                    return 0
 
84
                return CONNECTION_LOST
 
85
        else:
 
86
            return 0
 
87
 
 
88
    def connectionLost(self):
 
89
        """See abstract.FileDescriptor.connectionLost().
 
90
        """
 
91
        protocol = self.protocol
 
92
        del self.protocol
 
93
        abstract.FileDescriptor.connectionLost(self)
 
94
        self.socket.close()
 
95
        del self.socket
 
96
        del self.fileno
 
97
        protocol.connectionLost()
 
98
 
 
99
    def logPrefix(self):
 
100
        """Return the prefix to log with when I own the logging thread.
 
101
        """
 
102
        return self.logstr
 
103
 
 
104
    def getPeer(self):
 
105
        """
 
106
        Returns a tuple of ('INET_UDP', hostname, port), indicating
 
107
        the connected client's address
 
108
        """
 
109
        return ('INET_UDP',)+self.remote
 
110
 
 
111
    def getHost(self):
 
112
        """
 
113
        Returns a tuple of ('INET_UDP', hostname, port), indicating
 
114
        the servers address
 
115
        """
 
116
        return ('INET_UDP',)+self.socket.getsockname()
 
117
 
34
118
 
35
119
class Port(abstract.FileDescriptor):
36
120
    """I am a UDP server port, listening for packets.
38
122
    When a packet is received, I will call my factory's packetReceived
39
123
    with the packet and an address.
40
124
    """
41
 
    
42
 
    def __init__(self, port, factory, maxPacketSize=8192):
 
125
 
 
126
    sessionno = 0
 
127
 
 
128
    def __init__(self, port, factory, interface='', maxPacketSize=8192):
43
129
        """Initialize with a numeric port to listen on.
44
130
        """
45
131
        self.port = port
46
132
        self.factory = factory
47
133
        self.maxPacketSize = maxPacketSize
 
134
        self.interface = interface
 
135
        self.setLogStr()
48
136
 
49
137
    def __repr__(self):
50
138
        return "<%s on %s>" % (self.factory.__class__, self.port)
75
163
        """
76
164
        log.msg("%s starting on %s"%(self.factory.__class__, self.port))
77
165
        skt = self.createInternetSocket()
78
 
        skt.bind( ('',self.port) )
 
166
        skt.bind( (self.interface ,self.port) )
79
167
        self.connected = 1
80
168
        self.socket = skt
81
169
        self.fileno = self.socket.fileno
82
170
        self.startReading()
83
171
 
 
172
    def createConnection(self, addr):
 
173
        """Creates a virtual connection over UDP"""
 
174
        try:
 
175
            protocol = self.factory.buildProtocol(addr)
 
176
            s = self.sessionno
 
177
            self.sessionno = s+1
 
178
            transport = Connection(self.socket.dup(), protocol, addr, self, s)
 
179
            protocol.makeConnection(transport, self)
 
180
        except:
 
181
            traceback.print_exc(file=log.logfile)
 
182
        return transport
 
183
 
84
184
    def doRead(self):
85
185
        """Called when my socket is ready for reading.
86
 
        
87
 
        This gets a packet and calls the factory's packetReceived
88
 
        method to handle it.
 
186
 
 
187
        This reads a packet, calls self.protocol() to handle it.
89
188
        """
90
189
        try:
91
190
            data, addr = self.socket.recvfrom(self.maxPacketSize)
92
 
            self.factory.packetReceived(data, addr, self)
 
191
            transport = self.createConnection(addr)
 
192
            # Ugly patch needed because logically control passes here
 
193
            # from the port to the transport.
 
194
            self.logstr = transport.logPrefix()
 
195
            transport.protocol.dataReceived(data)
 
196
            self.setLogStr()
93
197
        except:
94
198
            traceback.print_exc(file=log.logfile)
95
199
 
119
223
        del self.socket
120
224
        del self.fileno
121
225
 
 
226
    def setLogStr(self):
 
227
        self.logstr = str(self.factory.__class__) + " (UDP)"
 
228
 
122
229
    def logPrefix(self):
123
230
        """Returns the name of my class, to prefix log entries with.
124
231
        """
125
 
        return str(self.factory.__class__)
 
232
        return self.logstr