Kamaelia OSCAR interfaceNOTE: These components implement the OSCAR protocol at the lowest level and require a fairly good knowledge of OSCAR to use them. For a high-level interface, see AIMHarness.py.
Explanation of TermsNOTE: A "byte" in the following documentation refers to an ASCII char, an unsigned char in C. OSCAR messages are transmitted in discrete units called FLAPs, which take the following form: ------------------------------------------- |FLAP-header | | message start character (*) -- 1 byte | | channel -- 1 byte | | sequence number -- 2 bytes | | length of following data -- 2 bytes | |-----------------------------------------| | ------------ | ||FLAP payload| | | ------------ | ------------------------------------------- The sequence number is incremented with every FLAP sent. AOL is very strict about in-order sequence numbers and servers may even disconnect a client for not sending the right sequence numbers. The majority of FLAP payloads (everything except new connection notifications, really serious errors, shutdown notifications, and keepalives) are units called SNACs and are transmitted over channel 2. The structure of a SNAC: -------------------------- |SNAC-header | | family -- 2 bytes | | subtype -- 2 bytes | | request ID -- 2 bytes | | flags -- 4 bytes | |------------------------ | -------------- | | | SNAC payload | | | -------------- | -------------------------- All SNAC payloads must follow a prescribed format unique to the particular type of SNAC, but all SNAC headers must follow the format described above. Each different (family, subtype) performs a different function. For example, SNAC (04, 07) (meaning family 0x04, subtype 0x07) carries AIM messages from the server to the client, SNAC (01, 11) reports client idle times to the server, and (04, 06) carries a message from one user to another. Yet another type of OSCAR datatype is a type-length-value (TLV) unit. The structure of a TLV: ------------------------------------------ |TLV-header | | type -- 2 bytes | | length of following data -- 2 bytes | |----------------------------------------| | --------- | | |TLV data | | | --------- | ----------------------------------------- TLVs may appear inside SNACs or just inside FLAPs. How does it work?OSCARProtocol receives messages on its "talk" inbox in (channel, flap body) format and retransmits them to "outbox" as true FLAPs. It receives FLAPs on its "inbox" inbox and retransmits them to its "heard" outbox in the format (channel, flap body). It also keeps track of sequence numbers. OSCARClient returns a Graphline with an OSCARProtocol component's inbox/outbox connected to a TCPClient's outbox/inbox. The Graphline's inbox and outbox are l inked to the OSCARProtocol component's "talk" and "heard" boxes, respectively. Send (channel, flap body) tuples to its inbox and receive (channel, flap body) tuples from the outbox. SNACExchanger provides specialized methods for dealing with SNACs. You must subclass it, as it does not have a main method. Example UsageTo get an MD5 key from the authorization server during login: class LoginHandler(SNACExchanger): def main(self): self.send((CHANNEL_NEWCONNECTION, struct.pack('!i', 1))) while not self.dataReady(): yield 1 reply = self.recv() # server ack of new connection zero = struct.pack('!H', 0) request = TLV(0x01, "kamaelia1") + TLV(0x4b, zero) + TLV(0x5a, zero) self.sendSnac(0x17, 0x06, request) for reply in self.waitSnac(0x17, 0x07): yield 1 md5key = reply[2:] print ("%02x " * len(md5key)) % unpackSingles(md5key) Graphline(osc = OSCARClient('login.oscar.aol.com', 5190), login = LoginHandler(), linkages = {("login", "outbox") : ("osc", "inbox"), ("osc", "outbox") : ("login", "inbox"), } ).run() For a more complete example, see LoginHandler.py Kamaelia.Protocol.AIM.OSCARClient.OSCARClientprefab: OSCARClientOSCARClient(server, port) -> returns an OSCARProtocol component connected to a TCPClient. User input goes into OSCARClient's "inbox" in the form (channel, flap body) and useable output comes out of "outbox" in the same form. Kamaelia.Protocol.AIM.OSCARClient.OSCARProtocolclass OSCARProtocol(Axon.Component.component)OSCARProtocol() -> new OSCARProtocol component. Provides a Kamaelia interface to the lowest level of OSCAR protocol, the FLAP level. For more information on FLAPs, see module level docs. Inboxes
Outboxes
Methods defined hereWarning! You should be using the inbox/outbox interface, not these methods (except construction). This documentation is designed as a roadmap as to their functionalilty for maintainers and new component developers. __init__(self)x.__init__(...) initializes x; see x.__class__.__doc__ for signature checkBoxes(self)checks for data in all our boxes, and if there is data, then call the appropriate function to handle it. handleinbox(self)receives data coming in through the wire, reformats it into a Python-friendly form, and retransmits it to its "heard" outbox. handletalk(self)checks that incoming messages from the "talk" inbox are in a (channel, flap data) tuple. If not, exceptions are raised. If so, OSCARProtocol.sendFLAP is called. main(self)main loop sendFLAP(self, data[, channel])constructs FLAPs and sends them Kamaelia.Protocol.AIM.OSCARClient.SNACExchangerclass SNACExchanger(Axon.Component.component)SNACExchanger() -> component that has methods specialized for sending and receiving FLAPs over Channel 2 (FLAPs whose payloads are SNACs). For a more thorough discussion on SNACs, see module level docs. Methods defined hereWarning! You should be using the inbox/outbox interface, not these methods (except construction). This documentation is designed as a roadmap as to their functionalilty for maintainers and new component developers. __init__(self)x.__init__(...) initializes x; see x.__class__.__doc__ for signature recvSnac(self)receives FLAPs containing SNACs and parses the SNAC data. sendSnac(self, fam, sub, body)constructs a SNAC by calling self.makeSnac and sends it out the "outbox". FIXME: It would be extremely helpful to have a predefined set of SNAC constants or perhaps even classes to pass to this method. For example, self.sendSnac(04, 06, data) is a lot less clear than something like self.sendSnac(MESSAGE_TO_USER, data). waitSnac(self, fam, sub)Yields 1 until a SNAC of the requested family and subtype is received. The last value yielded is the payload of the requested SNAC.
The body of the requested SNAC will be assigned to "result". FeedbackGot a problem with the documentation? Something unclear that could be clearer? Want to help improve it? Constructive criticism is very welcome - especially if you can suggest a better rewording! Please leave you feedback here in reply to the documentation thread in the Kamaelia blog. -- Automatic documentation generator, 05 Jun 2009 at 03:01:38 UTC/GMT |
Kamaelia
is an open source project originated from and guided by BBC
Research. For more information browse the site or get in
contact.
This is an ongoing community based development site. As a result the contents of this page is the opinions of the contributors of the pages involved not the organisations involved. Specificially, this page may contain personal views which are not the views of the BBC. (the site is powered by a wiki engine)
(C) Copyright 2008 Kamaelia Contributors, including the British Broadcasting Corporation, All Rights Reserved.