root/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h
/*
 * Copyright 2012-2013 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Paweł Dziepak, pdziepak@quarnos.org
 */
#ifndef RPCCALLBACKSERVER_H
#define RPCCALLBACKSERVER_H


#include <string.h>
#include <util/AutoLock.h>

#include "Connection.h"


namespace RPC {

class Callback;
class Server;

struct ConnectionEntry {
        Connection*                     fConnection;
        thread_id                       fThread;

        ConnectionEntry*        fNext;
        ConnectionEntry*        fPrev;
};

union CallbackSlot {
        Callback*       fCallback;
        int32           fNext;
};

class CallbackServer {
public:
                                                        CallbackServer(int networkFamily);
                                                        ~CallbackServer();

        static  CallbackServer* Get(Server* server);
        static  void                    ShutdownAll();

                        status_t                RegisterCallback(Callback* callback);
                        status_t                UnregisterCallback(Callback* callback);

        inline  PeerAddress             LocalID();

protected:
                        status_t                StartServer();
                        status_t                StopServer();

                        status_t                NewConnection(Connection* connection);
                        status_t                ReleaseConnection(ConnectionEntry* entry);

        static  status_t                ListenerThreadLauncher(void* object);
                        status_t                ListenerThread();

        static  status_t                ConnectionThreadLauncher(void* object);
                        status_t                ConnectionThread(ConnectionEntry* entry);

        inline  Callback*               GetCallback(int32 id);

private:
        static  mutex                   fServerCreationLock;
        static  CallbackServer* fServers[2];

                        mutex                   fConnectionLock;
                        ConnectionEntry*        fConnectionList;
                        ConnectionListener*     fListener;

                        mutex                   fThreadLock;
                        thread_id               fThread;
                        bool                    fThreadRunning;

                        rw_lock                 fArrayLock;
                        CallbackSlot*   fCallbackArray;
                        uint32                  fArraySize;
                        int32                   fFreeSlot;

                        int                             fNetworkFamily;
};


inline PeerAddress
CallbackServer::LocalID()
{
        PeerAddress address;

        ASSERT(fListener != NULL);

        memset((void*)&address, 0, sizeof(address));
        fListener->GetLocalAddress(&address);
        return address;
}


inline Callback*
CallbackServer::GetCallback(int32 id)
{
        ReadLocker _(fArrayLock);
        if (id >= 0 && static_cast<uint32>(id) < fArraySize)
                return fCallbackArray[id].fCallback;
        return NULL;
}


}               // namespace RPC

#endif  // RPCCALLBACKSERVER_H