Loading Rakefile +95 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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. src/lib/KineticConnection.c +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading src/lib/KineticLogger.c +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ #include <string.h> static char LogFile[256] = ""; bool LogToStdErr = false; bool LogToStdErr = true; void KineticLogger_Init(const char* log_file) { Loading src/lib/KineticSocket.c +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
Rakefile +95 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 }
src/lib/KineticConnection.c +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading
src/lib/KineticLogger.c +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ #include <string.h> static char LogFile[256] = ""; bool LogToStdErr = false; bool LogToStdErr = true; void KineticLogger_Init(const char* log_file) { Loading
src/lib/KineticSocket.c +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"); } } }