Skip to content

Commit 5c64e1a

Browse files
committed
Added support for TCP-NODELAY
1 parent cb491fa commit 5c64e1a

File tree

7 files changed

+159
-1
lines changed

7 files changed

+159
-1
lines changed

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ script:
9898
./benchmark_select 8080 $(nproc) &
9999
sleep 5 && ab -n 10000000 -c 100 localhost:8080/plaintext
100100
fi
101+
- |
102+
if [ "$PERFORMANCE" = "nodelay" ]; then
103+
cd examples
104+
./benchmark_nodelay 8080 $(nproc) &
105+
sleep 5 && ab -n 10000000 -c 100 localhost:8080/plaintext
106+
fi
101107
- |
102108
if [ "$PERFORMANCE" = "threads" ]; then
103109
cd examples
@@ -215,6 +221,16 @@ matrix:
215221
- apache2-utils
216222
env:
217223
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && PERFORMANCE=select"
224+
- os: linux
225+
addons:
226+
apt:
227+
sources:
228+
- ubuntu-toolchain-r-test
229+
packages:
230+
- g++-7
231+
- apache2-utils
232+
env:
233+
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && PERFORMANCE=nodelay"
218234
- os: linux
219235
addons:
220236
apt:

examples/benchmark_nodelay.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <httpserver.hpp>
2+
#include <cstdlib>
3+
#include <memory>
4+
5+
#define PATH "/plaintext"
6+
#define BODY "Hello, World!"
7+
8+
using namespace httpserver;
9+
10+
class hello_world_resource : public http_resource {
11+
public:
12+
hello_world_resource(const std::shared_ptr<http_response>& resp):
13+
resp(resp)
14+
{
15+
}
16+
17+
const std::shared_ptr<http_response> render(const http_request&) {
18+
return resp;
19+
}
20+
21+
private:
22+
std::shared_ptr<http_response> resp;
23+
};
24+
25+
int main(int argc, char** argv)
26+
{
27+
webserver ws = create_webserver(atoi(argv[1]))
28+
.start_method(http::http_utils::INTERNAL_SELECT)
29+
.tcp_nodelay()
30+
.max_threads(atoi(argv[2]));
31+
32+
std::shared_ptr<http_response> hello = std::shared_ptr<http_response>(new string_response(BODY, 200));
33+
hello->with_header("Server", "libhttpserver");
34+
35+
hello_world_resource hwr(hello);
36+
ws.register_resource(PATH, &hwr, false);
37+
38+
ws.start(true);
39+
40+
return 0;
41+
}

src/httpserver/create_webserver.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class create_webserver
8080
_post_process_enabled(true),
8181
_deferred_enabled(false),
8282
_single_resource(false),
83+
_tcp_nodelay(false),
8384
_not_found_resource(0x0),
8485
_method_not_allowed_resource(0x0),
8586
_internal_error_resource(0x0)
@@ -121,6 +122,7 @@ class create_webserver
121122
_post_process_enabled(b._post_process_enabled),
122123
_deferred_enabled(b._deferred_enabled),
123124
_single_resource(b._single_resource),
125+
_tcp_nodelay(b._tcp_nodelay),
124126
_not_found_resource(b._not_found_resource),
125127
_method_not_allowed_resource(b._method_not_allowed_resource),
126128
_internal_error_resource(b._internal_error_resource)
@@ -162,6 +164,7 @@ class create_webserver
162164
_post_process_enabled(b._post_process_enabled),
163165
_deferred_enabled(b._deferred_enabled),
164166
_single_resource(b._single_resource),
167+
_tcp_nodelay(b._tcp_nodelay),
165168
_not_found_resource(std::move(b._not_found_resource)),
166169
_method_not_allowed_resource(std::move(b._method_not_allowed_resource)),
167170
_internal_error_resource(std::move(b._internal_error_resource))
@@ -206,6 +209,7 @@ class create_webserver
206209
this->_post_process_enabled = b._post_process_enabled;
207210
this->_deferred_enabled = b._deferred_enabled;
208211
this->_single_resource = b._single_resource;
212+
this->_tcp_nodelay = b._tcp_nodelay;
209213
this->_not_found_resource = b._not_found_resource;
210214
this->_method_not_allowed_resource = b._method_not_allowed_resource;
211215
this->_internal_error_resource = b._internal_error_resource;
@@ -251,6 +255,7 @@ class create_webserver
251255
this->_post_process_enabled = b._post_process_enabled;
252256
this->_deferred_enabled = b._deferred_enabled;
253257
this->_single_resource = b._single_resource;
258+
this->_tcp_nodelay = b._tcp_nodelay;
254259
this->_not_found_resource = std::move(b._not_found_resource);
255260
this->_method_not_allowed_resource = std::move(b._method_not_allowed_resource);
256261
this->_internal_error_resource = std::move(b._internal_error_resource);
@@ -293,6 +298,7 @@ class create_webserver
293298
_post_process_enabled(true),
294299
_deferred_enabled(false),
295300
_single_resource(false),
301+
_tcp_nodelay(false),
296302
_not_found_resource(0x0),
297303
_method_not_allowed_resource(0x0),
298304
_internal_error_resource(0x0)
@@ -471,6 +477,10 @@ class create_webserver
471477
{
472478
_single_resource = true; return *this;
473479
}
480+
create_webserver& tcp_nodelay()
481+
{
482+
_tcp_nodelay = true; return *this;
483+
}
474484
create_webserver& not_found_resource(render_ptr not_found_resource)
475485
{
476486
_not_found_resource = not_found_resource; return *this;
@@ -524,6 +534,7 @@ class create_webserver
524534
bool _post_process_enabled;
525535
bool _deferred_enabled;
526536
bool _single_resource;
537+
bool _tcp_nodelay;
527538
render_ptr _not_found_resource;
528539
render_ptr _method_not_allowed_resource;
529540
render_ptr _internal_error_resource;

src/httpserver/webserver.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class webserver
174174
const bool post_process_enabled;
175175
const bool deferred_enabled;
176176
bool single_resource;
177+
bool tcp_nodelay;
177178
pthread_mutex_t mutexwait;
178179
pthread_rwlock_t runguard;
179180
pthread_cond_t mutexcond;

src/webserver.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232

3333
#if defined(__MINGW32__) || defined(__CYGWIN32__)
3434
#include <winsock2.h>
35+
#include <ws2tcpip.h>
3536
#define _WINDOWS
3637
#else
3738
#include <netinet/ip.h>
39+
#include <netinet/tcp.h>
3840
#endif
3941

4042
#include <signal.h>
@@ -149,6 +151,7 @@ webserver::webserver(const create_webserver& params):
149151
post_process_enabled(params._post_process_enabled),
150152
deferred_enabled(params._deferred_enabled),
151153
single_resource(params._single_resource),
154+
tcp_nodelay(params._tcp_nodelay),
152155
not_found_resource(params._not_found_resource),
153156
method_not_allowed_resource(params._method_not_allowed_resource),
154157
internal_error_resource(params._internal_error_resource)
@@ -757,6 +760,17 @@ int webserver::answer_to_connection(void* cls, MHD_Connection* connection,
757760
);
758761
}
759762

