Code Reference Manual (C) 2001 Oisin Mulvihill & Michael Twomey $Revision 1.2 $ $Date 2002/02/08 162710 $ Introduction This file aims to document all the classes and other code used in the xmlrpcstream module, regardless of whether the end user needs to know about them or not. I'm documenting this for my own use, so I don't forget how the code works ) In general the user only deals with XmlRpcAcceptor, XmlRpcConnector, XmlRpcStream and XmlRpcStreamFactory. XmlRpcAcceptor This class implements the "server side" of the connector-acceptor design pattern for establishing a connection. This class is derived from Acceptor. This class uses a thread to call the provided handler when a new connection has been received. This is used to prevent the Connection Manager from blocking and waiting on us, which would bring the whole comms model to a halt. __init__(port, stream_factory, new_stream_handler) port This is passed to the base class Acceptor, please refer to the Accpetor for further information. stream_factory This is passed to the base class Acceptor, please refer to the Accpetor for further information. new_connection_handler This gets called by newStreamHandlerThread() when it has received a new connection and wants to hand it over. __addStream(stream) Called to add a new stream to the objectBuffer and return preventing Acceptor handleRead(), which called this function, from blocking. If it blocking occured then connection manager would block as well. The connection manager tick() function calls handleRead() and is waiting for it to return. This means all comms would stop which is undesirable. newStreamHandlerThread() removes and finishes handling each object in the buffer. newStreamHandlerThread(data=0) Call the new stream handler to finish dealing with the stream. The data argument is not used and is only present as its required by thread.start_new_thread() XmlRpcConnector This class connects to an acceptor and established a stream connection. __init__(stream_factory) Create the connector with the specified factory. connect(host, port) Call the base call connector's connect. See Connector.connect for further information. XmlRpcConnection This class deal with send and receiving the xml rpc requests and responses. This class implements a simple protocol for doing xmlrpc calls over a persistent socket connection. __init__(socket, parent, xml_rpc_timeout = 60, chunk_limit = 2048, debug=0) socket This is passed to the Connection base class. parent This is an object who provides a callHandler and errorHandler methods. xml_rpc_timeout This is the amount of time in seconds that the awaitResponse() function will wait. chunk_limit This is the amount of data that will be read/sent in one tick by this class. handleIncomingData( incoming_data_buffer) Called by Connection.__handleDataBuffer() to deal with data in the incoming buffer. processXmlRpcData( xml_data, direction) Called to direct the xml_data to the correct function based on the direction parameter. The direction will be Connection.FUNCTION_RESPONSE or Connection.FUNCTION_CALL. handleMethodCallResponse( xml_rpc_data) Called to handle XML-RPC data, which represents a reponse to a command started at this endpoint. handleMethodCall( xml_rpc_data) Called to convert a buffer of XML-RPC data to a function call. This is a procedure call from the remote end point. This function will process it, generate a response and then return it. awaitResponse(self) Called to wait and get the remote end point response. This function checks whether the connection is still alive. It will also timeout if the remote endpoint hasn't reponded in the time specified by self.__xmlRpcTimeOut, which is 30 seconds by default. sendMethodCall( method, params) Call to send XML RPC to the remote end point. handleConnectionError( error) Called to handle socket and other fatal errors preventing continued use. __del__(self) Called to do clean up (close the socket). XmlRpcStream XmlRpcStream is designed for the situation where a persistant connection between client and server is required. XmlRpcStream is therefore not complient with the XML RPC spec. The spec specifically mentions the that transport of the rpc is done using the HTTP protocol. I don't currently support this however I may in future verisons of XmlRpcStream module. This class allows functions to be called similtaneously, on both end points of the connection, without problems. *** IMPORTANT *** The XmlRpcStream is not currently designed to handle multiple threads making rpc request. When an rpc request is made the calling thread is blocked waiting until for a response. When the response is received it is returned. IF multiple threads were to use the class then they would all block wait for a response, this is ok. The problem is that unless each request returns in the same order, the threads making the request will receive the incorrect responses. There is currently no code to sort out who should get what response. It is my intention to add this functionality, however this won't occur until I'm happy that XmlRpcStream is functioning correctly as is. __init__(socket, debug=0) socket This is passed to the XmlRpcConnection base class. errorHandler(error) Called to handle fatal errors (implemented by user). callHandler(method, params) Called to handle the method call (implemented by user). __getattr__(name) Called when the user does XmlRpcStreamInstance.someFunction() This function is the first step to calling the function on the remote end point i.e. the call to out conterpart XmlRpcStream on the server or client side of the connection. Note This function will also be called if the user attempts to call instance variables e.g. XmlRpcStreamInstance.someVariable. I don't currently handle this so the results are unpredictable, please don't do this ;) __repr__() __str__() Called to return a string in the form ' ' % id(self) __ne__(other) Called when a != comparison is done between this instance and something else. __eq__(other) Called when a == comparison is done between this instance and something else. __del__() Called at clean up time. XmlRpcStreamFactory Derive from this class to create and implement the buildStream() method. build(connection) Called to return an instance of XmlRpcStream. ConnectionInit Module Init This class is created as a singleton by the ConnectionInit() method. __init__(debug=0) This method creates an instance of ConnectionManager and starts it off as a thread. There is one optional parameter, the debug flag. If this is set to 1 then some debug print outs will be done to the console. getConnectionManager() This function returns a reference to the ConnectionManager instance maintained by this class. ConnectionInit() This method returns a reference to the Init() instance. The first time its called it creates Init() and then returns the referernce to it. The ConnectionInit() can be safely called multilple times by anyone wishing to get the ConnectionManager() reference. Acceptor The acceptor class is used to listen for socket connections. When a socket connection is received and accepted, the a factory is called to create a Connection instance for the socket. The newly created connection instance is then added to the connection manager before finally being passed to the new connection handler. The acceptor then goes back listening for new connections. The acceptor class is derived from connection. __init__(port, connection_factory, new_connection_handler, listen_backlog = 5, debug=0) This function sets itself up and calls ConnectionInit() to get the connection manager, before finally adding itself to it The connection manager is used to inform the acceptor when new socket connection has been received. When this occurs handleRead() gets called. This function has three required arguments and two optional ones. port This is the TCP port that the acceptor is to listen for new connections on. connection_factory This an object who has a build method. The acceptor will call when this method when it accepts a new socket and needs a Connection instance contructed for the socket it passes in as an argument. new_connection_handler This method is called to deal with a new connection instance. listen_backlog This argument specifies how many socket connects will be queue while the acceptor is busy. Once this limit is reached then all other connections will be refused until the current ones have been dealt with. debug If this is set to 1 then debug text print-outs will be done to the console. handleRead() This function is called when a new socket is waiting to be accepted. This function accepts the socket and then calls the factory build method. The new instance of Connection returned is then added to the connection manager. Connector __init__(connection_factort) This function get the connection manager its to use by calling ConnectionInit() connection_factory This an object who has a build method. The connector will call when this method when it has established a socket connection to a remote location. When the factory returns the new Connection instance it is added to the connection manager before being returned. connect(host, port) This method connects to a remote location and and returns a connection instance when the connection has successfully been established. host This argument is a string containing a hostname or an ip number. port This argument is a string. ConnectionFactory build(socket) This method creates a Connection instance for the socket passed in as an argument. The new instance is then returned. Connection __init__(socket, debug=0) socket This socket must be an establised socket. debug If this is set to 1 the debug print-outs are done to the console. handleRead() This is called by the connection manager when it has determined that data can be receive without blocking. This method reads in the raw data from the socket and adds it to the incomming data buffer. Once this has been done handleIncommingData() is called. handleWrite() This is called by the connection manager when it has determined that data can be sent without blocking. This method read a chunk of data from the out going buffer and attempts to send it. Note The majority of the time is is clear to send without blocking. This means that without some form of control handleWrite() would get called all the time, regardless of whether there is anything to send. To reduce the needless calls to this method the write flag is set when there is data to send. When all data has been sent this flag is cleared. The connection manager only checks our socket for write events if this flag is set, therefore handleWrite() get call more efficiently. handleError() This is called by the connection manager when it has determined that a socket error event has occured. This method simply pass the error on to handleConnectionError(). handleTick() This method gets called by the connection manager when it has completed all other handle events. This function is usefull if you need to do things in between handleRead/Write events. handleIncomingData(incoming_data_buffer) This method is called by handleRead() when there is new data in the incoming data buffer. It is my intention that the connection class be derived from and that the user will overide this function. This function must return a tupple of a (return code, data). The return code can currently be two values, DATA_INCOMPLETE or DATA_OK. (DATA_INCOMPLETE,'') indicates that data should continue to be added to the incoming data as more is expected. (DATA_OK, data_left_over) indicated that some data has been removed and that data_left_over is the buffer minus the removed data. Note if you want to use this classes recv() you don't have to overide this method. By default this function returns (DATA_INCOMPLETE,'') so the incomming buffer will always grow. Warning While there is nothing wrong with using recv() and handleIncomingData() it may not be suitable in your situation so be carefull. handleConnectionError(error) This method is called when a fatal error has occured and the connection cannot continue operation. It is the intention that the connection class be derived from and that the user will overide this function. send(data) This method is called to send data as soon as possible. The data is buffered and then sent when the socket is ready. This method returns the amount of data added to the buffer. recv(amount=0) This method is called to return an amount of data from the incomming buffer. If amount is > 0 the maximum number of bytes to return will be "amount". However if there isn't that amount of data all thats present will be returned. By default if no amount is specified then all of the data present will be returned. This method is provided as an alternative to overiding the handleIncomingData() function. The advantage of using this function is you can call it any time you want. If there is data it will be returned and removed from the incomming buffer. If there is no data then nothing gets returned. The disadvantage of using this function is that you don't get the immediate notification that overiding handleIncomingData() gets when data has been received. Note1 If you want to use this classes recv() you don't have to overide the handleIncommingData() method. If handleIncommingData() is not overriden then, by default, the incomming buffer will grow until recv() is called to remove data. Note2 This method tries to acquire a lock to gain access to the incomming buffer. This means that the caller will block waiting until it gets the lock. Warning While there is nothing wrong with using recv() and handleIncomingData() it may not be suitable in your situation so be carefull. getId() This return the id number that the connection manager has given this connection when it was added. If this connection wasn't added to the connection manager then this value will be zero. setFlags(read=None, write=None, error=None, remove=None) This method is called to set the connection's flags. If any of the flags are left at there default value of None then there current setting is left unchanged. E.g if you want to set the read flag for example but keep any of the other flags unchanged the you would do the following setFlags(read=1) The flags have the following meaning to the connection manager. Read == 1 The connection wants to know when it is clear to receive data without blocking. If the connection manager checks the connection's socket and finds that this is true then handleRead() gets called. Write == 1 The connection wants to know when it is clear to send data without blocking. If the connection manager checks the connection's socket and finds that this is true then handleWrite() gets called. Error == 1 The connection wants to know if a socket exception has occurred. If the connection manager checks the connection's socket and finds that this is true then handleError() gets called. Remove == 1 The connection is to be removed from the connection manager as soon as possible. Note 1 Be carefull about setting these flags. The connection manager uses them to decide whether this connection will be checked for read, write or error events. If all flags are clear, i.e. set to zero, then this class will not receive any more events until at least one of the flags is set. Note 2 The flags are protected by a lock so the caller will block waiting to acquire the lock. getFlags() This method is called to return the status of the flags. Returned is a tupple of flag values. The format is as follows (Read, Write, Error, Remove). Each flag will be 1 if set or 0 if clear. Note The flags are protected by a lock so the caller will block waiting to acquire the lock. getFatalError() This method is called to return the fatal error that has occured. A tupple is returned in the format (error code, error string) isFatalErrorSet() This method is called to return the status of the fatal error flag. If this is set to 1 the the connection is dead. If its 0 then everything is ok for the moment. ) Note The connection manager calls this method to test the connection. If the flag is set then the connection is removed from the connection manager. getSocket() This method is called by the conneciton manager to return the connection's socket. getInformation() This method is called to return a string of information about the network connection. At present this information is extracted from a getpeername() call and put into a string with the format 'host:port' rawReceive(amount) This method is called to do a low level socket receive. rawSend(data) This method is called to do a low level socket send. This function returns the amount of bytes sent. setChunkLimit(chunk_limit) This methoid is called to set the maximum amount of bytes handleRead() and handleWrite() will attempt to read/write per call. getChunkLimit() This method is called to return the current chunk limit. shutdown() This function closes the connection's socket and set the remove flag so the connection manager removes use from it. __del__() Garbage collection time call shutdown. ConnectionManager The connection manager is responsible for check the sockets under its __init__(sleep_interval=10, debug=0) sleep_internal This is the amount of time that poll will sleep waiting for the socket descriptors, of the sockets in its care, to change. add(connection) This is called to add a new connection to be managed by the connection manager. If the connection is already present then the KeyError exception will be raised. remove(connection) Called to remove a connection from the connection manager. When the connection has been removed, its shutdown is called. If the connection was not found then the KeyError exception will be raised. poll() This "function" is assigned by the __init__() once it has determined which poll funtion to used based on the platform that python returns pollUsingSelect() Poll on Win32 systems (and system that on provide select). pollUsingPoll() Poll on Linux (and most posix systems). tick() Called to do one pass through its interval list calling each member's tick method. Each connection, stored in the list, will have its isFatalErrorSet() method called before its tick() is called. If this returns 1 (true) then the connection is removed from the list and isn't dealt with again. run() Called to continually call tick() in a non busy waiting fashion. start() Start run() as a thread. stop() Cause run() to return as soon as possible. If run() is running as a thread then this will cause the thread to exit closing normally. shutdown() Called to close all connections in the connection manager's care. __del__() Called at garbage collection time to try and shutdown() any connections if this hasn't been done already. UdpBroadcaster This class is used to broadcast some information to all machines on a LAN. The broadcast is by default every ten seconds or so however this can be changed by the user. The broadcaster can also send to a range of ports specified in the port_list provided to it. The UdpReceiver class is designed to receive broadcasts from this class __init__(broadcast_period=10, broadcast_address=BROADCAST_ADDRESS) Store the broadcast_period and broadcast_address. __broadcaster(information, port_list) This thread broadcasts the "information" to a list of port numbers in the LAN. start(information, port_list) Start the broadcasting thread using the information and port_list. This function will return if the thread is already running. stop() Stop the broadcasting thread if its running. __del__() Set the exit flag to stop the broadcaster thread if its running. UdpReceiver This class is used to receive a broadcast from the UdpBroadcaster class. __init__(receive_block_size=1024) receive(port) This opens a udp port, waits to receive up to self.receiveBlockSize bytes. Then returns the data and address of who we received from and closes the open udp port. DataHeader This class manages a "header" of data being sent on a tcp stream socket connection. This class will create a header on data to be sent. It can also be used to extract a header information or remove a header. __init__(data) Store the data to be worked on. setData(data) Called to set the data that will be worked on. getData() Called to return the data. addHeader(direction) Called to add a header to the data using the direction provided. Example output I 18 This is some data. The 'I' indicates the direction, this mean whatever the user wants it to mean. 18 Means the length of the data string 'This is some data.' getHeaderInfo() Called to return the size of the data (excluding the header part of the data) stripHeader() Called to remove the header attached to the data. Note if there is no header present, there is no way of detecting it! What will happen is the first two words of the string will be removed. LockableDictionary A dictionary with locking. 'nuff said Uses threading.Lock to make itself more thread safe. This dictionary is intended for use when multiple append/del/get actions will be done by various threads. __init__() Sets up the base class dictionary and the threading lock. __setitem__(key, value) Called when a "self[key]" = value is done. __getitem__(key) Called when a "value = self[key]" is done. __delitem__(key) Called when a "del self[key]" is done. __len__() Called when to return the current length of the dictionary. Note: this is the size as of when the lock was aquired and then released, after getting the length of the base class dictionary. It may have change so this value should only be used as a guide. keys() Called when to return the current keys of the dictionary. values() Called when to return the current values of the dictionary. has_key(key) Called to check if a key is present in the dictionary.