def connect(self, connectionInfo, elementListener, onConnected): """ Connect according to the info in connectionInfo, and use elementListener. :param UdpTransport.ConnectionInfo connectionInfo: A UdpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement :param onConnected: This calls onConnected() when the connection is established. :type onConnected: function object """ self.close() # Save the _address to use in sendto. self._address = (connectionInfo.getHost(), connectionInfo.getPort()) self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) if connectionInfo.getLocalPort() != None: self._socket.bind(("0.0.0.0", connectionInfo.getLocalPort())) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) if onConnected != None: onConnected()
def connect(self, connectionInfo, elementListener): """ Connect according to the info in connectionInfo, and use elementListener. :param UnixTransport.ConnectionInfo connectionInfo: A UnixTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedData """ self.close() self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._socket.connect(connectionInfo.getFilePath()) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener)
def connect(self, connectionInfo, elementListener): """ Connect according to the info in connectionInfo, and use elementListener. :param UdpTransport.ConnectionInfo connectionInfo: A UdpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedData """ self.close() # Save the _address to use in sendto. self._address = (connectionInfo.getHost(), connectionInfo.getPort()) self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener)
def connect(self, connectionInfo, elementListener, onConnected): """ Connect according to the info in connectionInfo, and use elementListener. :param UnixTransport.ConnectionInfo connectionInfo: A UnixTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement :param onConnected: This calls onConnected() when the connection is established. :type onConnected: function object """ self.close() self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._socket.connect(connectionInfo.getFilePath()) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) onConnected()
class UdpTransport(Transport): """ Create a new UdpTransport in the unconnected state. """ def __init__(self): self._socket = None self._socketPoller = None self._buffer = bytearray(Common.MAX_NDN_PACKET_SIZE) # Create a Blob and take its buf() since this creates a memoryview # which is more efficient for slicing. self._bufferView = Blob(self._buffer, False).buf() self._elementReader = None class ConnectionInfo(Transport.ConnectionInfo): """ Create a new UdpTransport.ConnectionInfo which extends Transport.ConnectionInfo to hold the host and port info for the UDP connection. :param str host: The host for the connection. :param int port: (optional) The port number for the connection. If omitted, use 6363. """ def __init__(self, host, port = 6363): self._host = host self._port = port def getHost(self): """ Get the host given to the constructor. :return: The host. :rtype: str """ return self._host def getPort(self): """ Get the port given to the constructor. :return: The port. :rtype: int """ return self._port def isLocal(self, connectionInfo): """ Determine whether this transport connecting according to connectionInfo is to a node on the current machine. UDP transports are always non-local. :param UdpTransport.ConnectionInfo connectionInfo: This is ignored. :return: False because UDP transports are always non-local. :rtype: bool """ return False def isAsync(self): """ Override to return false since connect does not need to use the onConnected callback. :return: False :rtype bool: """ return False def connect(self, connectionInfo, elementListener, onConnected): """ Connect according to the info in connectionInfo, and use elementListener. :param UdpTransport.ConnectionInfo connectionInfo: A UdpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement :param onConnected: This calls onConnected() when the connection is established. :type onConnected: function object """ self.close() # Save the _address to use in sendto. self._address = (connectionInfo.getHost(), connectionInfo.getPort()) self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) if onConnected != None: onConnected() # This will be set True if send gets a TypeError. _sendNeedsStr = False def send(self, data): """ Send data to the host. :param data: The buffer of data to send. :type data: An array type accepted by socket.send """ if UdpTransport._sendNeedsStr: # This version of sendall can't use a memoryview, etc., so convert. self._socket.sendto(str(bytearray(data)), self._address) else: try: self._socket.sendto(data, self._address) except TypeError: # Assume we need to convert to a str. UdpTransport._sendNeedsStr = True self.send(data) def processEvents(self): """ Process any data to receive. For each element received, call elementListener.onReceivedElement. This is non-blocking and will silently time out after a brief period if there is no data to receive. You should repeatedly call this from an event loop. You should normally not call this directly since it is called by Face.processEvents. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ if not self.getIsConnected(): return # Loop until there is no more data in the receive buffer. while True: if not self._socketPoller.isReady(): # There is no data waiting. return nBytesRead, _ = self._socket.recvfrom_into(self._buffer) if nBytesRead <= 0: # Since we checked for data ready, we don't expect this. return # _bufferView is a memoryview, so we can slice efficienty. self._elementReader.onReceivedData(self._bufferView[0:nBytesRead]) def getIsConnected(self): """ For UDP, there really is no connection, but just return True if connect has been called. :return: True if connected. :rtype: bool """ if self._socket == None: return False # Assume we are still connected. TODO: Do a test receive? return True def close(self): """ Close the connection. If not connected, this does nothing. """ if self._socketPoller != None: self._socketPoller.close() self._socketPoller = None if self._socket != None: self._socket.close() self._socket = None
class UnixTransport(Transport): """ Create a new UnixTransport in the unconnected state. """ def __init__(self): self._socket = None self._socketPoller = None self._buffer = bytearray(8000) # Create a Blob and take its buf() since this creates a memoryview # which is more efficient for slicing. self._bufferView = Blob(self._buffer, False).buf() self._elementReader = None class ConnectionInfo(Transport.ConnectionInfo): """ Create a new UnixTransport.ConnectionInfo which extends Transport.ConnectionInfo to hold the socket file path for the Unix socket connection. :param str filePath: The file path of the Unix socket file. """ def __init__(self, filePath): self._filePath = filePath def getFilePath(self): """ Get the filePath given to the constructor. :return: The file path. :rtype: str """ return self._filePath def connect(self, connectionInfo, elementListener): """ Connect according to the info in connectionInfo, and use elementListener. :param UnixTransport.ConnectionInfo connectionInfo: A UnixTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedData """ self.close() self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._socket.connect(connectionInfo.getFilePath()) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) # This will be set True if send gets a TypeError. _sendNeedsStr = False def send(self, data): """ Set data to the host. :param data: The buffer of data to send. :type data: An array type accepted by socket.send """ if UnixTransport._sendNeedsStr: # This version of sendall can't use a memoryview, etc., so convert. self._socket.sendall(str(bytearray(data))) else: try: self._socket.sendall(data) except TypeError: # Assume we need to convert to a str. UnixTransport._sendNeedsStr = True self.send(data) def processEvents(self): """ Process any data to receive. For each element received, call elementListener.onReceivedElement. This is non-blocking and will silently time out after a brief period if there is no data to receive. You should repeatedly call this from an event loop. You should normally not call this directly since it is called by Face.processEvents. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ if not self.getIsConnected(): return # Loop until there is no more data in the receive buffer. while True: if not self._socketPoller.isReady(): # There is no data waiting. return nBytesRead = self._socket.recv_into(self._buffer) if nBytesRead <= 0: # Since we checked for data ready, we don't expect this. return # _bufferView is a memoryview, so we can slice efficienty. self._elementReader.onReceivedData(self._bufferView[0:nBytesRead]) def getIsConnected(self): """ Check if the transport is connected. :return: True if connected. :rtype: bool """ if self._socket == None: return False # Assume we are still connected. TODO: Do a test receive? return True def close(self): """ Close the connection. If not connected, this does nothing. """ if self._socketPoller != None: self._socketPoller.close() self._socketPoller = None if self._socket != None: self._socket.close() self._socket = None
class UdpTransport(Transport): """ Create a new UdpTransport in the unconnected state. """ def __init__(self): self._socket = None self._socketPoller = None self._buffer = bytearray(8000) # Create a Blob and take its buf() since this creates a memoryview # which is more efficient for slicing. self._bufferView = Blob(self._buffer, False).buf() self._elementReader = None class ConnectionInfo(Transport.ConnectionInfo): """ Create a new UdpTransport.ConnectionInfo which extends Transport.ConnectionInfo to hold the host and port info for the UDP connection. :param str host: The host for the connection. :param int port: (optional) The port number for the connection. If omitted, use 6363. """ def __init__(self, host, port = 6363): self._host = host self._port = port def getHost(self): """ Get the host given to the constructor. :return: The host. :rtype: str """ return self._host def getPort(self): """ Get the port given to the constructor. :return: The port. :rtype: int """ return self._port def connect(self, connectionInfo, elementListener): """ Connect according to the info in connectionInfo, and use elementListener. :param UdpTransport.ConnectionInfo connectionInfo: A UdpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement """ self.close() # Save the _address to use in sendto. self._address = (connectionInfo.getHost(), connectionInfo.getPort()) self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) # This will be set True if send gets a TypeError. _sendNeedsStr = False def send(self, data): """ Set data to the host. :param data: The buffer of data to send. :type data: An array type accepted by socket.send """ if UdpTransport._sendNeedsStr: # This version of sendall can't use a memoryview, etc., so convert. self._socket.sendto(str(bytearray(data)), self._address) else: try: self._socket.sendto(data, self._address) except TypeError: # Assume we need to convert to a str. UdpTransport._sendNeedsStr = True self.send(data) def processEvents(self): """ Process any data to receive. For each element received, call elementListener.onReceivedElement. This is non-blocking and will silently time out after a brief period if there is no data to receive. You should repeatedly call this from an event loop. You should normally not call this directly since it is called by Face.processEvents. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ if not self.getIsConnected(): return # Loop until there is no more data in the receive buffer. while True: if not self._socketPoller.isReady(): # There is no data waiting. return nBytesRead, _ = self._socket.recvfrom_into(self._buffer) if nBytesRead <= 0: # Since we checked for data ready, we don't expect this. return # _bufferView is a memoryview, so we can slice efficienty. self._elementReader.onReceivedData(self._bufferView[0:nBytesRead]) def getIsConnected(self): """ For UDP, there really is no connection, but just return True if connect has been called. :return: True if connected. :rtype: bool """ if self._socket == None: return False # Assume we are still connected. TODO: Do a test receive? return True def close(self): """ Close the connection. If not connected, this does nothing. """ if self._socketPoller != None: self._socketPoller.close() self._socketPoller = None if self._socket != None: self._socket.close() self._socket = None
class TcpTransport(Transport): """ Create a new TcpTransport in the unconnected state. """ def __init__(self): self._socket = None self._socketPoller = None self._buffer = bytearray(Common.MAX_NDN_PACKET_SIZE) # Create a Blob and take its buf() since this creates a memoryview # which is more efficient for slicing. self._bufferView = Blob(self._buffer, False).buf() self._elementReader = None self._connectionInfo = None self._isLocal = False class ConnectionInfo(Transport.ConnectionInfo): """ Create a new TcpTransport.ConnectionInfo which extends Transport.ConnectionInfo to hold the host and port info for the TCP connection. :param str host: The host for the connection. :param int port: (optional) The port number for the connection. If omitted, use 6363. """ def __init__(self, host, port = 6363): self._host = host self._port = port def getHost(self): """ Get the host given to the constructor. :return: The host. :rtype: str """ return self._host def getPort(self): """ Get the port given to the constructor. :return: The port. :rtype: int """ return self._port def isLocal(self, connectionInfo): """ Determine whether this transport connecting according to connectionInfo is to a node on the current machine; results are cached. According to http://redmine.named-data.net/projects/nfd/wiki/ScopeControl#local-face, TCP transports with a loopback address are local. If connectionInfo contains a host name, this will do a blocking DNS lookup; otherwise this will parse the IP address and examine the first octet to determine if it is a loopback address (e.g. the first IPv4 octet is 127 or IPv6 is "::1"). :param TcpTransport.ConnectionInfo connectionInfo: A TcpTransport.ConnectionInfo with the host to check. :return: True if the host is local, False if not. :rtype bool: """ if (self._connectionInfo == None or self._connectionInfo.getHost() != connectionInfo.getHost()): # Cache the result in _isLocal and save _connectionInfo for next time. self._isLocal = self.getIsLocal(connectionInfo.getHost()) self._connectionInfo = connectionInfo return self._isLocal def connect(self, connectionInfo, elementListener, onConnected): """ Connect according to the info in connectionInfo, and use elementListener. :param TcpTransport.ConnectionInfo connectionInfo: A TcpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement :param onConnected: This calls onConnected() when the connection is established. :type onConnected: function object """ self.close() self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.connect( (connectionInfo.getHost(), connectionInfo.getPort())) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) onConnected() # This will be set True if send gets a TypeError. _sendNeedsStr = False def send(self, data): """ Send data to the host. :param data: The buffer of data to send. :type data: An array type accepted by socket.send """ if TcpTransport._sendNeedsStr: # This version of sendall can't use a memoryview, etc., so convert. self._socket.sendall(str(bytearray(data))) else: try: self._socket.sendall(data) except TypeError: # Assume we need to convert to a str. TcpTransport._sendNeedsStr = True self.send(data) def processEvents(self): """ Process any data to receive. For each element received, call elementListener.onReceivedElement. This is non-blocking and will silently time out after a brief period if there is no data to receive. You should repeatedly call this from an event loop. You should normally not call this directly since it is called by Face.processEvents. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ if not self.getIsConnected(): return # Loop until there is no more data in the receive buffer. while True: if not self._socketPoller.isReady(): # There is no data waiting. return nBytesRead = self._socket.recv_into(self._buffer) if nBytesRead <= 0: # Since we checked for data ready, we don't expect this. return # _bufferView is a memoryview, so we can slice efficienty. self._elementReader.onReceivedData(self._bufferView[0:nBytesRead]) def getIsConnected(self): """ Check if the transport is connected. :return: True if connected. :rtype: bool """ if self._socket == None: return False # Assume we are still connected. TODO: Do a test receive? return True def close(self): """ Close the connection. If not connected, this does nothing. """ if self._socketPoller != None: self._socketPoller.close() self._socketPoller = None if self._socket != None: self._socket.close() self._socket = None @staticmethod def getIsLocal(host): """ A static method to determine whether the host is on the current machine. Results are not cached. http://redmine.named-data.net/projects/nfd/wiki/ScopeControl#local-face, TCP transports with a loopback address are local. If connectionInfo contains a host name, this will do a blocking DNS lookup; otherwise this will parse the IP address and examine the first octet to determine if it is a loopback address (e.g. the first IPv4 octet is 127 or IPv6 is "::1"). :param str host: The host to check. :return: True if the host is local, False if not. :rtype bool: """ if host == "": # Special case: For Python, "" means INADDR_ANY which is local. return True # Only look at the first result. family, _, _, _, sockaddr = socket.getaddrinfo( host, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0] if family == socket.AF_INET: # IPv4 address, _ = sockaddr return address.startswith("127.") else: # IPv6 address, _, _, _ = sockaddr return (address == "::1")
class TcpTransport(Transport): """ Create a new TcpTransport in the unconnected state. """ def __init__(self): self._socket = None self._socketPoller = None self._buffer = bytearray(Common.MAX_NDN_PACKET_SIZE) # Create a Blob and take its buf() since this creates a memoryview # which is more efficient for slicing. self._bufferView = Blob(self._buffer, False).buf() self._elementReader = None self._connectionInfo = None self._isLocal = False class ConnectionInfo(Transport.ConnectionInfo): """ Create a new TcpTransport.ConnectionInfo which extends Transport.ConnectionInfo to hold the host and port info for the TCP connection. :param str host: The host for the connection. :param int port: (optional) The port number for the connection. If omitted, use 6363. """ def __init__(self, host, port=6363): self._host = host self._port = port def getHost(self): """ Get the host given to the constructor. :return: The host. :rtype: str """ return self._host def getPort(self): """ Get the port given to the constructor. :return: The port. :rtype: int """ return self._port def isLocal(self, connectionInfo): """ Determine whether this transport connecting according to connectionInfo is to a node on the current machine; results are cached. According to http://redmine.named-data.net/projects/nfd/wiki/ScopeControl#local-face, TCP transports with a loopback address are local. If connectionInfo contains a host name, this will do a blocking DNS lookup; otherwise this will parse the IP address and examine the first octet to determine if it is a loopback address (e.g. the first IPv4 octet is 127 or IPv6 is "::1"). :param TcpTransport.ConnectionInfo connectionInfo: A TcpTransport.ConnectionInfo with the host to check. :return: True if the host is local, False if not. :rtype bool: """ if (self._connectionInfo == None or self._connectionInfo.getHost() != connectionInfo.getHost()): # Cache the result in _isLocal and save _connectionInfo for next time. self._isLocal = self.getIsLocal(connectionInfo.getHost()) self._connectionInfo = connectionInfo return self._isLocal def isAsync(self): """ Override to return false since connect does not need to use the onConnected callback. :return: False :rtype bool: """ return False def connect(self, connectionInfo, elementListener, onConnected): """ Connect according to the info in connectionInfo, and use elementListener. :param TcpTransport.ConnectionInfo connectionInfo: A TcpTransport.ConnectionInfo. :param elementListener: The elementListener must remain valid during the life of this object. :type elementListener: An object with onReceivedElement :param onConnected: This calls onConnected() when the connection is established. :type onConnected: function object """ self.close() self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.connect( (connectionInfo.getHost(), connectionInfo.getPort())) self._socketPoller = SocketPoller(self._socket) self._elementReader = ElementReader(elementListener) if onConnected != None: onConnected() # This will be set True if send gets a TypeError. _sendNeedsStr = False def send(self, data): """ Send data to the host. :param data: The buffer of data to send. :type data: An array type accepted by socket.send """ if TcpTransport._sendNeedsStr: # This version of sendall can't use a memoryview, etc., so convert. self._socket.sendall(str(bytearray(data))) else: try: self._socket.sendall(data) except TypeError: # Assume we need to convert to a str. TcpTransport._sendNeedsStr = True self.send(data) def processEvents(self): """ Process any data to receive. For each element received, call elementListener.onReceivedElement. This is non-blocking and will silently time out after a brief period if there is no data to receive. You should repeatedly call this from an event loop. You should normally not call this directly since it is called by Face.processEvents. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ if not self.getIsConnected(): return # Loop until there is no more data in the receive buffer. while True: if not self._socketPoller.isReady(): # There is no data waiting. return nBytesRead = self._socket.recv_into(self._buffer) if nBytesRead <= 0: # Since we checked for data ready, we don't expect this. return # _bufferView is a memoryview, so we can slice efficienty. self._elementReader.onReceivedData(self._bufferView[0:nBytesRead]) def getIsConnected(self): """ Check if the transport is connected. :return: True if connected. :rtype: bool """ if self._socket == None: return False # Assume we are still connected. TODO: Do a test receive? return True def close(self): """ Close the connection. If not connected, this does nothing. """ if self._socketPoller != None: self._socketPoller.close() self._socketPoller = None if self._socket != None: self._socket.close() self._socket = None @staticmethod def getIsLocal(host): """ A static method to determine whether the host is on the current machine. Results are not cached. http://redmine.named-data.net/projects/nfd/wiki/ScopeControl#local-face, TCP transports with a loopback address are local. If connectionInfo contains a host name, this will do a blocking DNS lookup; otherwise this will parse the IP address and examine the first octet to determine if it is a loopback address (e.g. the first IPv4 octet is 127 or IPv6 is "::1"). :param str host: The host to check. :return: True if the host is local, False if not. :rtype bool: """ if host == "": # Special case: For Python, "" means INADDR_ANY which is local. return True # Only look at the first result. family, _, _, _, sockaddr = socket.getaddrinfo(host, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0] if family == socket.AF_INET: # IPv4 address, _ = sockaddr return address.startswith("127.") else: # IPv6 address, _, _, _ = sockaddr return (address == "::1")