763+
const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(
764+
connection,
765+
MHD_CONNECTION_INFO_CONNECTION_FD
766+
);
767+
768+
if (static_cast<webserver*>(cls)->tcp_nodelay)
769+
{
770+
int yes = 1;
771+
setsockopt(conninfo->connect_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(int));
772+
}
773+
760774
std::string t_url = url;
761775

762776
base_unescaper(t_url, static_cast<webserver*>(cls)->unescaper);

test/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
LDADD = $(top_builddir)/src/libhttpserver.la
2020
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
2121
METASOURCES = AUTO
22-
check_PROGRAMS = basic http_utils threaded string_utilities http_endpoint ban_system ws_start_stop authentication deferred
22+
check_PROGRAMS = basic http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred
2323

2424
MOSTLYCLEANFILES = *.gcda *.gcno *.gcov
2525

@@ -32,6 +32,7 @@ deferred_SOURCES = integ/deferred.cpp
3232
http_utils_SOURCES = unit/http_utils_test.cpp
3333
string_utilities_SOURCES = unit/string_utilities_test.cpp
3434
http_endpoint_SOURCES = unit/http_endpoint_test.cpp
35+
nodelay_SOURCES = integ/nodelay.cpp
3536

3637
noinst_HEADERS = littletest.hpp
3738
AM_CXXFLAGS += -lcurl -Wall -fPIC

test/integ/nodelay.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
This file is part of libhttpserver
3+
Copyright (C) 2011-2019 Sebastiano Merlino
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library 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 GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18+
USA
19+
*/
20+
21+
#include "littletest.hpp"
22+
#include <curl/curl.h>
23+
#include <string>
24+
#include <map>
25+
#include "httpserver.hpp"
26+
27+
using namespace httpserver;
28+
using namespace std;
29+
30+
class ok_resource : public http_resource
31+
{
32+
public:
33+
const shared_ptr<http_response> render_GET(const http_request& req)
34+
{
35+
return shared_ptr<string_response>(new string_response("OK", 200, "text/plain"));
36+
}
37+
};
38+
39+
LT_BEGIN_SUITE(threaded_suite)
40+
41+
webserver* ws;
42+
43+
void set_up()
44+
{
45+
ws = new webserver(create_webserver(8080).tcp_nodelay());
46+
ws->start(false);
47+
}
48+
49+
void tear_down()
50+
{
51+
ws->stop();
52+
delete ws;
53+
}
54+
LT_END_SUITE(threaded_suite)
55+
56+
LT_BEGIN_AUTO_TEST(threaded_suite, base)
57+
ok_resource resource;
58+
ws->register_resource("base", &resource);
59+
curl_global_init(CURL_GLOBAL_ALL);
60+
std::string s;
61+
CURL* curl;
62+
CURLcode res;
63+
64+
curl = curl_easy_init();
65+
curl_easy_setopt(curl, CURLOPT_URL, "localhost:8080/base");
66+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
67+
res = curl_easy_perform(curl);
68+
LT_ASSERT_EQ(res, 0);
69+
curl_easy_cleanup(curl);
70+
LT_END_AUTO_TEST(base)
71+
72+
LT_BEGIN_AUTO_TEST_ENV()
73+
AUTORUN_TESTS()
74+
LT_END_AUTO_TEST_ENV()

0 commit comments

Comments
 (0)