qmsk/net/transport/socket.py
changeset 37 14db3fe42b6c
parent 33 c71de00715d6
child 45 bb49bf8222ed
equal deleted inserted replaced
36:4d5c02fe9c27 37:14db3fe42b6c
    67 class Common (Base) :
    67 class Common (Base) :
    68     """
    68     """
    69         Common operations for Client/Service
    69         Common operations for Client/Service
    70     """
    70     """
    71 
    71 
    72     @classmethod
    72     # default socktype
    73     def _socket (self, family, socktype, protocol = 0) :
    73     _SOCKTYPE = 0
       
    74 
       
    75     @classmethod
       
    76     def _socket (cls, family, socktype = None, protocol = 0) :
    74         """
    77         """
    75             Construct and return a new socket object using the given parameters.
    78             Construct and return a new socket object using the given parameters.
    76         """
    79         """
       
    80 
       
    81         if socktype is None :
       
    82             socktype = cls._SOCKTYPE
    77 
    83 
    78         return socket.socket(family, socktype, protocol)
    84         return socket.socket(family, socktype, protocol)
    79 
    85 
    80     @classmethod
    86     @classmethod
    81     def _bind_addrinfo (cls, ai) :
    87     def _bind_addrinfo (cls, ai) :
    98            
   104            
    99         else :
   105         else :
   100             return sock
   106             return sock
   101 
   107 
   102     @classmethod
   108     @classmethod
   103     def _bind_endpoint (cls, endpoint, family, socktype, protocol=0) :
   109     def _bind_endpoint (cls, endpoint, socktype = None, protocol=0) :
   104         """
   110         """
   105             This will resolve the given endpoint, and attempt to create and bind a suitable socket and return it.
   111             This will resolve the given endpoint, and attempt to create and bind a suitable socket and return it.
   106 
   112 
   107                 endpoint        - local Endpoint to bind() to.
   113                 endpoint        - local Endpoint to bind() to.
   108                 family          - socket address family to use.
   114                 socktype        - (optiona) socket type to use, defaults to _SOCKTYPE
   109                 socktype        - socket type to use
       
   110                 protocol        - (optional) specific protocol
   115                 protocol        - (optional) specific protocol
   111 
   116 
   112             Raises a ServiceBindError if this is unable to create a bound socket.
   117             Raises a ServiceBindError if this is unable to create a bound socket.
   113 
   118 
   114             XXX: bind to all of the given endpoint's addresses instead of just one...?
   119             XXX: bind to all of the given endpoint's addresses instead of just one...?
   115         """
   120         """
   116         
   121         
   117         errors = []
   122         errors = []
   118         
   123         
       
   124         if socktype is None :
       
   125             socktype = cls._SOCKTYPE
       
   126         
   119         # resolve the endpoint and try socket+bind
   127         # resolve the endpoint and try socket+bind
   120         for ai in endpoint.resolve(family, socktype, protocol, AI_PASSIVE) :
   128         for ai in endpoint.resolve(socktype, protocol, AI_PASSIVE) :
   121             try :
   129             try :
   122                 # try to socket+bind this addrinfo
   130                 # try to socket+bind this addrinfo
   123                 sock = cls._bind_addrinfo(ai)
   131                 sock = cls._bind_addrinfo(ai)
   124             
   132             
   125             except SocketBindAddrinfoError, error :
   133             except SocketBindAddrinfoError, error :
   135        
   143        
   136         else :
   144         else :
   137             # no suitable address found :(
   145             # no suitable address found :(
   138             raise SocketBindEndpointError(endpoint, errors)
   146             raise SocketBindEndpointError(endpoint, errors)
   139     
   147     
   140     def _init_endpoint (self, endpoint, family, socktype, protocol = 0) :
   148     def _init_endpoint (self, endpoint, socktype = None, protocol = 0, family = None) :
   141         """
   149         """
   142             Initialize this socket by constructing a new socket with the given parameters, bound to the given endpoint,
   150             Initialize this socket by constructing a new socket with the given parameters, bound to the given endpoint,
   143             if given. If no endpoint is given, this simply creates a socket with the given settings and does not bind
   151             if given. If no endpoint is given, this simply creates a socket with the given settings and does not bind
   144             it anywhere.
   152             it anywhere.
   145         """
   153         """
   146 
   154         
   147         # create local socket
   155         if endpoint is not None :
   148         if endpoint :
       
   149             # create a suitable socket bound to a the given endpoint
   156             # create a suitable socket bound to a the given endpoint
   150             self.sock = self._bind_endpoint(endpoint, family, socktype, protocol)
   157             self.sock = self._bind_endpoint(endpoint, socktype, protocol)
   151 
   158         
   152         else :
   159         else :
   153             # create a suitable socket not bound to anything
   160             assert family
       
   161 
       
   162             # simply create a socket
   154             self.sock = self._socket(family, socktype, protocol)
   163             self.sock = self._socket(family, socktype, protocol)
   155 
       
   156 
   164 
   157 class Service (Common) :
   165 class Service (Common) :
   158     """
   166     """
   159         Listener socket
   167         Listener socket
   160     """
   168     """
   250         
   258         
   251         # return once succesfully
   259         # return once succesfully
   252         return sock
   260         return sock
   253 
   261 
   254     @classmethod
   262     @classmethod
   255     def _connect_sock_endpoint (cls, sock, endpoint, family, socktype, protocol = 0) :
   263     def _connect_sock_endpoint (cls, sock, endpoint, socktype = None, protocol = 0) :
   256         """
   264         """
   257             Connect this socket to the given remote endpoint, using the given parameters to resolve the endpoint.
   265             Connect this socket to the given remote endpoint, using the given parameters to resolve the endpoint.
   258         """
   266         """
   259         
   267         
   260         errors = []
   268         errors = []
   261         
   269         
       
   270         if socktype is None :
       
   271             socktype = cls._SOCKTYPE
       
   272 
   262         # resolve the endpoint and try socket+bind
   273         # resolve the endpoint and try socket+bind
   263         for ai in endpoint.resolve(family, socktype, protocol) :
   274         for ai in endpoint.resolve(socktype, protocol) :
   264             try :
   275             try :
   265                 # try to connect the socket to this addrinfo
   276                 # try to connect the socket to this addrinfo
   266                 cls._connect_sock_addrinfo(sock, ai)
   277                 cls._connect_sock_addrinfo(sock, ai)
   267             
   278             
   268             except SocketConnectAddrinfoError, error :
   279             except SocketConnectAddrinfoError, error :
   279         else :
   290         else :
   280             # no suitable address found :(
   291             # no suitable address found :(
   281             raise SocketConnectEndpointError(endpoint, errors)
   292             raise SocketConnectEndpointError(endpoint, errors)
   282     
   293     
   283     @classmethod
   294     @classmethod
   284     def _connect_endpoint (cls, endpoint, family, socktype, protocol = 0) :
   295     def _connect_endpoint (cls, endpoint, socktype = None, protocol = 0) :
   285         """
   296         """
   286             Create a new socket and connect it to the given remote endpoint, using the given parameters to resolve the
   297             Create a new socket and connect it to the given remote endpoint, using the given parameters to resolve the
   287             endpoint.
   298             endpoint.
   288         """
   299         """
   289 
   300 
   290         errors = []
   301         errors = []
   291         
   302         
       
   303         if socktype is None :
       
   304             socktype = cls._SOCKTYPE
       
   305 
   292         # resolve the endpoint and try socket+bind
   306         # resolve the endpoint and try socket+bind
   293         for ai in endpoint.resolve(family, socktype, protocol) :
   307         for ai in endpoint.resolve(socktype, protocol) :
   294             try :
   308             try :
   295                 # try to socket+connect this addrinfo
   309                 # try to socket+connect this addrinfo
   296                 sock = cls._connect_addrinfo(ai)
   310                 sock = cls._connect_addrinfo(ai)
   297             
   311             
   298             except SocketConnectAddrinfoError, error :
   312             except SocketConnectAddrinfoError, error :
   308        
   322        
   309         else :
   323         else :
   310             # no suitable address found :(
   324             # no suitable address found :(
   311             raise SocketConnectEndpointError(endpoint, errors)
   325             raise SocketConnectEndpointError(endpoint, errors)
   312 
   326 
   313     def _init_connect_endpoint (self, endpoint, family, socktype, protocol = 0):
   327     def _init_connect_endpoint (self, endpoint, socktype = None, protocol = 0):
   314         """
   328         """
   315             If we already have an existing socket, connect it to the given endpoint, otherwise try and connect to the
   329             If we already have an existing socket, connect it to the given endpoint, otherwise try and connect to the
   316             given endpoint with a new socket.
   330             given endpoint with a new socket.
   317 
   331 
   318             There is a subtle difference here, because if we have e.g. an IPv4 socket and try and connect it to an
   332             There is a subtle difference here, because if we have e.g. an IPv4 socket and try and connect it to an
   323             and to the IPv4 address using an IPv4 socket.
   337             and to the IPv4 address using an IPv4 socket.
   324         """
   338         """
   325 
   339 
   326         if self.socket :
   340         if self.socket :
   327             # connect with existing socket
   341             # connect with existing socket
   328             self._connect_sock_endpoint(self.socket, endpoint, family, socktype, protocol)
   342             self._connect_sock_endpoint(self.socket, endpoint, socktype, protocol)
   329 
   343 
   330         else :
   344         else :
   331             # connect with new socket
   345             # connect with new socket
   332             self._connect_endpoint(endpoint, family, socktype, protocol)
   346             self._connect_endpoint(endpoint, socktype, protocol)
   333 
   347 
   334 class Stream (Base) :
   348 class Stream (Base) :
   335     """
   349     """
   336         Unbuffered byte-stream interface.
   350         Unbuffered byte-stream interface.
   337     """
   351     """