OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-cogserver / opencog / network / ConsoleSocket.h

94 lines · c ref:
/*
 * opencog/network/ConsoleSocket.h
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Written by Andre Senna <senna@vettalabs.com>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#ifndef _OPENCOG_CONSOLE_SOCKET_H
#define _OPENCOG_CONSOLE_SOCKET_H

#include <condition_variable>
#include <mutex>
#include <string>

#include <opencog/network/ServerSocket.h>
#include <opencog/network/GenericShell.h>

namespace opencog
{
/** \addtogroup grp_server
 *  @{
 */

/**
 * This class implements the ServerSocket that handles the primary
 * interface of the server: the plain text command line.
 *
 * There may be multiple instances of ConsoleSocket to support multiple
 * simultaneous clients. This is done by creating a separate thread and
 * dispatching a client socket for each client that connects to the
 * server socket.
 */
class ConsoleSocket : public ServerSocket
{
private:
    // We need the use-count and the condition variables to avoid races
    // between asynchronous socket closures and unsent replies. So, for
    // example, the user may send a command, but then close the socket
    // before the reply is sent.  The asio code notices the
    // closed socket, and ServerSocket::handle_connection() exits it's
    // loop, and then tries to destruct this class and exit the thread
    // that has been handling the socket i/o. We have to hold off this
    // destruction, until all of the users of this class have completed
    // their work. We accomplish this with a use-count: each in-flight
    // request increments the use-count, and then decrements it when done.
    // The destructor can run only when the use-count has dropped to zero.
    //
    // Sockets with a shell on them will typically have a use-count of
    // zero already; these use a different method of holding off the dtor.
    // Basically, the shell dtor has to run first, before the
    // ServerSocket::handle_connection() invokes this dtor.
    volatile unsigned int _use_count;
    std::mutex _in_use_mtx;
    std::condition_variable _in_use_cv;

protected:
    GenericShell* _shell;

    /** Status printing */
    virtual std::string connection_header(void);
    virtual std::string connection_stats(void);
public:
    /**
     * Ctor. Defines the socket's mime-type as 'text/plain' and then
     * configures the Socket to use line protocol.
     */
    ConsoleSocket(SocketManager*);
    virtual ~ConsoleSocket();

    void get() { std::unique_lock<std::mutex> lck(_in_use_mtx); _use_count++; }
    void put() { std::unique_lock<std::mutex> lck(_in_use_mtx); _use_count--; _in_use_cv.notify_all(); }

    /**
     * SetShell: Declare an alternate shell, that will perform all
     * command line processing.
     */
    void SetShell(GenericShell *);
    GenericShell * getShell(void) { return _shell; }

    /** Predicate: is there a shell, and is it busy? */
    bool busyShell(void);

    /**
     * Assorted debugging utilities.
     */
    unsigned int get_use_count() const { return _use_count; }
}; // class

/** @}*/
}  // namespace

#endif // _OPENCOG_CONSOLE_SOCKET_H