spoon.transports.SpoonTransport

Package spoon :: Package transports :: Module SpoonTransport |
[hide private]
[frames] | no frames]

# Source Code for Module spoon.transports.SpoonTransport

      1  #
      2  # Copyright (C) 2006, Matt Sullivan <matts@zarrf.com>
      3  #
      4  # Permission is hereby granted, free of charge, to any person obtaining
      5  # a copy of this software and associated documentation files (the
      6  # "Software"), to deal in the Software without restriction, including
      7  # without limitation the rights to use, copy, modify, merge, publish,
      8  # distribute, sublicense, and/or sell copies of the Software, and to
      9  # permit persons to whom the Software is furnished to do so, subject to
     10  # the following conditions:
     11  #
     12  # The above copyright notice and this permission notice shall be included
     13  # in all copies or substantial portions of the Software.
     14  #
     15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     16  # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18  # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     19  # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     20  # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     21  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  #
     23
     24  from spoon import SpoonStream
     25  from threading import Semaphore, Thread
     26  from transports import TransportException, TransportHub, LMTYPE_NETWORK, LMTYPE_NETWORK_PROTO, LinkMessage
     27  import StringIO
     28
     29 -class SpoonTransport(object):
     30      """
     31      The spoon transport base class.  This will probably mostly be responsible for handling locking on
     32      the transport.  It also takes care of removing itself from the transport hub if it is made inactive.
     33
     34      Any reads or writes on the socket should be performed with the SpoonTransport, or otherwise synchronized
     35      once this is created.
     36      @ivar sock: The raw socket or file object that the transport is bound to
     37      @ivar spoon: The SpoonStream wrapper around the socket.
     38      @ivar active: Indicates if the transport is currently active.
     39
     40      """
     41 -    def __init__(self, t, network=None):
     42          """
     43          Creates a spoon transport link out of an existing socket and joins it to a network.  This network
     44          is either a mesh network or a point to point network (just a direct connection.)
     45          @param t: Some sort of a socket or file like object.
     46          @param network: An instance of a mesh network or a point to point network that the transport will be joined to.
     47          """
     48          self.sock = t
     49          self.spoon = SpoonStream(self.sock)
     50          self.active = property(fget=self.__get_active, fset=self.__set_active,\
     51                                 doc="""Will be True as long as the transport is active, will be false if it is inactive.
     52  Transports are made inactive if any exceptions are encountered.""")
     53          if network:
     54              self.mtypes = {LMTYPE_NETWORK:network, LMTYPE_NETWORK_PROTO:network}
     55          else:
     56              self.mtypes = dict()
     57          self.nodeId = None
     58          self.thread = None
     59          self.__active = False
     60          self.__wlock = Semaphore()
     61          self.__rlock = Semaphore()
     62
     63 -    def __repr__(self):
     64          return "SpoonTransport(%s, %s)"%(repr(self.sock), repr(self.mtypes[LMTYPE_NETWORK]))
     65
     66 -    def write(self, obj):
     67          if not self.active:
     68              raise TransportException("SpoonTransport %s not active."%(repr(self)))
     69          self.__wlock.acquire()
     70          try:
     71              try:
     72                  self.spoon.write(obj)
     73              except Exception, ex:
     74                  self.active = False
     75                  raise ex
     76          finally:
     77              self.__wlock.release()
     78
     79 -    def read(self):
     80          if not self.active:
     81              raise TransportException("SpoonTransport %s not active."%(repr(self)))
     82          self.__rlock.acquire()
     83          try:
     84              try:
     85                  return self.spoon.read()
     86              except Exception, ex:
     87                  self.active = False
     88
     89                  raise ex
     90          finally:
     91              self.__rlock.release()
     92
     93 -    def fileno(self):
     94          """
     95          Returns the fileno for use in a select or poll call if one exists for the socket or file wrapped by this SpoonTransport.
     96          If the socket or file does not have a fileno method, None will be returned.  For proper behavior with paramiko, fileno
     97          on the socket isn't called any time before fileno is called on the SpoonTransport.
     98          """
     99          if hasattr(self.sock, "fileno"):
    100              return self.sock.fileno()
    101          else:
    102              return None
    103
    104 -    def close(self):
    105          TransportHub.removeTransport(self)
    106          self.sock.close()
    107
    108 -    def start(self):
    109          """
    110          Starts the spoon protocol on the socket.  Must be called before writing/reading with the SpoonTransport object.
    111          Will cause the Transport to be registered with TransportHub.
    112          """
    113          TransportHub.addTransport(self)
    114          self.__active = True
    115          self.thread = SpoonTransportThread(self)
    116          self.thread.start()
    117
    118 -    def getAuthedNodeId(self):
    119          """
    120          override this if your class does any pre authentication.
    121          """
    122          return None
    123
    124 -    def __get_active(self):
    125          return self.__active
    126
    127 -    def __set_active(self, newval):
    128          if (newval == False) and (self.__active):
    129              self.__active = newval
    130              TransportHub.removeTransport(self)
    131          # Do nothing if trying to do anything else
    132
    133 -    def getNetwork(self):
    134          return self.mtypes.get(LMTYPE_NETWORK, None)
    135
    136 -class SpoonTransportThread(Thread):
    137 -    def __init__(self, t):
    138          self.sock = t
    139          Thread.__init__(self, name="SpoonTransportThread for "+repr(t))
    140
    141 -    def run(self):
    142          while self.sock.active:
    143              obj = None
    144              try:
    145                  obj = self.sock.read()
    146              except Exception, ex:
    147                  TransportHub._log.error("Got exception '%s' while reading from socket '%s'"%(repr(ex), repr(self.sock)))
    148                  continue
    149
    150              if not isinstance(obj, LinkMessage):
    151                  TransportHub._log.warn("Decoded a message from %s that wasn't a LinkMessage, something's screwy here."%(repr(self.sock)))
    152                  return
    153
    154              if not self.sock.mtypes.has_key(obj.msgtype):
    155                  TransportHub._log.error("Unknown link message type receieved from '%s'"%(repr(self.sock)))
    156                  continue
    157              try:
    158                  self.sock.mtypes[obj.msgtype].handleLinkMessage(self.sock, obj)
    159              except Exception, ex:
    160                  TransportHub._log.error("Uncaught exception in link message handler for type %d on transport '%s'"%(obj.msgtype, self.sock), ex)
    161                  continue
    162          TransportHub._log.debug("SpoonTransportThread stopping")
    163