qmsk/net/transport/tcp.py
author Tero Marttila <terom@fixme.fi>
Mon, 31 Aug 2009 22:19:16 +0300
branchconnect-async
changeset 45 bb49bf8222ed
parent 37 14db3fe42b6c
permissions -rw-r--r--
initial async connect attempt
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     1
"""
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     2
    TCP service/client implementation.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     3
"""
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     4
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     5
from qmsk.net.transport import service, client, stream, socket
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     6
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     7
# default backlog for listen()
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     8
# XXX: number pulled out of a hat
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     9
LISTEN_BACKLOG = 5
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    10
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    11
class Connection (socket.Stream, stream.Stream) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    12
    """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    13
        Stream interface for a TCP connection
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    14
    """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    15
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    16
    def __init__ (self, sock) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    17
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    18
            Initialize with the given already-existing, connected, socket.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    19
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    20
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    21
        self._init_sock(sock)
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    22
    
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    23
    def shutdown (self, how) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    24
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    25
            Selectively shut-down parts of all of the full-duplex TCP connection.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    26
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    27
                how             - one of socket.SHUT_* to shutdown read, write or both.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    28
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    29
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    30
        self.sock.shutdown(how)
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    31
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    32
class Service (socket.Service, service.Service) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    33
    """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    34
        An implementation of Service for TCP sockets.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    35
    """
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    36
    
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    37
    _SOCKTYPE = socket.SOCK_STREAM
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    38
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    39
    def __init__ (self, endpoint, listen_backlog=LISTEN_BACKLOG, family=None) :
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    40
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    41
            Construct a service, bound to the given local endpoint and listening for incoming connections using the
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    42
            given backlog.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    43
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    44
                endpoint        - local Endpoint to bind() to. Usually, it is enough to just specify the port.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    45
                listen_backlog  - backlog length argument to use for socket.listen()
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    46
                family          - (optional) address family to use if no endpoint is given
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    47
            
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    48
            Note that as a special case, it is possible to construct a service without an Endpoint (i.e. None).
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    49
            In this case, there will be no socket.bind() call, instead, a socket is created with the given address
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    50
            family (which *MUST* be given), and .listen() causes the OS to pick a local address to use.
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    51
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    52
            This will raise an error if the bind() or listen() operations fail.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    53
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    54
        
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    55
        # construct a suitable socket bound to the given endpoint
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
    56
        self._init_endpoint(endpoint, family=family)
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    57
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    58
        # make us listen
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    59
        self._listen(listen_backlog)
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    60
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    61
        # ok, great
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    62
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    63
    def accept (self, cls=Connection) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    64
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    65
            Perform an accept() operation on our socket, returning a tcp.Connection.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    66
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    67
        
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    68
        # XXX: trap and raise a ServiceAcceptError?
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    69
        # XXX: what to do with addr?
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    70
        sock, addr = self.sock.accept()
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    71
        
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    72
        # construct the new Stream
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    73
        return cls(sock)
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    74
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    75
    def close (self) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    76
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    77
            Close the underlying socket object, invalidating this Service for future use.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    78
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    79
            This will raise if the underlying socket.close() operation does.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    80
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    81
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    82
        self.sock.close()
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    83
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    84
class Connector (socket.Connect) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    85
    """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    86
        The connect() state machine.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    87
    """
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    88
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    89
    def __init__ (self, bind_endpoint=None, family=None) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    90
        # bind()?
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    91
        if bind_endpoint or family :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    92
            # construct a socket as defined
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    93
            self._init_endpoint(bind_endpoint, family=family)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    94
 
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    95
    def start (self, endpoint) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    96
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    97
            Start connecting to the given endpoint
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    98
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
    99
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   100
        # connect()-time errors
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   101
        self._errors = []
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   102
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   103
        # resolve the list of addresses to try and connect to
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   104
        self._ais = self._resolve_endpoint(endpoint)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   105
    
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   106
    def cleanup (self) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   107
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   108
            Destroy any used state
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   109
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   110
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   111
        del self._errors
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   112
        del self._ais
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   113
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   114
    def build_error (self) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   115
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   116
            Build and return an error object for this connect operation, and cleanup
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   117
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   118
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   119
        error = socket.SocketConnectEndpointError(self._connect_endpoint, self._connect_errors)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   120
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   121
        self.cleanup()
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   122
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   123
        return error
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   124
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   125
    def operate (self, nonblocking=True) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   126
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   127
            Try and connect to each of our AddrInfo's in turn, collecting any errors, until we either run out of
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   128
            addresses to try, or we manage to connect().
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   129
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   130
                nonblocking - perform non-blocking connect()'s, so put the socket into non-blocking mode and treat
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   131
                              EINPROGRESS as a succesful connect().
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   132
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   133
            Returns True if we managed to connect, otherwise False.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   134
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   135
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   136
        # get next addrinfo to try
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   137
        for ai in self._connect_ais :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   138
            try :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   139
                if self.sock :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   140
                    # try and connect the existing socket
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   141
                    self._connect_sock_addrinfo(self.sock, ai, nonblocking)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   142
                
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   143
                else :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   144
                    # create a new socket and connect it
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   145
                    self.sock = self._connect_addrinfo(ai, nonblocking)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   146
            
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   147
            except SocketConnectAddrinfoError, error :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   148
                # log it
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   149
                self._errors.append(error)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   150
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   151
                # try the next one
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   152
                continue
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   153
            
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   154
            else :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   155
                # yay!
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   156
                return True
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   157
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   158
        else :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   159
            # unable to connect anywhere, nothing left to try
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   160
            return False
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   161
    
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   162
    def next (self) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   163
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   164
            Operate asynchronously, 
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   165
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   166
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   167
        if not self.operate() :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   168
            # faail
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   169
            pass
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   170
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   171
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   172
    def connect (self, endpoint) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   173
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   174
            Operate synchronously, either raising an error, or returning a socket.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   175
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   176
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   177
        # init
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   178
        self.start(endpoint)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   179
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   180
        if not self.operate() :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   181
            # nay :(
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   182
            raise self.build_error()
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   183
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   184
        else :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   185
            # yay :)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   186
            return self.sock
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   187
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   188
class Client (client.Client) :
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   189
    """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   190
        An implementation of Client for TCP sockets.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   191
    """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   192
