Skip to content

Commit b6fd4bf

Browse files
author
Sebastiano Merlino
committed
Moved comet management in a separate class
This helps in reducing the responsibilities of the webserver class. The webserver class moves to uncopyable - it turns out to be so complex to be dangerous as a copyable class and btw it is almost useless to have facilities to copy the entire webserver.
1 parent 73930a0 commit b6fd4bf

File tree

6 files changed

+418
-222
lines changed

6 files changed

+418
-222
lines changed

examples/Test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ void Test::render_PUT(const http_request& r, http_response** res)
116116
int main()
117117
{
118118
// signal(SIGINT, &signal_callback_handler);
119-
webserver ws = create_webserver(8080)/*.max_threads(5)*/;
119+
webserver ws(create_webserver(8080)/*.max_threads(5)*/);
120120
ws_ptr = &ws;
121121
Test dt = Test();
122122
Test2 dt2 = Test2();

src/Makefile.am

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
AM_CPPFLAGS = -I../ -I$(srcdir)/httpserver/
2020
METASOURCES = AUTO
2121
lib_LTLIBRARIES = libhttpserver.la
22-
libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp http_utils.cpp http_endpoint.cpp http_request.cpp http_response.cpp http_resource.cpp
23-
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/details/modded_request.hpp httpserver/details/http_response_ptr.hpp httpserver/details/cache_entry.hpp gettext.h
22+
libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp http_utils.cpp http_endpoint.cpp http_request.cpp http_response.cpp http_resource.cpp comet_manager.cpp
23+
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/details/modded_request.hpp httpserver/details/http_response_ptr.hpp httpserver/details/cache_entry.hpp httpserver/details/comet_manager.hpp gettext.h
2424
nobase_include_HEADERS = httpserver.hpp httpserver/create_webserver.hpp httpserver/webserver.hpp httpserver/http_utils.hpp httpserver/details/http_endpoint.hpp httpserver/http_request.hpp httpserver/http_response.hpp httpserver/http_resource.hpp httpserver/binders.hpp httpserver/event_supplier.hpp httpserver/details/event_tuple.hpp httpserver/details/http_resource_mirror.hpp
2525
AM_CXXFLAGS += -fPIC -Wall
2626
libhttpserver_la_LIBADD = -lmicrohttpd

src/comet_manager.cpp

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
This file is part of libhttpserver
3+
Copyright (C) 2011, 2012, 2013, 2014 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 <errno.h>
22+
#include <iostream>
23+
#include "details/comet_manager.hpp"
24+
25+
using namespace std;
26+
27+
namespace httpserver
28+
{
29+
30+
namespace details
31+
{
32+
33+
comet_manager::comet_manager()
34+
{
35+
pthread_rwlock_init(&comet_guard, NULL);
36+
pthread_mutex_init(&cleanmux, NULL);
37+
pthread_cond_init(&cleancond, NULL);
38+
}
39+
40+
comet_manager::~comet_manager()
41+
{
42+
pthread_rwlock_destroy(&comet_guard);
43+
pthread_mutex_destroy(&cleanmux);
44+
pthread_cond_destroy(&cleancond);
45+
}
46+
47+
void comet_manager::send_message_to_topic (
48+
const string& topic,
49+
const string& message,
50+
const httpserver::http::http_utils::start_method_T& start_method
51+
)
52+
{
53+
pthread_rwlock_wrlock(&comet_guard);
54+
for(set<http::httpserver_ska>::const_iterator it = q_waitings[topic].begin();
55+
it != q_waitings[topic].end();
56+
++it
57+
)
58+
{
59+
q_messages[(*it)].push_back(message);
60+
q_signal.insert((*it));
61+
if(start_method != http::http_utils::INTERNAL_SELECT)
62+
{
63+
pthread_mutex_lock(&q_blocks[(*it)].first);
64+
pthread_cond_signal(&q_blocks[(*it)].second);
65+
pthread_mutex_unlock(&q_blocks[(*it)].first);
66+
}
67+
map<http::httpserver_ska, long>::const_iterator itt;
68+
if((itt = q_keepalives.find(*it)) != q_keepalives.end())
69+
{
70+
struct timeval curtime;
71+
gettimeofday(&curtime, NULL);
72+
q_keepalives[*it] = curtime.tv_sec;
73+
}
74+
}
75+
pthread_rwlock_unlock(&comet_guard);
76+
if(start_method != http::http_utils::INTERNAL_SELECT)
77+
{
78+
pthread_mutex_lock(&cleanmux);
79+
pthread_cond_signal(&cleancond);
80+
pthread_mutex_unlock(&cleanmux);
81+
}
82+
}
83+
84+
void comet_manager::register_to_topics (
85+
const vector<string>& topics,
86+
const http::httpserver_ska& connection_id,
87+
int keepalive_secs,
88+
string keepalive_msg,
89+
const httpserver::http::http_utils::start_method_T& start_method
90+
)
91+
{
92+
pthread_rwlock_wrlock(&comet_guard);
93+
for(vector<string>::const_iterator it = topics.begin();
94+
it != topics.end(); ++it
95+
)
96+
q_waitings[*it].insert(connection_id);
97+
if(keepalive_secs != -1)
98+
{
99+
struct timeval curtime;
100+
gettimeofday(&curtime, NULL);
101+
q_keepalives[connection_id] = curtime.tv_sec;
102+
q_keepalives_mem[connection_id] = make_pair(
103+
keepalive_secs, keepalive_msg
104+
);
105+
}
106+
if(start_method != http::http_utils::INTERNAL_SELECT)
107+
{
108+
pthread_mutex_t m;
109+
pthread_cond_t c;
110+
pthread_mutex_init(&m, NULL);
111+
pthread_cond_init(&c, NULL);
112+
q_blocks[connection_id] =
113+
make_pair(m, c);
114+
}
115+
pthread_rwlock_unlock(&comet_guard);
116+
}
117+
118+
size_t comet_manager::read_message(const http::httpserver_ska& connection_id,
119+
string& message
120+
)
121+
{
122+
pthread_rwlock_wrlock(&comet_guard);
123+
deque<string>& t_deq = q_messages[connection_id];
124+
message.assign(t_deq.front());
125+
t_deq.pop_front();
126+
pthread_rwlock_unlock(&comet_guard);
127+
return message.size();
128+
}
129+
130+
size_t comet_manager::get_topic_consumers(
131+
const string& topic,
132+
set<http::httpserver_ska>& consumers
133+
)
134+
{
135+
pthread_rwlock_rdlock(&comet_guard);
136+
137+
for(set<http::httpserver_ska>::const_iterator it = q_waitings[topic].begin();
138+
it != q_waitings[topic].end(); ++it
139+
)
140+
{
141+
consumers.insert((*it));
142+
}
143+
int size = consumers.size();
144+
pthread_rwlock_unlock(&comet_guard);
145+
return size;
146+
}
147+
148+
bool comet_manager::pop_signaled(const http::httpserver_ska& consumer,
149+
const httpserver::http::http_utils::start_method_T& start_method
150+
)
151+
{
152+
if(start_method == http::http_utils::INTERNAL_SELECT)
153+
{
154+
pthread_rwlock_wrlock(&comet_guard);
155+
set<http::httpserver_ska>::iterator it = q_signal.find(consumer);
156+
if(it != q_signal.end())
157+
{
158+
if(q_messages[consumer].empty())
159+
{
160+
q_signal.erase(it);
161+
pthread_rwlock_unlock(&comet_guard);
162+
return false;
163+
}
164+
pthread_rwlock_unlock(&comet_guard);
165+
return true;
166+
}
167+
else
168+
{
169+
pthread_rwlock_unlock(&comet_guard);
170+
return false;
171+
}
172+
}
173+
else
174+
{
175+
pthread_rwlock_rdlock(&comet_guard);
176+
pthread_mutex_lock(&q_blocks[consumer].first);
177+
struct timespec t;
178+
struct timeval curtime;
179+
180+
{
181+
bool to_unlock = true;
182+
while(q_signal.find(consumer) == q_signal.end())
183+
{
184+
if(to_unlock)
185+
{
186+
pthread_rwlock_unlock(&comet_guard);
187+
to_unlock = false;
188+
}
189+
gettimeofday(&curtime, NULL);
190+
t.tv_sec = curtime.tv_sec + q_keepalives_mem[consumer].first;
191+
t.tv_nsec = 0;
192+
int rslt = pthread_cond_timedwait(&q_blocks[consumer].second,
193+
&q_blocks[consumer].first, &t
194+
);
195+
if(rslt == ETIMEDOUT)
196+
{
197+
pthread_rwlock_wrlock(&comet_guard);
198+
send_message_to_consumer(consumer,
199+
q_keepalives_mem[consumer].second, false, start_method
200+
);
201+
pthread_rwlock_unlock(&comet_guard);
202+
}
203+
}
204+
if(to_unlock)
205+
pthread_rwlock_unlock(&comet_guard);
206+
}
207+
208+
if(q_messages[consumer].size() == 0)
209+
{
210+
pthread_rwlock_wrlock(&comet_guard);
211+
q_signal.erase(consumer);
212+
pthread_mutex_unlock(&q_blocks[consumer].first);
213+
pthread_rwlock_unlock(&comet_guard);
214+
return false;
215+
}
216+
pthread_rwlock_rdlock(&comet_guard);
217+
pthread_mutex_unlock(&q_blocks[consumer].first);
218+
pthread_rwlock_unlock(&comet_guard);
219+
return true;
220+
}
221+
return false;
222+
}
223+
224+
void comet_manager::complete_request(const http::httpserver_ska& connection_id)
225+
{
226+
pthread_rwlock_wrlock(&comet_guard);
227+
q_messages.erase(connection_id);
228+
q_blocks.erase(connection_id);
229+
q_signal.erase(connection_id);
230+
q_keepalives.erase(connection_id);
231+
232+
typedef map<string, set<http::httpserver_ska> >::iterator conn_it;
233+
for(conn_it it = q_waitings.begin(); it != q_waitings.end(); ++it)
234+
{
235+
it->second.erase(connection_id);
236+
}
237+
pthread_rwlock_unlock(&comet_guard);
238+
}
239+
240+
void comet_manager::comet_select(unsigned long long* timeout_secs,
241+
unsigned long long* timeout_microsecs,
242+
const httpserver::http::http_utils::start_method_T& start_method
243+
)
244+
{
245+
pthread_rwlock_wrlock(&comet_guard);
246+
for(map<http::httpserver_ska, long>::iterator it = q_keepalives.begin(); it != q_keepalives.end(); ++it)
247+
{
248+
struct timeval curtime;
249+
gettimeofday(&curtime, NULL);
250+
int waited_time = curtime.tv_sec - (*it).second;
251+
if(waited_time >= q_keepalives_mem[(*it).first].first)
252+
{
253+
send_message_to_consumer((*it).first, q_keepalives_mem[(*it).first].second, true, start_method);
254+
}
255+
else
256+
{
257+
unsigned long long to_wait_time = (q_keepalives_mem[(*it).first].first - waited_time);
258+
if(to_wait_time < *timeout_secs)
259+
{
260+
*timeout_secs = to_wait_time;
261+
*timeout_microsecs = 0;
262+
}
263+
}
264+
}
265+
pthread_rwlock_unlock(&comet_guard);
266+
}
267+
268+
void comet_manager::send_message_to_consumer(
269+
const http::httpserver_ska& connection_id,
270+
const std::string& message,
271+
bool to_lock,
272+
const httpserver::http::http_utils::start_method_T& start_method
273+
)
274+
{
275+
//This function need to be externally locked on write
276+
q_messages[connection_id].push_back(message);
277+
map<http::httpserver_ska, long>::const_iterator it;
278+
if((it = q_keepalives.find(connection_id)) != q_keepalives.end())
279+
{
280+
struct timeval curtime;
281+
gettimeofday(&curtime, NULL);
282+
q_keepalives[connection_id] = curtime.tv_sec;
283+
}
284+
q_signal.insert(connection_id);
285+
if(start_method != http::http_utils::INTERNAL_SELECT)
286+
{
287+
if(to_lock)
288+
pthread_mutex_lock(&q_blocks[connection_id].first);
289+
pthread_cond_signal(&q_blocks[connection_id].second);
290+
if(to_lock)
291+
pthread_mutex_unlock(&q_blocks[connection_id].first);
292+
}
293+
}
294+
295+
} //details
296+
297+
} //httpserver

0 commit comments

Comments
 (0)