.
675 |
--------------------------------------------------------------------------------
/NEWS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fr0stbyte/ruok/7057ea2cb71f1bd48eade1d0290f5d6613d31216/NEWS
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # R U OK
2 |
3 | A program to measures timings of transferring data with URL syntax and helps identify where in the pipeline the problem exists, if at all.
4 |
5 | ## Libraries needed
6 | * curl >= 7.21.0
7 | * libxml2 >= 2.7.8 ( not required )
8 | * cmake >= 2.6
9 |
10 | ## Compilation
11 |
12 | 1. cmake .
13 | 2. make
14 | 3. make install
15 |
16 | ## Parameters
17 |
18 | Allowed options:
19 | -f [ --follow ] Follow redirects
20 | -h [ --help ] Displays this information
21 | -H [ --Header ] arg ( "Host:www.example.com" ) Stackable parameter to pass HTTP headers to the request
22 | -j [ --json ] Verify JSON validity
23 | -m [ --miliseconds ] Display timings in miliseconds ( default seconds )
24 | -n [ --no-header ] Do not display the header
25 | -p [ --period ] arg (=10) Period in seconds
26 | -r [ --rate ] arg (=1) Rate of requests per second
27 | -u [ --url ] arg Url to test
28 | -U [ --user-agent ] arg (=Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1)
29 | User agent to use
30 | -v [ --verbose ] Be verbose
31 | -V [ --version ] Print version string
32 | -x [ --xml ] Verify XML validity
33 |
34 |
35 | ## Example usage
36 |
37 | * By default rate is 1 request per second for 10 seconds
38 |
39 | ruok -u http://www.google.com/search?q=ruok
40 |
41 | DNS Connect SSL Protocol First byte Total Bytes Return code
42 | 0.000934 0.109248 0.000000 0.000001 0.153485 1.320860 96679.000000 200
43 | 0.001100 0.107790 0.000000 0.000001 0.146549 1.639408 96680.000000 200
44 | 0.000691 0.117595 0.000000 0.000000 0.147891 1.113251 81004.000000 200
45 | 0.000499 0.117757 0.000000 0.000001 0.135330 1.282660 96599.000000 200
46 |
47 |
48 | * Turn on XML validation
49 |
50 | ruok -u http://www.google.com/search?q=ruok -x
51 |
52 | DNS Connect SSL Protocol First byte Total Bytes Return code XML
53 | 0.000799 0.107808 0.000000 0.000000 0.141417 1.258222 96699.000000 200 NOT OK
54 | 0.000855 0.108051 0.000000 0.000005 0.151036 1.573901 96721.000000 200 NOT OK
55 | 0.000323 0.115909 0.000000 0.000001 0.153521 1.506323 96580.000000 200 NOT OK
56 | 0.000899 0.115320 0.000000 0.000002 0.142294 1.507822 96363.000000 200 NOT OK
57 |
58 |
59 | ## Thanks
60 |
61 | * Peter Ellehauge for a very cool name suggestion and testing
62 |
--------------------------------------------------------------------------------
/config.h:
--------------------------------------------------------------------------------
1 | #ifndef HAVE_CONFIG
2 | #define HAVE_CONFIG
3 |
4 | #cmakedefine LIBXML2_FOUND
5 | #define PACKAGE_NAME @RUOK_NAME@
6 | #define PACKAGE_VERSION @RUOK_VERSION@
7 |
8 | #endif //HAVE_CONFIG
9 |
--------------------------------------------------------------------------------
/libs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | FIND_PACKAGE(BISON REQUIRED)
2 | FIND_PACKAGE(FLEX REQUIRED)
3 | BISON_TARGET(json_parser json_parser.y ${CMAKE_CURRENT_BINARY_DIR}/json_parser.c)
4 | FLEX_TARGET(json_scanner json_scanner.l ${CMAKE_CURRENT_BINARY_DIR}/json_scanner.c)
5 | ADD_FLEX_BISON_DEPENDENCY(json_scanner json_parser)
6 |
7 | include_directories(${CMAKE_CURRENT_BINARY_DIR})
8 |
9 | set(RUOK_JSON_SOURCES
10 | jsonmain.c
11 | ${BISON_json_parser_OUTPUTS}
12 | ${FLEX_json_scanner_OUTPUTS}
13 | )
14 |
15 | include_directories(${RUOK_JSON_SOURCE_DIR})
16 | add_library(json STATIC ${RUOK_JSON_SOURCES})
17 | SET_TARGET_PROPERTIES(json PROPERTIES OUTPUT_NAME json)
18 |
--------------------------------------------------------------------------------
/libs/json_parser.y:
--------------------------------------------------------------------------------
1 | /*
2 | jsonval - validates JSON files for well-formedness
3 | Copyright (C) 2007 Ben Spencer
4 |
5 | This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, write to the Free Software
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | %{
21 | #include "json_parser.h"
22 | #include "json_scanner.h"
23 |
24 | extern void yyerror(yyscan_t, const char *);
25 | %}
26 |
27 | %defines
28 | %error-verbose
29 | %pure-parser
30 | %parse-param {yyscan_t scanner}
31 | %lex-param {yyscan_t scanner}
32 |
33 | %token TSTRING
34 | %token TNUMBER
35 | %token TBOOL
36 | %token TNULL
37 | %token TINVALID
38 |
39 | %%
40 |
41 | text: object
42 | | array
43 | ;
44 |
45 | object: '{' '}'
46 | | '{' members '}'
47 | ;
48 |
49 | members: member
50 | | member ',' members
51 | ;
52 |
53 | member: TSTRING ':' value
54 | ;
55 |
56 | array: '[' ']'
57 | | '[' elements ']'
58 | ;
59 |
60 | elements: value
61 | | value ',' elements
62 | ;
63 |
64 | value: TSTRING
65 | | TNUMBER
66 | | object
67 | | array
68 | | TBOOL
69 | | TNULL
70 | ;
71 |
72 |
--------------------------------------------------------------------------------
/libs/json_scanner.l:
--------------------------------------------------------------------------------
1 | /*
2 | jsonval - validates JSON files for well-formedness
3 | Copyright (C) 2007 Ben Spencer
4 |
5 | This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, write to the Free Software
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 |
20 | %{
21 | #include "json_parser.h"
22 | %}
23 | %option outfile="json_scanner.c" header="json_scanner.h"
24 | %option 8bit reentrant bison-bridge
25 | %option yylineno noyywrap nounput
26 | %option warn nodefault
27 |
28 |
29 | %x str
30 |
31 | %%
32 | /* Whitespace */
33 | [ \t\n]
34 |
35 | /* Punctuation */
36 | [\[\]\{\}:,] return (unsigned char) yytext[0];
37 |
38 | /* Numbers */
39 | 0|-?([1-9][0-9]*(\.[0-9]+)?|0\.[0-9]+)([Ee][+-]?[0-9]+)? return TNUMBER;
40 |
41 | /* Strings */
42 | \" BEGIN str;
43 | [^\"\\[:cntrl:]]+
44 | \\u[0-9A-Fa-f]{4}
45 | \\[\"\\/bfnrt]
46 | \" {BEGIN(INITIAL); return TSTRING;}
47 | .|\n return TINVALID;
48 |
49 | /* Booleans and NULL */
50 | (true|false) return TBOOL;
51 | null return TNULL;
52 |
53 | /* Crap */
54 | . return TINVALID;
55 |
--------------------------------------------------------------------------------
/libs/jsonmain.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include "json_parser.h"
22 | #include "json_scanner.h"
23 |
24 | extern int yyparse(yyscan_t scanner);
25 | int parse_and_report(FILE *f);
26 |
27 | int parse_and_report(FILE *f)
28 | {
29 | yyscan_t scanner;
30 | int err = 0;
31 |
32 | if(!f) {
33 | perror("failed");
34 | return 1;
35 | }
36 |
37 | yylex_init(&scanner);
38 | yyset_in(f, scanner);
39 | // yyset_extra((void *) filename, scanner);
40 | #ifdef DEBUG
41 | yyset_debug(1, scanner);
42 | #endif
43 |
44 | switch(yyparse(scanner)) {
45 | case 0:
46 | err = 0;
47 | break;
48 | case 1:
49 | err = 1;
50 | break;
51 | case 2:
52 | fprintf(stderr, "Out of memory\n");
53 | err = 1;
54 | break;
55 | }
56 |
57 | yylex_destroy(scanner);
58 |
59 | return err;
60 | }
61 |
62 | void yyerror(yyscan_t scanner, const char *error)
63 | {
64 | }
65 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(RUOK_SOURCES
2 | main.cc
3 | options.cc
4 | options.h
5 | requestthread.cc
6 | requestthread.h
7 | responseprinter.cc
8 | responseprinter.h
9 | )
10 | include_directories(${RUOK_SOURCE_DIR} ${RUOK_CURL_INCLUDES} ${RUOK_LIBXML2_INCLUDES})
11 | add_executable(ruok ${RUOK_SOURCES})
12 | target_link_libraries(ruok ${RUOK_LIBXML2_LIBRARIES} ${RUOK_CURL_LIBRARIES} json)
13 |
14 | INSTALL(PROGRAMS ruok ${CMAKE_CURRENT_BINARY_DIR}/ruok
15 | DESTINATION bin)
16 |
--------------------------------------------------------------------------------
/src/main.cc:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #include "options.h"
19 | #include "requestthread.h"
20 |
21 | int main(int argc, char** argv) {
22 |
23 | curl_global_init(CURL_GLOBAL_DEFAULT);
24 |
25 | ruok::OptionsParser* options = new ruok::OptionsParser();
26 | options->parse(argc, argv);
27 |
28 | struct ruok::config Cfg = options->getConfig();
29 |
30 | delete(options);
31 |
32 | if(!Cfg.no_header) {printHeader(Cfg);}
33 |
34 |
35 | ruok::MainThread mt(Cfg);
36 | mt.start();
37 |
38 | curl_global_cleanup();
39 | return 0;
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/options.cc:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #include
19 | #include "requestthread.h"
20 | #include "options.h"
21 |
22 | namespace ruok {
23 |
24 | OptionsParser::OptionsParser()
25 | {
26 | m_config.callback = default_callback;
27 | #ifdef LIBXML2_FOUND
28 | m_config.xml = 0;
29 | #endif
30 | m_config.json = 0;
31 | m_config.verbose = 0L;
32 | m_config.follow_redirects = 0;
33 | m_config.no_header = 0;
34 | m_config.ms = 0;
35 | m_config.version = 0;
36 | m_config.ua = std::string("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1");
37 | m_config.url = std::string("");
38 | m_config.rate = 1;
39 | m_config.period = 10;
40 | m_config.help = 0;
41 | m_config.headers = NULL;
42 | }
43 |
44 | void OptionsParser::parse(int ac, char** av) {
45 | int c;
46 | static struct option longopts[] =
47 | {
48 | { "follow", no_argument, 0, 'f' },
49 | { "help", no_argument, 0 , 'h' },
50 | { "Header", required_argument, 0, 'H' },
51 | { "json", no_argument, 0, 'j' },
52 | { "miliseconds", no_argument, 0 , 'm' },
53 | { "no-header", no_argument, 0, 'n' },
54 | { "period", required_argument, 0, 'p' },
55 | { "rate", required_argument, 0, 'r' },
56 | { "url", required_argument, 0, 'u' },
57 | { "user-agent", required_argument, 0, 'U' },
58 | { "verbose", no_argument, 0, 'v' },
59 | { "version", no_argument, 0, 'V' },
60 | #ifdef LIBXML2_FOUND
61 | { "xml", no_argument, 0, 'x' },
62 | #endif
63 | {0, 0, 0, 0}
64 | };
65 |
66 |
67 | while(1) {
68 | int idx = 0;
69 | c = getopt_long(ac, av, "?fhH:jmnp:r:u:U:vVx" , longopts, &idx);
70 | if (c == -1) { //end of options
71 | break;
72 | }
73 |
74 | switch(c) {
75 | case 0:
76 | if(longopts[idx].flag !=0) break;
77 | std::cout << "Option : " << longopts[idx].name << std::endl;
78 | if(optarg) {
79 | std::cout << "Optarg : " << optarg << std::endl;
80 | }
81 | break;
82 |
83 | case 'f':
84 | m_config.follow_redirects = 1;
85 | break;
86 |
87 | case 'j':
88 | m_config.json = 1;
89 | break;
90 |
91 | case 'H':
92 | m_config.headers = curl_slist_append(m_config.headers, optarg);
93 | break;
94 |
95 | case 'm':
96 | m_config.ms = 1;
97 | break;
98 |
99 | case 'n':
100 | m_config.no_header = 1;
101 | break;
102 |
103 | case 'p':
104 | m_config.period = atoi(optarg);
105 | std::cout << "Period set to : " << m_config.period << std::endl;
106 | break;
107 |
108 | case 'r':
109 | m_config.rate = atoi(optarg);
110 | std::cout << "Rate set to : " << m_config.rate << std::endl;
111 | break;
112 |
113 | case 'u':
114 | m_config.url = optarg;
115 | std::cout << "Url set to : " << m_config.url << std::endl;
116 | break;
117 |
118 | case 'U':
119 | m_config.ua = optarg;
120 | std::cout << "User agent set to : " << m_config.ua << std::endl;
121 | break;
122 |
123 | case 'v' :
124 | m_config.verbose = 1;
125 | break;
126 |
127 | case 'V':
128 | m_config.version = 1;
129 | break;
130 |
131 | #ifdef LIBXML2_FOUND
132 | case 'x':
133 | m_config.xml = 1;
134 | break;
135 | #endif
136 |
137 | case 'h':
138 | case '?':
139 | m_config.help = 1;
140 | break;
141 |
142 | default:
143 | break;
144 | }
145 | }
146 |
147 | if(m_config.help){
148 | printHelp(av[0]);
149 | exit(EXIT_SUCCESS);
150 | }
151 |
152 | if(m_config.version) {
153 | std::cout << PACKAGE_NAME << " : Version : " << PACKAGE_VERSION << std::endl;
154 | exit(EXIT_SUCCESS);
155 | }
156 |
157 | if(m_config.no_header){
158 | std::cout << "no header" << std::endl;
159 | }
160 | #ifdef LIBXML2_FOUND
161 | if(m_config.xml || m_config.json){
162 | m_config.callback = checkcontent_callback;
163 | }
164 | #else
165 | if(m_config.json){
166 | m_config.callback = checkcontent_callback;
167 | }
168 | #endif
169 |
170 | if(m_config.url == "") {
171 | std::cout << "No url provided -- giving up" << std::endl;
172 | exit(EXIT_FAILURE);
173 | }
174 |
175 |
176 | }
177 |
178 |
179 | void OptionsParser::printHelp(const char* prog) {
180 | std::cout << prog << "\n" \
181 | << "\t--follow,f\t" << std::setfill(' ') << std::setw(10) << " Follow redirects\n" \
182 | << "\t--help,h,?\t" << std::setfill(' ') << std::setw(10) << " Displays this information\n" \
183 | << "\t--Header,H\t" << std::setfill(' ') << std::setw(10) << " Add a Header directive \n" \
184 | << "\t--json,j\t" << std::setfill(' ') << std::setw(10) << " Validate retrieved data through a JSON parser\n" \
185 | << "\t--miliseconds,m\t" << std::setw(10) << " Displays times in miliseconds [ seconds is default ]\n" \
186 | << "\t--no-header,n" << std::setw(10) << " When printing results don't print the header [ default on ]\n" \
187 | << "\t--period,p" << std::setw(10) << " Time to run the tests in seconds [ default 10 ]\n" \
188 | << "\t--rate,r"<< std::setw(10) << " Rate of requests per second [ default 1 ]\n" \
189 | << "\t--url,u" << std::setw(10) << " Url to connect to [ required ]\n" \
190 | << "\t--user-agent,U" << std::setw(10) << " User agent to use\n" \
191 | << "\t--verbose,v" << std::setw(10) << " Be verbose\n" \
192 | << "\t--version,V" << std::setw(10) << " Print version\n";
193 | #ifdef LIBXML2_FOUND
194 | std::cout << "\t--xml,x\t-\tValidate retrieved data through an XML parser";
195 | #endif
196 | std::cout << std::endl;
197 |
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/src/options.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #ifndef _RUOK_OPTIONS_H
19 | #define _RUOK_OPTIONS_H
20 | #define GNU_SOURCE
21 |
22 | #include
23 | #include
24 | #include
25 | #include "config.h"
26 |
27 | namespace ruok {
28 |
29 | struct config {
30 | int help;
31 | int json;
32 | int rate;
33 | int period;
34 | int no_header;
35 | int ms;
36 | int follow_redirects;
37 | std::string ua;
38 | struct curl_slist* headers;
39 | std::string url;
40 | int verbose;
41 | int version;
42 | #ifdef LIBXML2_FOUND
43 | int xml;
44 | #endif
45 | size_t (*callback)(void*,size_t,size_t,void*);
46 | };
47 |
48 |
49 | class OptionsParser {
50 | private:
51 | struct config m_config;
52 |
53 | public:
54 | OptionsParser();
55 | void parse(int ac, char** av);
56 | struct config getConfig() { return m_config; };
57 | void printHelp(const char* prog);
58 | };
59 |
60 | }
61 |
62 | #endif // end _RUOK_OPTIONS_H
63 |
--------------------------------------------------------------------------------
/src/requestthread.cc:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include "requestthread.h"
25 | #include "options.h"
26 | #include "responseprinter.h"
27 |
28 | #include "config.h"
29 |
30 | namespace ruok {
31 |
32 | //struct config;
33 | CURLINFO timers[] = { CURLINFO_NAMELOOKUP_TIME, CURLINFO_CONNECT_TIME, CURLINFO_APPCONNECT_TIME, CURLINFO_PRETRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME, CURLINFO_TOTAL_TIME, CURLINFO_REDIRECT_TIME };
34 |
35 | int processRequest(struct config *C) {
36 | int ret = EXIT_FAILURE;
37 | CURL* handle;
38 | CURLcode res;
39 | std::list results;
40 | char tempfile[] = "/tmp/ruokXXXXXX";
41 | struct tmpfile tfile = {0,NULL};
42 | tfile.fd = mkstemp(tempfile);
43 | if(tfile.fd) {
44 | tfile.fp = fdopen(tfile.fd, "wb+");
45 | }
46 | int factor = (C->ms)?1000:1;
47 |
48 | handle = curl_easy_init();
49 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, C->callback);
50 | #ifdef LIBXML2_FOUND
51 | if(C->xml || C->json) {
52 | #else
53 | if(C->json) {
54 | #endif
55 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, &tfile);
56 | } else {
57 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
58 | }
59 |
60 | if(C->headers) {
61 | curl_easy_setopt(handle, CURLOPT_HTTPHEADER, C->headers);
62 | }
63 | curl_easy_setopt(handle, CURLOPT_VERBOSE, long(C->verbose));
64 | curl_easy_setopt(handle, CURLOPT_USERAGENT, C->ua.c_str());
65 | curl_easy_setopt(handle, CURLOPT_URL, C->url.c_str());
66 |
67 | // automatically set referer when it follows a Location:redirect:
68 | curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L);
69 |
70 | // follow Location ( redirects )
71 | if( C->follow_redirects ) {
72 | curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
73 | }
74 |
75 | res = curl_easy_perform(handle);
76 |
77 | if(C->headers){
78 | curl_slist_free_all(C->headers);
79 | }
80 | if(CURLE_OK == res) {
81 | CURLcode r;
82 | double result;
83 | long rcode;
84 | double last=0;
85 |
86 | ResponsePrinter rp = ResponsePrinter();
87 | last = 0;
88 |
89 | for( int j = 0; j<=4; j++) {
90 | r = curl_easy_getinfo(handle, timers[j] , &result);
91 | if(CURLE_OK != r || result == 0) {
92 | rp.addTiming(result*factor);
93 | } else {
94 | rp.addTiming((result-last)*factor);
95 | last = result;
96 | }
97 | }
98 | r = curl_easy_getinfo(handle, CURLINFO_TOTAL_TIME, &result);
99 | if(CURLE_OK != r) {
100 | rp.addTiming(-1);
101 | } else {
102 | rp.addTiming(result*factor);
103 | }
104 | r = curl_easy_getinfo(handle, CURLINFO_REDIRECT_TIME, &result);
105 | if(CURLE_OK != r) {
106 | rp.addTiming(-1);
107 | } else {
108 | rp.addTiming(result*factor);
109 | }
110 |
111 | r = curl_easy_getinfo(handle, CURLINFO_SIZE_DOWNLOAD, &result);
112 | if(CURLE_OK != r) {
113 | rp.setDocumentSize(-1);
114 | } else {
115 | rp.setDocumentSize(result);
116 | }
117 |
118 | if(tfile.fp) {
119 | #ifdef LIBXML2_FOUND
120 | if(C->xml) {
121 | rp.checkXML(tfile.fd);
122 | }
123 | #endif
124 | if(C->json) {
125 | rp.checkJSON(tfile.fp);
126 | }
127 | fclose(tfile.fp);
128 | }
129 |
130 | r = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &rcode);
131 | if(CURLE_OK != r) { rcode = -1; }
132 | rp.addResponseCode(rcode);
133 | std::cout << rp ;
134 | ret = EXIT_SUCCESS;
135 | }
136 | curl_easy_cleanup(handle);
137 | return ret;
138 | }
139 |
140 | void printHeader(struct config C) {
141 | if(C.verbose) {std::cout << "Using url : " << C.url << std::endl;}
142 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "DNS";
143 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Connect";
144 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "SSL";
145 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Protocol";
146 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "First byte";
147 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Total";
148 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Redirect";
149 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Bytes";
150 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "Return code";
151 | if(C.json){
152 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "JSON";
153 | }
154 | #ifdef LIBXML2_FOUND
155 | if(C.xml){
156 | std::cout << std::left << std::setfill(' ') << std::setw(20) << "XML";
157 | }
158 | #endif
159 | std::cout << std::endl;
160 | }
161 |
162 |
163 |
164 | size_t default_callback(void *p, size_t n, size_t l, void *d) {
165 | (void)p;
166 | (void)d;
167 | return n*l;
168 | }
169 |
170 |
171 | size_t checkcontent_callback(void *p, size_t n, size_t l, void *d) {
172 | struct tmpfile *out = (struct tmpfile*)d;
173 | /* if(out && !out->fd) {
174 | out->fp = fdopen(out->fd, "wb+");
175 | if(!out->fp){
176 | return -1;
177 | }
178 | }*/
179 | fseek(out->fp, 0, SEEK_END);
180 | size_t ret = fwrite(p, n, l, out->fp);
181 | return ret;
182 | }
183 |
184 | MainThread::MainThread(struct config Cfg)
185 | : m_Cfg(Cfg) {};
186 |
187 | void MainThread::start() {
188 | static int period = m_Cfg.period;
189 | std::list pids;
190 | int ret;
191 |
192 | while(period > 0) {
193 | useconds_t sl = (useconds_t)(1.0*1000000/m_Cfg.rate);
194 | for(int i=0; i < m_Cfg.rate; i++) {
195 | pid_t pid = fork();
196 | if(pid > 0) { // parent
197 | usleep(sl);
198 | int status;
199 | while(waitpid(-1, &status, WNOHANG) > 0) { ; }
200 | } else if(pid == 0) { // child
201 | ret = ruok::processRequest(&m_Cfg);
202 | _exit(ret);
203 | } else { // failure to fork
204 | perror("Failed to fork : ");
205 | exit(EXIT_FAILURE);
206 | }
207 | }
208 | int status;
209 | while(waitpid(-1, &status, 0) > 0) { ; }
210 | period--;
211 | }
212 |
213 | }
214 |
215 |
216 | } // end namespace
217 |
--------------------------------------------------------------------------------
/src/requestthread.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #ifndef _RUOK_REQUESTTHREAD_H
19 | #define _RUOK_REQUESTTHREAD_H
20 |
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "options.h"
28 |
29 | namespace ruok {
30 |
31 | struct tmpfile {
32 | int fd;
33 | FILE* fp;
34 | };
35 |
36 | int processRequest(struct config *C);
37 | // int processMultiRequest(std::string url, struct config *C);
38 | void startThreads(struct config C);
39 |
40 | size_t default_callback(void *p, size_t n, size_t l, void *d);
41 | size_t checkcontent_callback(void *p, size_t n, size_t l, void *d);
42 |
43 | void printHeader(struct config C);
44 |
45 | class MainThread {
46 | private:
47 | struct config m_Cfg;
48 | public:
49 | MainThread(struct config C);
50 | void start();
51 | };
52 |
53 | } // end namespace
54 |
55 | #endif // end _RUOK_REQUESTTHREAD_H
56 |
--------------------------------------------------------------------------------
/src/responseprinter.cc:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #include "config.h"
19 | #include
20 | #include
21 |
22 | #ifdef LIBXML2_FOUND
23 | #include
24 | #include
25 | #endif
26 |
27 |
28 | #include "responseprinter.h"
29 |
30 | // forward declaration for libjson validator
31 | extern "C" int parse_and_report(FILE *fp);
32 |
33 | namespace ruok {
34 |
35 | ResponsePrinter::ResponsePrinter() {
36 | timings = std::list();
37 | responseCode = 0;
38 | valids = std::map();
39 | }
40 |
41 | ResponsePrinter::~ResponsePrinter() {
42 | timings.clear();
43 | responseCode = 0;
44 | valids.clear();
45 | }
46 |
47 | void ResponsePrinter::addTiming(double data){
48 | timings.push_back(data);
49 | }
50 |
51 | long ResponsePrinter::getResponseCode(void) {
52 | return responseCode;
53 | }
54 |
55 | double ResponsePrinter::getDocumentSize(void) {
56 | return dsize;
57 | }
58 |
59 | void ResponsePrinter::setDocumentSize(double data) {
60 | dsize = data;
61 | }
62 |
63 | void ResponsePrinter::addResponseCode(long code){
64 | responseCode = code;
65 | }
66 |
67 | #ifdef LIBXML2_FOUND
68 | bool ResponsePrinter::checkXML(int fd){
69 | xmlParserCtxtPtr ctxt;
70 | xmlDocPtr doc;
71 | valids["xml"] = false;
72 | ctxt = xmlNewParserCtxt();
73 | if(ctxt == NULL){
74 | return valids["xml"];
75 | }
76 |
77 | doc = xmlCtxtReadFd(ctxt, fd, NULL, NULL, XML_PARSE_DTDVALID|XML_PARSE_NOERROR);
78 |
79 | if(doc == NULL) {
80 | valids["xml"] = false;
81 | } else {
82 | if(ctxt->valid == 0){
83 | valids["xml"] = false;
84 | }
85 | xmlFreeDoc(doc);
86 | }
87 | xmlFreeParserCtxt(ctxt);
88 |
89 | xmlCleanupParser();
90 |
91 | return valids["xml"];
92 | }
93 | #endif
94 |
95 | bool ResponsePrinter::checkJSON(FILE* fp) {
96 | valids["json"] = false;
97 | if(parse_and_report(fp) == 0) {
98 | valids["json"] = true;
99 | } else {
100 | valids["json"] = false;
101 | }
102 | return valids["json"];
103 | }
104 |
105 |
106 | std::ostream& operator<<(std::ostream &os, ResponsePrinter obj){
107 | std::list::iterator it;
108 | for(it = obj.timings.begin(); it != obj.timings.end(); it++){
109 | os << std::left << std::setfill(' ') << std::setw(20) << std::fixed << (*it);
110 | }
111 | os << std::left << std::setfill(' ') << std::setw(20) << std::fixed << obj.getDocumentSize();
112 |
113 | os << std::left << std::setfill(' ') << std::setw(20) << obj.getResponseCode();
114 |
115 | if(obj.valids.find("json") != obj.valids.end()) {
116 | os << std::left << std::setfill(' ') << std::setw(20) << ( (obj.valids["json"])?"\x1b[32mOK\x1b[0m":"\x1b[31mNOT OK\x1b[0m" );
117 | }
118 | if(obj.valids.find("xml") != obj.valids.end()) {
119 | os << std::left << std::setfill(' ') << std::setw(20) << ( (obj.valids["xml"])?"\x1b[32mOK\x1b[0m":"\x1b[31mNOT OK\x1b[0m" );
120 | }
121 | os << std::endl;
122 |
123 | return os;
124 | }
125 |
126 |
127 |
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/responseprinter.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of ruok - a program that measures timings of transferring data with URL syntax
3 | Copyright (C) 2011 by Radu Brumariu [brum76@gmail.com]
4 |
5 | ruok is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | ruok is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with ruok. If not, see .
17 | */
18 | #ifndef _RUOK_RESPONSEPRINTER_H
19 | #define _RUOK_RESPONSEPRINTER_H
20 | #include "config.h"
21 | #include
22 | #include