Socket Server code - refactoring

| 2 Comments
After spending some time cleaning up and refactoring away the need to derive from concrete classes in the Win32 and IO libraries that make up The Server Framework, I finally reached the Socket library and applied the same transformations to the interfaces there. This is actually where I hoped to get most value from taking classes that required you to override virtual methods in a derived class and replacing them with explicit virtual callback interfaces that you need to implement. The main gain I was hoping for was that the result would be easier to document, as it is I got that and lots more; the code structure is just much better this way.

The resulting interface which is the main area of interest for users of the Socket Tools library (assuming they're writing a server) is now this:

class IStreamSocketServerCallback 
{
   public :

      virtual void OnStartAcceptingConnections();
  
      virtual void OnStopAcceptingConnections();
      
      virtual void OnShutdownInitiated();
      
      virtual void OnShutdownComplete();
  
      virtual void OnConnectionEstablished(
         IStreamSocket &socket,
         const IAddress &address);
  
      virtual void OnAcceptError(
         const DWORD lastError);
  
      virtual void OnMaximumConnections();
  
      virtual SOCKET CreateListeningSocket(
         SOCKET socket,
         const IAddress &address,
         const size_t listenBacklog);
  
      virtual void OnOutgoingConnectionEstablished(
         IStreamSocket &socket,
         const void *pServerData);
  
      virtual void OnOutgoingConnectionEstablished(
         IStreamSocket &socket,
         const IAddress &address,
         const void *pUserData);
  
      virtual void OnOutgoingConnectionFailed(
         IStreamSocket &socket,
         const IAddress &address,
         const void *pUserData,
         DWORD lastError);
  
      virtual void OnSocketReleased(
         JetByteTools::Win32::IIndexedOpaqueUserData &userData);
  
      /* filtering on a separate interface? */
  
      virtual bool FilterReadRequest(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer *pBuffer);
  
      virtual bool FilterReadCompleted(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer);
  
      virtual bool FilterWriteRequest(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer);
  
      virtual bool FilterWriteCompleted(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer);
  
      virtual void ReadCompleted(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer);
  
      virtual void WriteCompleted(
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer);
  
      virtual void OnError(
         IStreamSocket &socket,
         const JetByteTools::Win32::_tstring &message);
  
      virtual bool OnConnectionClosing(
         IStreamSocket &socket);

      virtual void OnConnectionClientClose(
          IStreamSocket &socket);
  
      virtual void OnConnectionReset(
          IStreamSocket &socket,
          DWORD lastError);
        
      virtual void OnConnectionClosed(
         IStreamSocket &socket);
  
      virtual void OnConnectionError(
         ConnectionErrorSource source,
         IStreamSocket &socket,
         JetByteTools::IO::IBuffer &buffer,
         DWORD lastError);
  
      virtual bool FilterSocketShutdown(
         IStreamSocket &socket,
         ShutdownHow how);
  
      virtual bool FilterSocketClose(
         IStreamSocket &socket);
  
      virtual void OnError(
         const JetByteTools::Win32::_tstring &message);
};

Which, whilst a lot, is at least all in one place and doesn't include any things that the user doesn't need to worry about... And it's easy to provide an object that has a default implementation (which generally does nothing) for 99% of these virtual functions.

The design of the code which calls these methods is cleaner too, it's obvious at the call site that the method being called is a callback method to alert the 'business logic layer' of something. The callback interface itself is actually derived from several other interfaces which various parts of the internals of the library can use...

Now, to finish the docs...

2 Comments

With your current API, it seems trivial to create Managed C++
implementation of IStreamSocketServerCallback base class...

This brings the question I posted earlier: how did the testing of CLR hosting go?
Would that approach perform better?

I'm still deep in the changes needed for the new interface... The code is in, but I'm refactoring the framework some more and then adjusting all the example servers and updating all the tests... So, I haven't had much time to play with the CLR hosting server recently.

Leave a comment