/* ---- This file is part of SECONDO. Copyright (C) 2014, University in Hagen, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO 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 General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[ue] [\"u] //[ae] [\"a] //[_] [\_] //[TOC] [\tableofcontents] [1] Loadgenerator. This program generates CSV data and send the data through a network socket. A sample line looks like: gEpYm0eUDk,fAgVgUHWPo,bClSVK17HX,ixjXTTW7yh,qdsU8WzP1O, CcZw52F47W,bpRKKsoq0m,YoNOJWsGtt,c5U92XBHbG,kA5CUO4GE2 You can specify the number of lines to be send and parameter like delay, number of columns or the size of a column. */ /* 1.0 Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "timer.h" /* 1.1 Defines */ #define EOT "\004" #define ACK "\006" #define CMDLINE_HOST 1<<0 #define CMDLINE_PORT 1<<1 #define CMDLINE_LINES 1<<2 #define CMDLINE_DELAY 1<<3 #define CMDLINE_COLUMNS 1<<4 #define CMDLINE_SIZE 1<<5 #define CMDLINE_ACK 1<<6 using namespace std; /* 1.2 Structs */ struct commandline_args_t { char *hostname; // Hostname int port; // Port to connect to int lines; // Lines to send int delay; // Delay in ms int columns; // Number of columns int sizePerColumn; // Size per column int acknowledgeAfter;// Wait for ack after n lines }; // Allowed chars to send static const char charArray[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijlkmnopqrstuvwxyz" "01"; // Padding to 64 Byte static unsigned int g_seed; //Used to seed the generator. //Code from: https://software.intel.com/en-us/articles/ // fast-random-number-generator-on-the-intel-pentiumr-4-processor/ inline void fast_srand( int seed ) { g_seed = seed; } //fastrand routine returns one integer, similar output value range as C lib. inline int fastrand() { g_seed = (214013*g_seed+2531011); return (g_seed>>16)&0x7FFF; } /* 2.1 Print usage fuction */ void printUsageAndExit(char* progname) { cerr << "Usage: " << progname << " -h -p -l " "-d -c -s -a " << endl; cerr << endl; cerr << "Where is the hostname to connect to" << endl; cerr << " is the port to connect to" << endl; cerr << " is the numer of lines to send" << endl; cerr << " is the pause (in ms) between two lines " << endl; cerr << " is the number of columns to generate" << endl; cerr << " is the size in byte per column" << endl; cerr << " wait fror a ACK from server after n lines" << endl; cerr << endl; cerr << "Example: " << progname << " -h 127.0.0.1 -p 10000 -l 10 -d 4 -c 10 -s 10 -a 10" << endl; exit(-1); } /* 2.2 Fill the send buffer with the specified content */ void fillBuffer(char *buffer, int columns, int sizePerColumn) { size_t pos = 0; for(size_t i = 0; i < columns; i++) { if(i != 0) { *(buffer + pos) = ','; ++pos; } int arrayPos = fastrand() & 0x3F; for(size_t charNum = 0; charNum < sizePerColumn; ++charNum) { // Access to the charArray 64 Byte // 0x3F = 00111111 (Coveres the last 64 Byte) *(buffer + pos) = charArray[arrayPos]; ++pos; } } *(buffer + pos) = '\n'; *(buffer + pos + 1) = '\0'; } /* 2.3 Wait for an ACK char from remote server */ void waitForAck(int socketfd) { char buffer[255]; size_t bytes = read(socketfd, buffer, sizeof(buffer)); /*if(strncmp(buffer,ACK,1) == 0) { cout << "[Info] Got ack"; } else { cout << "[Error] Got something else"; }*/ } /* 2.4 Open the network socket */ bool openSocket(int &socketfd, char* hostname, int port) { struct hostent *server; struct sockaddr_in server_addr; socketfd = socket(AF_INET, SOCK_STREAM, 0); if(socketfd < 0) { cerr << "Error opening socket" << endl; return false; } // Resolve hostname server = gethostbyname(hostname); if(server == NULL) { cerr << "Error resolving hostname: " << hostname << endl; return -1; } // Connect memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = ((struct in_addr *)server->h_addr_list[0])->s_addr; if(connect(socketfd, (struct sockaddr*) &server_addr, sizeof(struct sockaddr)) < 0) { cerr << "Error in connect() " << endl; return false; } return true; } /* 2.5 Parse commandline args amd fill struct commandline\_args */ void parseCommandline(int argc, char* argv[], commandline_args_t &commandline_args) { unsigned int flags = 0; // Default values commandline_args.acknowledgeAfter = -1; commandline_args.delay = 0; int option = 0; while ((option = getopt(argc, argv,"h:p:l:d:c:s:a:")) != -1) { switch (option) { case 'h': commandline_args.hostname = optarg; flags |= CMDLINE_HOST; break; case 'p': commandline_args.port = atoi(optarg); flags |= CMDLINE_PORT; break; case 'l': commandline_args.lines = atoi(optarg); flags |= CMDLINE_LINES; break; case 'd': commandline_args.delay = atoi(optarg); flags |= CMDLINE_DELAY; break; case 'c': commandline_args.columns = atoi(optarg); flags |= CMDLINE_COLUMNS; break; case 's': commandline_args.sizePerColumn = atoi(optarg); flags |= CMDLINE_SIZE; break; case 'a': commandline_args.acknowledgeAfter = atoi(optarg); flags |= CMDLINE_ACK; break; default: printUsageAndExit(argv[0]); } } unsigned int requriedFlags = CMDLINE_HOST | CMDLINE_PORT | CMDLINE_LINES | CMDLINE_COLUMNS | CMDLINE_SIZE ; if((flags & requriedFlags) != requriedFlags) { printUsageAndExit(argv[0]); } } /* 2.6 Write data to the socket */ bool writeData(const int socketfd, const char *data, const size_t len) { int ret = 0; for (int n = 0; n < len; ) { ret = write(socketfd, (char *)data + n, len - n); if (ret < 0) { if (errno == EINTR || errno == EAGAIN) { continue; } break; } else { n += ret; } } // All data was written successfully if(ret > 0) { return true; } return false; } /* 2.7 Main function The function open a socket, generate requested data and close the socket */ int main(int argc, char* argv[]) { // Our output socket int socketfd; // Commandline args commandline_args_t commandline_args; parseCommandline(argc, argv, commandline_args); // Initalize Rand fast_srand (time(NULL)); // Open socket if(! openSocket(socketfd, commandline_args.hostname, commandline_args.port) ) { cerr << "[Error] Unable to open socket" << endl; return EXIT_FAILURE; } // Prepare buffer size_t bufferSize = commandline_args.columns * commandline_args.sizePerColumn + commandline_args.columns + 1; char *buffer = (char*) malloc(bufferSize * sizeof(char)); fillBuffer(buffer, commandline_args.columns, commandline_args.sizePerColumn); cout << "The size of the buffer is: " << bufferSize << " bytes " << endl; cout << "The buffer contains: " << buffer << endl; // Start timer Timer timer; timer.start(); // Calculate progess (i) cout << "Writing: "; int fivePercents = max(((int) ((commandline_args.lines / 100.0) * 5.0)), 1); // Write lines to server for(int i = 0; i < commandline_args.lines; ++i) { fillBuffer(buffer, commandline_args.columns, commandline_args.sizePerColumn); // -1 because we dont want so send the \0 terminal writeData(socketfd, buffer, bufferSize - 1); // Calculate progess (ii) if(i % fivePercents == 0) { cout << "."; cout << flush; } // Wait for ack if(commandline_args.acknowledgeAfter > 0 && ((i + 1) % commandline_args.acknowledgeAfter == 0)) { waitForAck(socketfd); } if(commandline_args.delay != 0) { usleep(commandline_args.delay * 1000); } } cout << endl; cout << "Total execution time (ms): " << timer.getDiff() / 1000 << endl; // Send EOT (End of Transmission) writeData(socketfd, EOT, sizeof(char)); shutdown(socketfd, 2); if(buffer != NULL) { free(buffer); buffer = NULL; } return EXIT_SUCCESS; }