37
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
   193
    _SOCKTYPE = socket.SOCK_STREAM
14db3fe42b6c move address-family from tcp/socket interface to endpoint interface. The address family of a socket is strictly a property of the address passed to it
Tero Marttila <terom@fixme.fi>
parents: 28
diff changeset
   194
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   195
    def __init__ (self, connect_endpoint, bind_endpoint=None, family=None) :
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   196
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   197
            Construct a client, connecting to the given remote endpoint.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   198
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   199
                connect_endpoint    - remote Endpoint to connect() to.
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   200
                bind_endpoint       - (optional) local Endpoint to bind() to before connecting.
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   201
                family              - (optional) family to create sockaddr for
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   202
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   203
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   204
        # store
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   205
        self._connect_endpoint = connect_endpoint
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   206
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   207
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   208
   
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   209
   
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   210
  
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   211
   
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   212
    def _connect_next (self) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   213
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   214
            Driver for the async connect process
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   215
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   216
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   217
        if self._connect(async=True) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   218
            # yay :)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   219
            self._connect_deinit()
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   220
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   221
            self.on_connect()
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   222
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   223
        else :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   224
            # nay :(
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   225
            self.on_error(self._connect_error())
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   226
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   227
    def connect (self, cls=Connection) :
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   228
        """
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   229
            Perform a synchronous connect() operation.
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   230
        """
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   231
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   232
        connector = Connector(self.bind_endpoint, self.family)
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   233
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   234
        sock = connector.connect(self.connect_endpoint)
28
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   235
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   236
        return cls(sock)
020c89baaa33 [transport] initial TCP implementation
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   237
45
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   238
    def connect_async (self, reactor=None) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   239
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   240
            Perform an asynchronous connect() operation, returning a Connector object.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   241
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   242
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   243
        connector = Connector(self.bind_endpoint, self.family)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   244
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   245
        connector.start(self.connect_endpoint)
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   246
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   247
        return connector
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   248
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   249
    def on_connect (self) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   250
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   251
            Succesfully connected.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   252
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   253
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   254
        pass
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   255
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   256
    def on_error (self, error) :
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   257
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   258
            Connection failed.
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   259
        """
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   260
        
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   261
        pass
bb49bf8222ed initial async connect attempt
Tero Marttila <terom@fixme.fi>
parents: 37
diff changeset
   262