OnSocketReleased() weirdness

| 4 Comments

I ran into an unexpected issue with OnSocketReleased() yesterday whilst writing a connection filter for a client. OnSocketReleased() is a callback method in The Server Framework that allows you to 'do stuff' at the last possible moment of a connection's lifetime. It's guaranteed to be the last callback ever called for a connection and it's guaranteed not to be called until all references to a connection have been released; so you can't get caught out by other threads still processing other last minute connection shutdown events. Since, by the time OnSocketReleased() is called the connection is dead, you only get passed a very reduced interface, in fact you get the socket's IIndexedOpaqueUserData interface. This allows you to clean up any user data that you added to the socket which is pretty much the reason for this callback's existence... The issue that bit me yesterday is that I was using the address of the IIndexedOpaqueUserData reference that I was passed as a key into a map that had initially been keyed with the address of the socket that the user data was part of, cast to a IIndexedOpaqueUserData pointer. Now, usually this would work fine, but the socket actually inherits from IIndexedOpaqueUserData twice due to a dodgy design decision around the socket allocators (see the inheritance diagram for IPoolableStreamSocket here. This all leads to the fact that you can't use the address of the user data object that you're supplied in OnSocketReleased() for anything useful... I may fix the design in a later release, in the meantime I'll update the documentation...

The solution to my problem was to store a unique connection identifier in user data in the socket, index the map from that and then access it legitimately in OnSocketReleased(). The filter (which automatically reinstates outbound connections if they are closed) is now working, but I must admit that the problem took me a while to work out, with lots of scribbling down of address values and scratching of heads.

4 Comments

"...with lots of scribbling down of address values and scratching of heads."

How many heads do you have?

Actually don't answer that one...

I admit, I was getting strange looks from the random people in the street when I popped out and scratched one of them on the head ;)

Smart idea...
It never occured to me to use filters for this purpose. I had to override connection manager instead to provide the same functionality.

The filtering idea works well and they compose nicely which is good for putting together servers quickly. The current server has the connection maintaining filter and a read timeout filter installed. The one thing I'm a little concerned about is overall performance. It's not a problem with the servers that I've been using the filters on, but I'm concerned that with a lot of filters installed there's the cost of walking the filter chain for each filtered operation for every connection. I need to do some profiling but I may switch to having a filter chain per operation in a future release and have each filter indicate which operations that it filters when it's installed...

Leave a comment