<commit_before>/*
 * src/CogServer/SimpleNetworkServer.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * All Rights Reserved
 *
 * Written by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "platform.h"

#include "SimpleNetworkServer.h"
#include "ServerSocket.h"
#include "CommandRequest.h"

#include <exceptions.h>
#include <ListenSocket.h>
#include <SocketHandler.h>

using namespace opencog;

bool SimpleNetworkServer::stopListenerThreadFlag = false;

SimpleNetworkServer::~SimpleNetworkServer()
{
    if (! stopListenerThreadFlag) {
        stopListenerThreadFlag = true;
        pthread_join(socketListenerThread, NULL);
    }
}

SimpleNetworkServer::SimpleNetworkServer(CogServer *cs, int pn)
{
    started = false;
    stopListenerThreadFlag = false;
    portNumber = pn;
    cogServer = cs;
    shell_mode = false;
    prompt = "opencog> ";
}

/**
 * Convert a command line, received over a socket from some client,
 * into a request for the CogServer.
 */
void SimpleNetworkServer::processCommandLine(CallBackInterface *callBack,
                                             const std::string &cmdLine)
{
    std::string command;
    std::queue<std::string> args;

    // Special handling for command escapes
    // Note that "data" will have LF or CRLF because the socket code
    // has already been put into "raw" mode when "data" shows up.
    // However, other things, like "scm", will not have CRLF because
    // the socket code will be in line mode.
    if (cmdLine.substr(0, 5) == "data\n") {
        command = "data";
        args.push(cmdLine.substr(5));
    } else if (cmdLine.substr(0, 6) == "data\r\n") {
        command = "data";
        args.push(cmdLine.substr(6));
    } else if (cmdLine.substr(0, 3) == "scm") {
        command = "scm";
        shell_mode = true;
    } else if (cmdLine.substr(0, 1) == "") {
        command = "scm-exit";
        shell_mode = false;
    } else if (cmdLine.substr(0, 1) == ".") {
        command = "scm-exit";
        shell_mode = false;
    } else if (shell_mode) {
        // In shell mode, do *not* parse the command line!
        command = cmdLine;
    } else {
        // XXX FIXME: this is really the wrong place to do command-line
        // parsing. This needs to be moved to the simple cog server,
        // so that the silly "shell_mode" crap above can be removed.
        parseCommandLine(cmdLine, command, args);
    }

    CommandRequest *request = new CommandRequest(callBack, command, args);
    cogServer->pushRequest(request);
}

std::string SimpleNetworkServer::getCommandPrompt()
{
    return prompt;
}

