Dev:Abstract Connection Layer

From AMSN
Jump to: navigation, search

aMSN Internals Overview: The Abstract Connection Layer

What is this, and what's this for?

Before AMSN 0.83, we added support for many proxy types (http proxy, SSL proxy, socks5...). But after the October 15th protocol change, the authentication procedure changed. All proxies stopped working. We fixed some of them, but some others won't work (SSL or socks5) and the code is a total mess.

That's why we decided we should do some cleaning and abstraction on this.

The idea is simple: The protocol should be able to connect, using the same code, independent from the connection. That's is, the protocol layer doesn't need to know if we're using a direct connection, http connection, or a proxy.

How is it done?

Ok, so the protocol layer needs to do the following task, connection independent:

  • Connect to a remote Notification/Switchboard server.
  • Write (send a message/command) to a remote server
  • Be notified when a new message/command arrives from the remote server
  • Close the connection to a remote server
  • Do the new authentication system, connecting to a web server using SSL, with a challenge given by the notification server, and the user name and password, to get a ticket that will authenticate the user against the notification server.

So, when the protocol layer needs to write, it will call a ~np~::$wrapper::write~/np~ procedure to write, a ~np~::$wrapper::connect~/np~ procedure to connect, and so on... Just by settingthe $wrapper variable, a different connection layer will be used. It's up to the conection layer to implement these procedures.

Right now, we detect the connection type (according to the configuration), in procedure cmsn_socket, in protocol.tcl. There, we store the wrapper in the SB structure, with:

sb set $sb_name connection_handler $wrapper

The first available wrappers are:

  • DirectConnection (you can find it in protocol.tcl)
  • HTTPConnection (you can find it in proxy.tcl)

In procedure WriteSBRaw, we use:


~np~set command [list [sb get $sb_name connection_handler] $sb_name $data]~/np~ eval $command

instead of writing the data directly into the socket.

Implementing a new connection wrapper

The connection wrapper must implement some common public procedures, with a defined syntax.

A connection wrapper must implement the following procedures inside a namespace (see DirectConnection namespace in protocol.tcl as an example):

__===proc write { sbn data }===__

Will write the given __data__ to the connection related to __sbn__. __Return:__ -1 if an error happens, 0 if ok.

__===proc finish { sbn }===__

Finishes the connection related to __sbn__ __Return:__ -1 if an error happens, 0 if ok.

__===proc connect { sbn }===__

Connects the given __sbn__. The server or address it will connect to are not passed as parameters, but as a __server__ field of the SB structure. This field must be a list of server,port. Example: ~np~sb set $sbn server [list messenger.hotmail.com 1863]~/np~ ~np~::$wrapper::connect $sbn~/np~

__Return:__ -1 if an error happens, 0 if ok.

__===Receiving from the server===___

Before calling the __connect__ procedure of the connection wrapper, three fields on the SB structure must be set:

  • __command_handler__: The command handler is the command that will be called when a command message is received from the server. By default, it's set to __~np~::MSN::receivedCommand $sbn~/np~__
  • __payload_handler__: This field must be set to the command that will be called when a payload message is received from the server. By default, it's set to __~np~::MSN::receivedPayload $sbn~/np~__
  • __error_handler__: This must be set to a command that will be called if an error happens while reading from the server. By default, it's set to __~np~::MSN::CloseSB $sbn~/np~__

When a command message is received from the server (a single line command), the connection wrapper will extract it (for example, the HTTP proxy wrapper will process and remove headers and similar), and then will call the __command_handler__ command, appending the message data as parameter:

~np~set command [sb get $sbn command_handler]~/np~ lappend command $data eval $command

The command_handler procedure has two parameters:

proc receivedCommand { sbn command }

But the first parameter is automatically set when the command_handler field is set, in procedure cmsn_connect.

If a payload message is received (a message composed by a one line command finished with a __content size__ number, a new line, and a stream of bytes of the given size), the __payload_handler__ procedure must be called, appending two arguments. The first one is the message command (first line), and second argument is the payload content:

~np~set command [sb get $sbn command_handler]~/np~ lappend command $command_data lappend command $payload_data eval $command

If an error happens while reading, the read handler must call the error handler defined in the __error_handler__ field of the SB structure. Right now, this handler is always set to CloseSB procedure, which will show an error, and call the __finish__ procedure of the connection wrapper.

For implementation examples, take a look at __~np~::DirectConnection~/np~__ namespace, and __~np~::HTTPConnection~/np~__.

Personal tools