Commit 57cbfa10 authored by Greg Williams's avatar Greg Williams
Browse files

Added socket connections and simple Ruby Kinetic test server for integration...

Added socket connections and simple Ruby Kinetic test server for integration testing with networking layer
parent 2e2afcf9
Loading
Loading
Loading
Loading
+95 −3
Original line number Diff line number Diff line
@@ -4,7 +4,10 @@ TEAMCITY_BUILD = !ENV['TEAMCITY_PROJECT_NAME'].nil?
load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling/rakefile.rb"

def report(message='')
  $stderr.flush
  $stdout.flush
  puts message
  $stderr.flush
  $stdout.flush
end

@@ -67,7 +70,81 @@ task :cppcheck do
  execute_command "cppcheck ./src ./build/temp/proto", "Analyzing code w/CppCheck"
end

task :default => ['cppcheck', 'test:all', 'release']
namespace :test_server do

  require "webrick"

  $test_server = nil

  # WEBrick is a Ruby library that makes it easy to build an HTTP server with Ruby.
  # It comes with most installations of Ruby by default (it’s part of the standard library),
  # so you can usually create a basic web/HTTP server with only several lines of code.
  #
  # The following code creates a generic WEBrick server on the local machine on port 1234
  class KineticServlet < WEBrick::HTTPServlet::AbstractServlet
    def do_GET (request, response)
      # a = request.query["a"]
      response.status = 200
      response.content_type = "text/plain"
      response.body = "Kinetic Fake Test Server"

      case request.path
      when "/admin"
        response.body += " - admin mode"
      when "/config"
        response.body += " - config mode"
      else
        response.body += " - normal mode"
      end
    end
  end

  class KineticTestServer

    def initialize(port=8213)
      @server = WEBrick::HTTPServer.new(:Port => port)
      @server.mount "/", KineticServlet
      trap("INT") do
        report "INT triggered Kintic Test Server shutdown"
        shutdown
      end
      @abort = false
      @worker = Thread.new do
        @server.start
        while !@abort do
          puts 'X'
        end
      end
    end

    def shutdown
      report_banner "Kinetic Test Server shutting down..."
      @abort = true
      @worker.join(2)
      @server.shutdown
      sleep(0.2)
      report "Kinetic Test Server shutdown complete"
    end

  end

  task :start do
    $test_server ||= KineticTestServer.new
  end

  task :shutdown do
    $test_server.shutdown unless $test_server.nil?
    $test_server = nil
  end

end

task :default => [
  'test_server:start',
  'test:all',
  'test_server:shutdown',
  'release'
]

desc "Run client test utility"
task :run do
@@ -75,7 +152,22 @@ task :run do
end

desc "Build all and run test utility"
task :all => ['default', 'run']
task :all => [
  'cppcheck',
  'default',
  'run'
]

desc "Run full CI build"
task :ci => ['clobber', 'all']
task :ci => [
  'clobber',
  'all'
]


# This block of code will be run prior to Rake instance terminating
END {
  # Ensure test server is shutdown, so we can terminate cleanly
  $test_server.shutdown unless $test_server.nil?
  $test_server = nil
}

kinetic.log

0 → 100644
+0 −0

Empty file added.

