#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/orb/IIOPConnection.py,v $ # Version: @(#)$RCSfile: IIOPConnection.py,v $ $Revision: 1.11 $ # ############################################################################# """ IIOPConnection class. """ # Standard/built-in modules. import socket, struct # Try to import select. # It will fail in Jython. try: import select select_available = 1 except: select_available = 0 # Fnorb modules. import CORBA, Connection, OctetStream, Util class IIOPConnection(Connection.Connection): """ IIOPConnection class. """ def __init__(self, _socket=None): """ Provide an IIOP connection to a remote object! '_socket' is a socket that is *already* connected. """ # If we are given a "here's one I prepared earlier" socket, then we # use that. # if _socket is not None: self.__socket = _socket self.__connected = 1 # The 'TCP_NODELAY' option disables the TCP Nagle algorithm which # prevents the transmission of small packets (like for example # 'CloseConnection' messages). # # fixme: We don't use symbolic constants from the 'socket' module # as they don't appear to be present on all platforms (eg. Linux!). # Is this just an ommision or is there a reason?!? self.__socket.setsockopt(6, # IPPROTO_TCP 1, # TCP_NODELAY 1) # Option on! # Otherwise, we will create a socket when the 'connect' method is # called. else: self.__connected = 0 self.__negotiated_codeset = None return ######################################################################### # Connection interface. ######################################################################### def connect(self, address): """ Connect to the remote object. """ # Create a socket and connect to the remote object. try: self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__socket.connect(address) # Set the socket by default to NON-blocking mode. # Jython sockets have no 'setblocking' method. if hasattr(self.__socket, 'setblocking'): self.__socket.setblocking(0) # Connected! self.__connected = 1 except socket.error: raise CORBA.COMM_FAILURE() # System exception. return def disconnect(self): """ Disconnect from the remote server. """ # Make sure that we are actually connected! if self.__connected: try: # Close the connection. self.__socket.close() except socket.error: pass # Disconnected. self.__connected = 0 return def send(self, data, block=0): """ Send as much of the data as we can. """ try: n = self.__socket.send(data) except socket.error: raise CORBA.COMM_FAILURE(0, CORBA.COMPLETED_MAYBE) return n def recv(self, n): """ Receive at most 'n' bytes of data. """ try: # Block until there is some data present on the socket. # # We do a 'select' instead of a blocking read, because 'select' # can be interrupted by closing the socket. This is useful in # the presence of threads when we need to shut down the read # thread. if select_available: try: (iwtd, owtd, ewtd) = select.select([self.__socket], [], []) # Read the data. data = self.__socket.recv(n) except select.error: raise CORBA.COMM_FAILURE(0, CORBA.COMPLETED_MAYBE) else: # Read the data. data = self.__socket.recv(n) # fixme: The 'AttributeError' is caught because it seems that on # Windows platforms this exception is raised when the socket has been # closed by the peer? except (socket.error, ValueError, AttributeError): raise CORBA.COMM_FAILURE(0, CORBA.COMPLETED_MAYBE) return data def is_connected(self): """ Are we connected to the remote address? """ return self.__connected def blocking(self, blocking): """ Set the connection to blocking (1) or non-blocking (0). """ # Jython sockets have no 'setblocking' method. if hasattr(self.__socket, 'setblocking'): self.__socket.setblocking(blocking) return def handle(self): """ Return my underlying I/O handle. In this case, my I/O handle is the file descriptor of my socket. """ return self.__socket.fileno() def get_tcs_c(self): """Return the negotiated transmission code set for characters.""" if self.__negotiated_codeset is None: return 0 return self.__unpacked_codeset.char_data def get_tcs_w(self): """Return the negotiated transmission code set for wide characters.""" if self.__negotiated_codeset is None: return 0 return self.__unpacked_codeset.wchar_data def set_negotiated_codeset(self, codeset): """Set the flag that the codeset has been sent.""" self.__negotiated_codeset = codeset csc_tc = CORBA.typecode( "IDL:omg.org/CONV_FRAME/CodeSetContext:1.0") encaps = OctetStream.Encapsulation(codeset.context_data) csc = csc_tc._fnorb_unmarshal_value(encaps.cursor()) self.__unpacked_codeset = csc # Set-up the conversion functions. ASCII (0x00010020) # and Latin-1 (0x00010001) are treated as equivalent to # avoid conversions in the common case pcs = CORBA.ORB_init()._fnorb_get_process_codeset() if (csc.char_data == pcs or csc.char_data == 0x00010020 and pcs == 0x00010001 or csc.char_data == 0x00010001 and pcs == 0x00010020): self.encode_char = lambda x:x self.decode_char = lambda x:x else: try: del self.encode_char del self.decode_char except AttributeError: pass self.__pcs = Util.osf2codec[pcs] self.__tcs_c = Util.osf2codec[csc.char_data] self.__wcs = Util.osf2codec[csc.wchar_data] def get_negotiated_codeset(self): return self.__negotiated_codeset def encode_char(self, data): try: return unicode(data, self.__pcs).encode(self.__tcs_c) except UnicodeError: raise CORBA.DATA_CONVERSION def decode_char(self, codeset): try: return unicode(data, self.__tcs_c).encode(self.__pcs) except UnicdeError: raise CORBA.DATA_CONVERSION #############################################################################