void SimpleNetworkServer::start()
{
    if (started) {
        throw new RuntimeException(NULL, "Cannot restart SimpleNetworkServer");
    }

    ServerSocket::setMaster(this);

    pthread_attr_init(&socketListenerAttr);
    pthread_attr_setscope(&socketListenerAttr, PTHREAD_SCOPE_PROCESS);
    pthread_attr_setinheritsched(&socketListenerAttr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setdetachstate(&socketListenerAttr, PTHREAD_CREATE_DETACHED);

    pthread_create(&socketListenerThread,
                   &socketListenerAttr,
                   SimpleNetworkServer::portListener,
                   &portNumber);

    started = true;
}


void *SimpleNetworkServer::portListener(void *arg)
{
    int port = *((int*) arg);

    SocketHandler socketHandler;
    ListenSocket<ServerSocket> listenSocket(socketHandler);

    if (listenSocket.Bind(port)) {
        throw new RuntimeException(NULL, "NetworkElement - Cannot bind to port %d.", port);
    }

    socketHandler.Add(&listenSocket);

    socketHandler.Select(0, 200);

    while (!stopListenerThreadFlag) {
        if (socketHandler.GetCount() == 0) {
            throw new RuntimeException(NULL, "NetworkElement - Bind to port %d is broken.", port);
        }
        // poll for 200 millsecs
        socketHandler.Select(0, 200 * 1000);
    }

    return NULL;
}

/**
 * parseCommandLine -- split string into space-separated tokens
 * @line -- input string
 * @command -- output, contains first non-whitespace part of input string
 * @args -- output, queue of space-separated tokens split from the input string.
 *
 * XXX ?? what is the purpose of this?? gnu getopt is an better/more general way to get
 * args from a command line.
 */
void SimpleNetworkServer::parseCommandLine(const std::string &line,
        std::string &command,
        std::queue<std::string> &args)
{
    std::string::size_type pos1, pos2;

    pos1 = line.find(' ', 0);
    if (pos1 == line.npos) {
        command.assign(line);
        return;
    }
    command.assign(line.substr(0, pos1));

    while (pos1 != line.npos) {
        pos2 = line.find(' ', pos1 + 1);
        if (pos2 == line.npos) {
            args.push(line.substr(pos1 + 1));
        } else {
            args.push(line.substr(pos1 + 1, pos2 - pos1 - 1));
        }
        pos1 = pos2;
    }
}
<commit_msg>Fix bug #243680: Print error when server port in use.<commit_after>/*
 * src/CogServer/SimpleNetworkServer.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * All Rights Reserved
 *
 * Written by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "platform.h"

#include "SimpleNetworkServer.h"
#include "ServerSocket.h"
#include "CommandRequest.h"
#include "Logger.h"

#include <exceptions.h>
#include <ListenSocket.h>
#include <SocketHandler.h>

using namespace opencog;

bool SimpleNetworkServer::stopListenerThreadFlag = false;

SimpleNetworkServer::~SimpleNetworkServer()
{
    if (! stopListenerThreadFlag) {
        stopListenerThreadFlag = true;
        pthread_join(socketListenerThread, NULL);
    }
}

SimpleNetworkServer::SimpleNetworkServer(CogServer *cs, int pn)
{
    started = false;
    stopListenerThreadFlag = false;
    portNumber = pn;
    cogServer = cs;
    shell_mode = false;
    prompt = "opencog> ";
}

/**
 * Convert a command line, received over a socket from some client,
 * into a request for the CogServer.
 */
void SimpleNetworkServer::processCommandLine(CallBackInterface *callBack,
                                             const std::string &cmdLine)
{
    std::string command;
    std::queue<std::string> args;

    // Special handling for command escapes
    // Note that "data" will have LF or CRLF because the socket code
    // has already been put into "raw" mode when "data" shows up.
    // However, other things, like "scm", will not have CRLF because
    // the socket code will be in line mode.
    if (cmdLine.substr(0, 5) == "data\n") {
        command = "data";
        args.push(cmdLine.substr(5));
    } else if (cmdLine.substr(0, 6) == "data\r\n") {
        command = "data";
        args.push(cmdLine.substr(6));
    } else if (cmdLine.substr(0, 3) == "scm") {
        command = "scm";
        shell_mode = true;
    } else if (cmdLine.substr(0, 1) == "") {
        command = "scm-exit";
        shell_mode = false;
    } else if (cmdLine.substr(0, 1) == ".") {
        command = "scm-exit";
        shell_mode = false;
    } else if (shell_mode) {
        // In shell mode, do *not* parse the command line!
        command = cmdLine;
    } else {
        // XXX FIXME: this is really the wrong place to do command-line
        // parsing. This needs to be moved to the simple cog server,
        // so that the silly "shell_mode" crap above can be removed.
        parseCommandLine(cmdLine, command, args);
    }

    CommandRequest *request = new CommandRequest(callBack, command, args);
    cogServer->pushRequest(request);
}

std::string SimpleNetworkServer::getCommandPrompt()
{
    return prompt;
}

void SimpleNetworkServer::start()
{
    if (started) {
        throw new RuntimeException(NULL, "Cannot restart SimpleNetworkServer");
    }

    ServerSocket::setMaster(this);

    pthread_attr_init(&socketListenerAttr);
    pthread_attr_setscope(&socketListenerAttr, PTHREAD_SCOPE_PROCESS);
    pthread_attr_setinheritsched(&socketListenerAttr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setdetachstate(&socketListenerAttr, PTHREAD_CREATE_DETACHED);

    pthread_create(&socketListenerThread,
                   &socketListenerAttr,
                   SimpleNetworkServer::portListener,
                   &portNumber);

    started = true;
}


void *SimpleNetworkServer::portListener(void *arg)
{
    int port = *((int*) arg);

    SocketHandler socketHandler;
    ListenSocket<ServerSocket> listenSocket(socketHandler);

    try {
        // we throw an exception ourselves because csockets may
        // be compiled with exceptions disabled
        if (listenSocket.Bind(port)) throw new Exception("bind error");
    } catch (Exception &e) {
        logger().error("Unable to bind to port %d. Aborting.", port);
        std::exit(1);
    }

    socketHandler.Add(&listenSocket);

    socketHandler.Select(0, 200);

    while (!stopListenerThreadFlag) {
        if (socketHandler.GetCount() == 0) {
            throw new RuntimeException(NULL, "NetworkElement - Bind to port %d is broken.", port);
        }
        // poll for 200 millsecs
        socketHandler.Select(0, 200 * 1000);
    }

    return NULL;
}

/**
 * parseCommandLine -- split string into space-separated tokens
 * @line -- input string
 * @command -- output, contains first non-whitespace part of input string
 * @args -- output, queue of space-separated tokens split from the input string.
 *
 * XXX ?? what is the purpose of this?? gnu getopt is an better/more general way to get
 * args from a command line.
 */
void SimpleNetworkServer::parseCommandLine(const std::string &line,
        std::string &command,
        std::queue<std::string> &args)
{
    std::string::size_type pos1, pos2;

    pos1 = line.find(' ', 0);
    if (pos1 == line.npos) {
        command.assign(line);
        return;
    }
    command.assign(line.substr(0, pos1));

    while (pos1 != line.npos) {
        pos2 = line.find(' ', pos1 + 1);
        if (pos2 == line.npos) {
            args.push(line.substr(pos1 + 1));
        } else {
            args.push(line.substr(pos1 + 1, pos2 - pos1 - 1));
        }
        pos1 = pos2;
    }
}

{'fraction_non_alphanumeric': 0.11082070047046524, 'fraction_numerical': 0.012632862868095488, 'mean_word_length': 2.9204234972677594, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 2, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7228587', 'n_tokens_mistral': 3458, 'n_tokens_neox': 3314, 'n_words': 1044}