+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ bool KineticConnection_Connect(KineticConnection* connection, const char* host,
    connection->FileDescriptor = -1;
    strcpy(connection->Host, host);

    connection->FileDescriptor = KineticSocket_Connect(connection->Host, connection->Port);
    connection->FileDescriptor = KineticSocket_Connect(connection->Host, connection->Port, blocking);
    connection->Connected = (connection->FileDescriptor >= 0);

    return connection->Connected;
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
#include <string.h>

static char LogFile[256] = "";
bool LogToStdErr = false;
bool LogToStdErr = true;

void KineticLogger_Init(const char* log_file)
{
+137 −87
Original line number Diff line number Diff line
#include "KineticSocket.h"

int KineticSocket_Connect(const char* host, int port)
#include "KineticLogger.h"

#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

int KineticSocket_Connect(const char* host, int port, bool blocking)
{
    return KINETIC_PROTO_STATUS_STATUS_CODE_INVALID_STATUS_CODE;

//     LOG(INFO) << "Connecting to " << host_ << ":" << port_;
    char message[256];
    char port_str[32];
    struct addrinfo* result = NULL;
    struct addrinfo hints;
    struct addrinfo* ai = NULL;
    int socket_fd;
    int res;

//     struct addrinfo hints;
//     memset(&hints, 0, sizeof(struct addrinfo));
    sprintf(message, "Connecting to %s:%d", host, port);
    LOG(message);

//     // could be inet or inet6
//     hints.ai_family = PF_UNSPEC;
//     hints.ai_socktype = SOCK_STREAM;
//     hints.ai_protocol = IPPROTO_TCP;
//     hints.ai_flags = AI_NUMERICSERV;
    memset(&hints, 0, sizeof(struct addrinfo));

//     struct addrinfo* result;
    // could be inet or inet6
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_NUMERICSERV;

//     string port_str = std::to_string(port_);
    sprintf(port_str, "%d", port);

//     if (int res = getaddrinfo(host_.c_str(), port_str.c_str(), &hints, &result) != 0) {
//         LOG(ERROR) << "Could not resolve host " << host_ << " port " << port_ << ": "
//                 << gai_strerror(res);
//         return false;
//     }
    res = getaddrinfo(host, port_str, &hints, &result);
    if (res != 0)
    {
        LOG("Could not resolve host");
        return -1;
    }

//     struct addrinfo* ai;
//     int socket_fd;
//     for (ai = result; ai != NULL; ai = ai->ai_next) {
//         char host[NI_MAXHOST];
//         char service[NI_MAXSERV];
//         if (int res = getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof(host), service,
//                 sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
//             LOG(ERROR) << "Could not get name info: " << gai_strerror(res);
//             continue;
//         } else {
//             LOG(INFO) << "Trying to connect to " << string(host) << " on " << string(service);
//         }
    for (ai = result; ai != NULL; ai = ai->ai_next)
    {
        char host[NI_MAXHOST];
        char service[NI_MAXSERV];
        int res;

//         socket_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        res = getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof(host), service,
                sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV);
        if (res != 0)
        {
            LOG("Could not get name info");
            continue;
        }
        else
        {
            LOG("Trying to connect to host");
        }

//         if (socket_fd == -1) {
//             LOG(WARNING) << "Could not create socket";
//             continue;
//         }
        socket_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (socket_fd == -1)
        {
            LOG("Could not create socket");
            continue;
        }

//         // os x won't let us set close-on-exec when creating the socket, so set it separately
//         int current_fd_flags = fcntl(socket_fd, F_GETFD);
//         if (current_fd_flags == -1) {
//             PLOG(ERROR) << "Failed to get socket fd flags";
//             close(socket_fd);
//             continue;
//         }
//         if (fcntl(socket_fd, F_SETFD, current_fd_flags | FD_CLOEXEC) == -1) {
//             PLOG(ERROR) << "Failed to set socket close-on-exit";
//             close(socket_fd);
//             continue;
//         }
        // os x won't let us set close-on-exec when creating the socket, so set it separately
        int current_fd_flags = fcntl(socket_fd, F_GETFD);
        if (current_fd_flags == -1)
        {
            LOG("Failed to get socket fd flags");
            close(socket_fd);
            continue;
        }
        if (fcntl(socket_fd, F_SETFD, current_fd_flags | FD_CLOEXEC) == -1)
        {
            LOG("Failed to set socket close-on-exit");
            close(socket_fd);
            continue;
        }

//         // On BSD-like systems we can set SO_NOSIGPIPE on the socket to prevent it from sending a
//         // PIPE signal and bringing down the whole application if the server closes the socket
//         // forcibly
        // On BSD-like systems we can set SO_NOSIGPIPE on the socket to prevent it from sending a
        // PIPE signal and bringing down the whole application if the server closes the socket
        // forcibly
// #ifdef SO_NOSIGPIPE
//         int set = 1;
//         int setsockopt_result = setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set));
//         // Allow ENOTSOCK because it allows tests to use pipes instead of real sockets
//         if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK) {
//             PLOG(ERROR) << "Failed to set SO_NOSIGPIPE on socket";
//         if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK)
//         {
//             LOG("Failed to set SO_NOSIGPIPE on socket");
//             close(socket_fd);
//             continue;
//         }
// #endif

//         if (connect(socket_fd, ai->ai_addr, ai->ai_addrlen) == -1) {
//             PLOG(WARNING) << "Unable to connect";
//             close(socket_fd);
//             continue;
//         }
        if (connect(socket_fd, ai->ai_addr, ai->ai_addrlen) == -1)
        {
            LOG("Unable to connect");
            close(socket_fd);
            continue;
        }
        else
        {
            LOG("Connected to host!");
        }

//         if (nonblocking_ && fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0) {
//             PLOG(ERROR) << "Failed to set socket nonblocking";
//             close(socket_fd);
//             continue;
//         }
        if (!blocking && fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0)
        {
            LOG("Failed to set socket nonblocking");
            close(socket_fd);
            continue;
        }

//         break;
//     }
        break;
    }

//     freeaddrinfo(result);
    freeaddrinfo(result);

//     if (ai == NULL) {
//         // we went through all addresses without finding one we could bind to
//         LOG(ERROR) << "Could not connect to " << host_ << " on port " << port_;
//         return false;
//     }
    if (ai == NULL)
    {
        // we went through all addresses without finding one we could bind to
        sprintf(message, "Could not connect to %s:%d", host, port);
        LOG(message);
        return -1;
    }

//     fd_ = socket_fd;
//     return true;
    return socket_fd;
}

void KineticSocket_Close(int socket_descriptor)
{
    char message[64];
    if (socket_descriptor == -1)
    {
        LOG("Not connected so no cleanup needed");
    }
    else
    {
        sprintf(message, "Closing socket with fd=%d", socket_descriptor);
        LOG(message);
        if (close(socket_descriptor))
        {
            LOG("Error closing socket file descriptor");
        }
    }
}
Loading