passenger 3.0.8 → 3.0.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (42) hide show
  1. data/NEWS +9 -0
  2. data/bin/passenger-install-nginx-module +1 -1
  3. data/build/basics.rb +0 -1
  4. data/build/cxx_tests.rb +5 -0
  5. data/build/rpm.rb +1 -1
  6. data/doc/Users guide Apache.html +1 -1
  7. data/doc/Users guide Nginx.html +1 -1
  8. data/ext/apache2/Configuration.cpp +12 -0
  9. data/ext/apache2/Configuration.hpp +12 -1
  10. data/ext/apache2/Hooks.cpp +2 -0
  11. data/ext/common/AgentsStarter.cpp +4 -0
  12. data/ext/common/AgentsStarter.h +2 -0
  13. data/ext/common/AgentsStarter.hpp +4 -0
  14. data/ext/common/Constants.h +1 -1
  15. data/ext/common/Logging.h +481 -261
  16. data/ext/common/LoggingAgent/LoggingServer.h +10 -4
  17. data/ext/common/LoggingAgent/Main.cpp +7 -2
  18. data/ext/common/LoggingAgent/RemoteSender.h +25 -3
  19. data/ext/common/MessageChannel.h +18 -227
  20. data/ext/common/MessageClient.h +95 -92
  21. data/ext/common/Utils/IOUtils.cpp +114 -1
  22. data/ext/common/Utils/IOUtils.h +57 -1
  23. data/ext/common/Utils/MessageIO.h +576 -0
  24. data/ext/nginx/Configuration.c +35 -0
  25. data/ext/nginx/Configuration.h +2 -0
  26. data/ext/nginx/ContentHandler.c +17 -6
  27. data/ext/nginx/ngx_http_passenger_module.c +8 -0
  28. data/lib/phusion_passenger.rb +2 -2
  29. data/lib/phusion_passenger/analytics_logger.rb +174 -117
  30. data/lib/phusion_passenger/app_process.rb +14 -2
  31. data/test/cxx/CxxTestMain.cpp +14 -19
  32. data/test/cxx/IOUtilsTest.cpp +68 -18
  33. data/test/cxx/LoggingTest.cpp +20 -24
  34. data/test/cxx/MessageChannelTest.cpp +1 -1
  35. data/test/cxx/MessageIOTest.cpp +310 -0
  36. data/test/cxx/TestSupport.cpp +47 -0
  37. data/test/cxx/TestSupport.h +8 -0
  38. data/test/ruby/analytics_logger_spec.rb +20 -28
  39. data/test/tut/tut.h +2 -0
  40. metadata +11 -11
  41. data/build/rdoctask.rb +0 -209
  42. data/test/cxx/HttpStatusExtractorTest.cpp +0 -198
data/NEWS CHANGED
@@ -1,3 +1,12 @@
1
+ Release 3.0.9
2
+ -------------
3
+
4
+ * [Nginx] Fixed a NULL pointer crash that occurs on HTTP/1.0 requests
5
+ when the Host header isn't given.
6
+ * Fixed deprecation warnings on RubyGems >= 1.6.
7
+ * Improved Union Station support stability.
8
+
9
+
1
10
  Release 3.0.8
2
11
  -------------
3
12
 
@@ -192,7 +192,7 @@ private
192
192
  new_screen
193
193
  color_puts "<banner>Downloading Nginx...</banner>"
194
194
 
195
- url = "http://sysoev.ru/nginx/nginx-#{PREFERRED_NGINX_VERSION}.tar.gz"
195
+ url = "http://www.nginx.org/download/nginx-#{PREFERRED_NGINX_VERSION}.tar.gz"
196
196
  dirname = "nginx-#{PREFERRED_NGINX_VERSION}"
197
197
  tarball = "#{@working_dir}/nginx.tar.gz"
198
198
 
@@ -38,7 +38,6 @@ require 'phusion_passenger/platform_info/documentation_tools'
38
38
  include PhusionPassenger
39
39
  include PhusionPassenger::PlatformInfo
40
40
 
41
- require 'build/rdoctask'
42
41
  require 'build/packagetask'
43
42
  require 'build/gempackagetask'
44
43
  require 'build/rake_extensions'
@@ -28,6 +28,7 @@ TEST_CXX_CFLAGS = "-Iext -Iext/common -Iext/nginx " <<
28
28
  "#{TEST_COMMON_CFLAGS}"
29
29
  TEST_CXX_LDFLAGS = "#{TEST_COMMON_LIBRARY} #{TEST_BOOST_OXT_LIBRARY} #{LIBEV_LIBS} " <<
30
30
  "#{PlatformInfo.curl_libs} " <<
31
+ "#{PlatformInfo.zlib_libs} " <<
31
32
  "#{PlatformInfo.portability_ldflags} #{EXTRA_LDFLAGS}"
32
33
  TEST_CXX_OBJECTS = {
33
34
  'test/cxx/CxxTestMain.o' => %w(
@@ -187,6 +188,10 @@ TEST_CXX_OBJECTS = {
187
188
  test/cxx/BufferedIOTest.cpp
188
189
  ext/common/Utils/BufferedIO.h
189
190
  ext/common/Utils/Timer.h),
191
+ 'test/cxx/MessageIOTest.o' => %w(
192
+ test/cxx/MessageIOTest.cpp
193
+ ext/common/Utils/MessageIO.h
194
+ ext/common/Utils/IOUtils.h),
190
195
  'test/cxx/VariantMapTest.o' => %w(
191
196
  test/cxx/VariantMapTest.cpp
192
197
  ext/common/MessageChannel.h
@@ -42,7 +42,7 @@ namespace :package do
42
42
  def fetch(dir)
43
43
  tarball = "nginx-#{PREFERRED_NGINX_VERSION}.tar.gz"
44
44
  return true if File.exists?("#{dir}/#{tarball}")
45
- download("http://sysoev.ru/nginx/#{tarball}", "#{dir}/#{tarball}")
45
+ download("http://www.nginx.org/download/#{tarball}", "#{dir}/#{tarball}")
46
46
  end
47
47
  end
48
48
 
@@ -4781,7 +4781,7 @@ has no effect.</p></div>
4781
4781
  <div id="footnotes"><hr></div>
4782
4782
  <div id="footer">
4783
4783
  <div id="footer-text">
4784
- Last updated 2011-08-03 11:00:00 CEST
4784
+ Last updated 2011-08-11 22:39:09 CEST
4785
4785
  </div>
4786
4786
  </div>
4787
4787
  </body>
@@ -3704,7 +3704,7 @@ has no effect.</p></div>
3704
3704
  <div id="footnotes"><hr></div>
3705
3705
  <div id="footer">
3706
3706
  <div id="footer-text">
3707
- Last updated 2011-08-03 11:00:00 CEST
3707
+ Last updated 2011-08-11 22:39:09 CEST
3708
3708
  </div>
3709
3709
  </div>
3710
3710
  </body>
@@ -282,6 +282,8 @@ DEFINE_SERVER_STR_CONFIG_SETTER(cmd_passenger_temp_dir, tempDir)
282
282
  DEFINE_SERVER_STR_CONFIG_SETTER(cmd_union_station_gateway_address, unionStationGatewayAddress)
283
283
  DEFINE_SERVER_INT_CONFIG_SETTER(cmd_union_station_gateway_port, unionStationGatewayPort, int, 1)
284
284
  DEFINE_SERVER_STR_CONFIG_SETTER(cmd_union_station_gateway_cert, unionStationGatewayCert)
285
+ DEFINE_SERVER_STR_CONFIG_SETTER(cmd_union_station_proxy_address, unionStationProxyAddress)
286
+ DEFINE_SERVER_STR_CONFIG_SETTER(cmd_union_station_proxy_type, unionStationProxyType)
285
287
  DEFINE_SERVER_STR_CONFIG_SETTER(cmd_passenger_analytics_log_dir, analyticsLogDir)
286
288
  DEFINE_SERVER_STR_CONFIG_SETTER(cmd_passenger_analytics_log_user, analyticsLogUser)
287
289
  DEFINE_SERVER_STR_CONFIG_SETTER(cmd_passenger_analytics_log_group, analyticsLogGroup)
@@ -619,6 +621,16 @@ const command_rec passenger_commands[] = {
619
621
  NULL,
620
622
  RSRC_CONF,
621
623
  "The Union Station Gateway certificate."),
624
+ AP_INIT_TAKE1("UnionStationProxyAddress",
625
+ (Take1Func) cmd_union_station_proxy_address,
626
+ NULL,
627
+ RSRC_CONF,
628
+ "The address of the proxy that should be used for sending data to Union Station."),
629
+ AP_INIT_TAKE1("UnionStationProxyType",
630
+ (Take1Func) cmd_union_station_proxy_type,
631
+ NULL,
632
+ RSRC_CONF,
633
+ "The type of the proxy that should be used for sending data to Union Station."),
622
634
  AP_INIT_TAKE1("PassengerAnalyticsLogDir",
623
635
  (Take1Func) cmd_passenger_analytics_log_dir,
624
636
  NULL,
@@ -399,6 +399,8 @@ struct ServerConfig {
399
399
  string unionStationGatewayAddress;
400
400
  int unionStationGatewayPort;
401
401
  string unionStationGatewayCert;
402
+ string unionStationProxyAddress;
403
+ string unionStationProxyType;
402
404
 
403
405
  /** Directory in which analytics logs should be saved. */
404
406
  string analyticsLogDir;
@@ -421,7 +423,9 @@ struct ServerConfig {
421
423
  tempDir = getSystemTempDir();
422
424
  unionStationGatewayAddress = DEFAULT_UNION_STATION_GATEWAY_ADDRESS;
423
425
  unionStationGatewayPort = DEFAULT_UNION_STATION_GATEWAY_PORT;
424
- unionStationGatewayCert = "";
426
+ unionStationGatewayCert = string();
427
+ unionStationProxyAddress = string();
428
+ unionStationProxyType = string();
425
429
  analyticsLogUser = DEFAULT_ANALYTICS_LOG_USER;
426
430
  analyticsLogGroup = DEFAULT_ANALYTICS_LOG_GROUP;
427
431
  analyticsLogPermissions = DEFAULT_ANALYTICS_LOG_PERMISSIONS;
@@ -466,6 +470,13 @@ struct ServerConfig {
466
470
  "/passenger-analytics-logs." +
467
471
  username;
468
472
  }
473
+
474
+ if (unionStationProxyType != ""
475
+ && unionStationProxyType != "http"
476
+ && unionStationProxyType != "socks5") {
477
+ throw ConfigurationException(string("The option 'UnionStationProxyType' ") +
478
+ "may only be set to 'http' or 'socks5'.");
479
+ }
469
480
  }
470
481
  };
471
482
 
@@ -1404,6 +1404,8 @@ public:
1404
1404
  serverConfig.unionStationGatewayAddress,
1405
1405
  serverConfig.unionStationGatewayPort,
1406
1406
  serverConfig.unionStationGatewayCert,
1407
+ serverConfig.unionStationProxyAddress,
1408
+ serverConfig.unionStationProxyType,
1407
1409
  serverConfig.prestartURLs);
1408
1410
 
1409
1411
  analyticsLogger = ptr(new AnalyticsLogger(agentsStarter.getLoggingSocketAddress(),
@@ -61,6 +61,8 @@ agents_starter_start(AgentsStarter *as,
61
61
  const char *unionStationGatewayAddress,
62
62
  unsigned short unionStationGatewayPort,
63
63
  const char *unionStationGatewayCert,
64
+ const char *unionStationProxyAddress,
65
+ const char *unionStationProxyType,
64
66
  const char **prestartURLs, unsigned int prestartURLsCount,
65
67
  const AfterForkCallback afterFork,
66
68
  void *callbackArgument,
@@ -91,6 +93,8 @@ agents_starter_start(AgentsStarter *as,
91
93
  unionStationGatewayAddress,
92
94
  unionStationGatewayPort,
93
95
  unionStationGatewayCert,
96
+ unionStationProxyAddress,
97
+ unionStationProxyType,
94
98
  setOfprestartURLs,
95
99
  afterForkFunctionObject);
96
100
  return 1;
@@ -61,6 +61,8 @@ int agents_starter_start(AgentsStarter *as,
61
61
  const char *unionStationGatewayAddress,
62
62
  unsigned short unionStationGatewayPort,
63
63
  const char *unionStationGatewayCert,
64
+ const char *unionStationProxyAddress,
65
+ const char *unionStationProxyType,
64
66
  const char **prestartURLs, unsigned int prestartURLsCount,
65
67
  const AfterForkCallback afterFork,
66
68
  void *callbackArgument,
@@ -384,6 +384,8 @@ public:
384
384
  const string &unionStationGatewayAddress,
385
385
  unsigned short unionStationGatewayPort,
386
386
  const string &unionStationGatewayCert,
387
+ const string &unionStationProxyAddress,
388
+ const string &unionStationProxyType,
387
389
  const set<string> &prestartURLs,
388
390
  const function<void ()> &afterFork = function<void ()>())
389
391
  {
@@ -425,6 +427,8 @@ public:
425
427
  .set ("union_station_gateway_address", unionStationGatewayAddress)
426
428
  .setInt ("union_station_gateway_port", unionStationGatewayPort)
427
429
  .set ("union_station_gateway_cert", realUnionStationGatewayCert)
430
+ .set ("union_station_proxy_address", unionStationProxyAddress)
431
+ .set ("union_station_proxy_type", unionStationProxyType)
428
432
  .set ("prestart_urls", serializePrestartURLs(prestartURLs));
429
433
 
430
434
  SocketPair fds;
@@ -26,7 +26,7 @@
26
26
  #define _PASSENGER_CONSTANTS_H_
27
27
 
28
28
  /* Don't forget to update lib/phusion_passenger.rb too. */
29
- #define PASSENGER_VERSION "3.0.8"
29
+ #define PASSENGER_VERSION "3.0.9"
30
30
 
31
31
  #define FEEDBACK_FD 3
32
32
 
@@ -26,6 +26,8 @@
26
26
  #define _PASSENGER_LOGGING_H_
27
27
 
28
28
  #include <boost/shared_ptr.hpp>
29
+ #include <boost/noncopyable.hpp>
30
+ #include <oxt/thread.hpp>
29
31
  #include <oxt/system_calls.hpp>
30
32
  #include <oxt/backtrace.hpp>
31
33
 
@@ -38,21 +40,23 @@
38
40
  #include <pthread.h>
39
41
  #include <string>
40
42
  #include <map>
43
+ #include <stdexcept>
41
44
  #include <ostream>
42
45
  #include <sstream>
43
46
  #include <cstdio>
44
47
  #include <ctime>
45
48
  #include <cerrno>
46
49
 
47
- #include "RandomGenerator.h"
48
- #include "FileDescriptor.h"
49
- #include "MessageClient.h"
50
- #include "StaticString.h"
51
- #include "Exceptions.h"
52
- #include "Utils.h"
53
- #include "Utils/StrIntUtils.h"
54
- #include "Utils/MD5.h"
55
- #include "Utils/SystemTime.h"
50
+ #include <RandomGenerator.h>
51
+ #include <FileDescriptor.h>
52
+ #include <StaticString.h>
53
+ #include <Exceptions.h>
54
+ #include <Utils.h>
55
+ #include <Utils/ScopeGuard.h>
56
+ #include <Utils/MessageIO.h>
57
+ #include <Utils/StrIntUtils.h>
58
+ #include <Utils/MD5.h>
59
+ #include <Utils/SystemTime.h>
56
60
 
57
61
 
58
62
  namespace Passenger {
@@ -152,51 +156,89 @@ void setDebugFile(const char *logFile = NULL);
152
156
 
153
157
  /********** Analytics logging facilities *********/
154
158
 
155
- struct AnalyticsLoggerSharedData {
156
- boost::mutex lock;
157
- MessageClient client;
159
+ // All access to the file descriptor must be synchronized through the lock.
160
+ struct AnalyticsLoggerConnection {
161
+ mutable boost::mutex lock;
162
+ FileDescriptor fd;
158
163
 
159
- void disconnect(bool checkErrorResponse = false) {
160
- if (checkErrorResponse && client.connected()) {
161
- // Maybe the server sent us an error message and closed
162
- // the connection. Let's check.
163
- TRACE_POINT();
164
- vector<string> args;
165
- bool hasData = true;
166
-
167
- try {
168
- hasData = client.read(args);
169
- } catch (const SystemException &e) {
170
- if (e.code() != ECONNRESET) {
171
- throw;
172
- }
164
+ AnalyticsLoggerConnection(FileDescriptor _fd)
165
+ : fd(_fd)
166
+ { }
167
+
168
+ bool connected() const {
169
+ return fd != -1;
170
+ }
171
+
172
+ bool disconnect(string &errorResponse) {
173
+ if (!connected()) {
174
+ return false;
175
+ }
176
+
177
+ // The server might send an "error" array message
178
+ // just before disconnecting. Try to read it.
179
+ TRACE_POINT();
180
+ vector<string> response;
181
+ try {
182
+ while (true) {
183
+ unsigned long long timeout = 10000;
184
+ response = readArrayMessage(fd, &timeout);
173
185
  }
174
-
175
- UPDATE_TRACE_POINT();
176
- client.disconnect();
177
- if (hasData) {
178
- if (args[0] == "error") {
179
- throw IOException("The logging server responded with an error: " + args[1]);
180
- } else {
181
- throw IOException("The logging server sent an unexpected reply.");
182
- }
186
+ } catch (const TimeoutException &) {
187
+ // This means that the last message isn't an array
188
+ // message or that the server didn't send it quickly
189
+ // enough. In any case, discard whatever previous
190
+ // array messages we were able to read because they're
191
+ // guaranteed not to be the error message we're expecting.
192
+ response.clear();
193
+ } catch (const SystemException &e) {
194
+ // We treat ECONNRESET the same as EOFException.
195
+ // Other errors are treated as TimeoutException.
196
+ if (e.code() != ECONNRESET) {
197
+ response.clear();
183
198
  }
199
+ } catch (const EOFException &) {
200
+ // Do nothing. We've successfully read the last array message.
201
+ }
202
+
203
+ this_thread::disable_interruption di;
204
+ this_thread::disable_syscall_interruption dsi;
205
+ UPDATE_TRACE_POINT();
206
+ fd.close();
207
+
208
+ if (response.size() == 2 && response[0] == "error") {
209
+ errorResponse = response[1];
210
+ return true;
184
211
  } else {
185
- client.disconnect();
212
+ return false;
186
213
  }
187
214
  }
215
+
216
+ void disconnect() {
217
+ fd.close();
218
+ }
188
219
  };
189
- typedef shared_ptr<AnalyticsLoggerSharedData> AnalyticsLoggerSharedDataPtr;
220
+
221
+ typedef shared_ptr<AnalyticsLoggerConnection> AnalyticsLoggerConnectionPtr;
222
+
223
+
224
+ enum ExceptionHandlingMode {
225
+ PRINT,
226
+ THROW,
227
+ IGNORE
228
+ };
229
+
190
230
 
191
231
  class AnalyticsLog {
192
232
  private:
193
233
  static const int INT64_STR_BUFSIZE = 22; // Long enough for a 64-bit number.
194
-
195
- AnalyticsLoggerSharedDataPtr sharedData;
196
- string txnId;
197
- string groupName;
198
- string category;
199
- string unionStationKey;
234
+ static const unsigned long long IO_TIMEOUT = 5000000; // In microseconds.
235
+
236
+ const AnalyticsLoggerConnectionPtr connection;
237
+ const string txnId;
238
+ const string groupName;
239
+ const string category;
240
+ const string unionStationKey;
241
+ const ExceptionHandlingMode exceptionHandlingMode;
200
242
  bool shouldFlushToDiskAfterClose;
201
243
 
202
244
  /**
@@ -227,68 +269,135 @@ private:
227
269
  return buffer + 1;
228
270
  }
229
271
 
230
- public:
231
- AnalyticsLog() { }
232
-
233
- AnalyticsLog(const AnalyticsLoggerSharedDataPtr &sharedData, const string &txnId,
234
- const string &groupName, const string &category, const string &unionStationKey)
235
- {
236
- this->sharedData = sharedData;
237
- this->txnId = txnId;
238
- this->groupName = groupName;
239
- this->category = category;
240
- this->unionStationKey = unionStationKey;
241
- shouldFlushToDiskAfterClose = false;
272
+ template<typename ExceptionType>
273
+ void handleException(const ExceptionType &e) {
274
+ switch (exceptionHandlingMode) {
275
+ case THROW:
276
+ throw e;
277
+ case PRINT:
278
+ try {
279
+ const tracable_exception &te =
280
+ dynamic_cast<const tracable_exception &>(e);
281
+ P_WARN(te.what() << "\n" << te.backtrace());
282
+ } catch (const bad_cast &) {
283
+ P_WARN(e.what());
284
+ }
285
+ break;
286
+ default:
287
+ break;
288
+ }
242
289
  }
243
290
 
291
+ public:
292
+ AnalyticsLog()
293
+ : exceptionHandlingMode(PRINT)
294
+ { }
295
+
296
+ AnalyticsLog(const AnalyticsLoggerConnectionPtr &_connection,
297
+ const string &_txnId,
298
+ const string &_groupName,
299
+ const string &_category,
300
+ const string &_unionStationKey,
301
+ ExceptionHandlingMode _exceptionHandlingMode = PRINT)
302
+ : connection(_connection),
303
+ txnId(_txnId),
304
+ groupName(_groupName),
305
+ category(_category),
306
+ unionStationKey(_unionStationKey),
307
+ exceptionHandlingMode(_exceptionHandlingMode),
308
+ shouldFlushToDiskAfterClose(false)
309
+ { }
310
+
244
311
  ~AnalyticsLog() {
245
- if (sharedData != NULL) {
246
- lock_guard<boost::mutex> l(sharedData->lock);
247
- if (sharedData->client.connected()) {
248
- try {
249
- char timestamp[2 * sizeof(unsigned long long) + 1];
250
- integerToHexatri<unsigned long long>(SystemTime::getUsec(),
251
- timestamp);
252
- sharedData->client.write("closeTransaction",
253
- txnId.c_str(), timestamp, NULL);
254
- } catch (const SystemException &e) {
255
- if (e.code() == EPIPE || e.code() == ECONNRESET) {
256
- TRACE_POINT();
257
- sharedData->disconnect(true);
258
- } else {
259
- throw;
260
- }
261
- }
262
-
263
- if (shouldFlushToDiskAfterClose) {
264
- vector<string> args;
265
- sharedData->client.write("flush", NULL);
266
- sharedData->client.read(args);
267
- }
312
+ TRACE_POINT();
313
+ if (connection == NULL) {
314
+ return;
315
+ }
316
+ lock_guard<boost::mutex> l(connection->lock);
317
+ if (!connection->connected()) {
318
+ return;
319
+ }
320
+
321
+ char timestamp[2 * sizeof(unsigned long long) + 1];
322
+ integerToHexatri<unsigned long long>(SystemTime::getUsec(),
323
+ timestamp);
324
+
325
+ UPDATE_TRACE_POINT();
326
+ ScopeGuard guard(boost::bind(&AnalyticsLoggerConnection::disconnect,
327
+ connection.get()));
328
+ try {
329
+ unsigned long long timeout = IO_TIMEOUT;
330
+ writeArrayMessage(connection->fd, &timeout,
331
+ "closeTransaction",
332
+ txnId.c_str(),
333
+ timestamp,
334
+ NULL);
335
+
336
+ if (shouldFlushToDiskAfterClose) {
337
+ UPDATE_TRACE_POINT();
338
+ timeout = IO_TIMEOUT;
339
+ writeArrayMessage(connection->fd, &timeout,
340
+ "flush", NULL);
341
+ readArrayMessage(connection->fd, &timeout);
342
+ }
343
+ guard.clear();
344
+ } catch (const SystemException &e) {
345
+ string errorResponse;
346
+
347
+ UPDATE_TRACE_POINT();
348
+ guard.clear();
349
+ if (connection->disconnect(errorResponse)) {
350
+ handleException(IOException(
351
+ string("Logging agent disconnected with error: ") +
352
+ e.what()));
353
+ } else {
354
+ handleException(e);
268
355
  }
269
356
  }
270
357
  }
271
358
 
272
359
  void message(const StaticString &text) {
273
- if (sharedData != NULL) {
274
- lock_guard<boost::mutex> l(sharedData->lock);
275
- if (sharedData->client.connected()) {
276
- char timestamp[2 * sizeof(unsigned long long) + 1];
277
- integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestamp);
278
- sharedData->client.write("log", txnId.c_str(),
279
- timestamp, NULL);
280
- sharedData->client.writeScalar(text);
360
+ TRACE_POINT();
361
+ if (connection == NULL) {
362
+ return;
363
+ }
364
+ lock_guard<boost::mutex> l(connection->lock);
365
+ if (!connection->connected()) {
366
+ return;
367
+ }
368
+
369
+ char timestamp[2 * sizeof(unsigned long long) + 1];
370
+ integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestamp);
371
+
372
+ UPDATE_TRACE_POINT();
373
+ ScopeGuard guard(boost::bind(&AnalyticsLoggerConnection::disconnect,
374
+ connection.get()));
375
+ try {
376
+ unsigned long long timeout = IO_TIMEOUT;
377
+ writeArrayMessage(connection->fd, &timeout,
378
+ "log",
379
+ txnId.c_str(),
380
+ timestamp,
381
+ NULL);
382
+ writeScalarMessage(connection->fd, text, &timeout);
383
+ guard.clear();
384
+ } catch (const std::exception &e) {
385
+ string errorResponse;
386
+
387
+ UPDATE_TRACE_POINT();
388
+ guard.clear();
389
+ if (connection->disconnect(errorResponse)) {
390
+ handleException(IOException(
391
+ string("Logging agent disconnected with error: ") +
392
+ e.what()));
393
+ } else {
394
+ handleException(e);
281
395
  }
282
396
  }
283
397
  }
284
398
 
285
399
  void abort(const StaticString &text) {
286
- if (sharedData != NULL) {
287
- lock_guard<boost::mutex> l(sharedData->lock);
288
- if (sharedData->client.connected()) {
289
- message("ABORT");
290
- }
291
- }
400
+ message("ABORT");
292
401
  }
293
402
 
294
403
  void flushToDiskAfterClose(bool value) {
@@ -296,7 +405,7 @@ public:
296
405
  }
297
406
 
298
407
  bool isNull() const {
299
- return sharedData == NULL;
408
+ return connection == NULL;
300
409
  }
301
410
 
302
411
  string getTxnId() const {
@@ -318,9 +427,10 @@ public:
318
427
 
319
428
  typedef shared_ptr<AnalyticsLog> AnalyticsLogPtr;
320
429
 
321
- class AnalyticsScopeLog {
430
+
431
+ class AnalyticsScopeLog: public boost::noncopyable {
322
432
  private:
323
- AnalyticsLog *log;
433
+ AnalyticsLog * const log;
324
434
  enum {
325
435
  NAME,
326
436
  GRANULAR
@@ -346,8 +456,9 @@ private:
346
456
  }
347
457
 
348
458
  public:
349
- AnalyticsScopeLog(const AnalyticsLogPtr &log, const char *name) {
350
- this->log = log.get();
459
+ AnalyticsScopeLog(const AnalyticsLogPtr &_log, const char *name)
460
+ : log(_log.get())
461
+ {
351
462
  type = NAME;
352
463
  data.name = name;
353
464
  ok = false;
@@ -373,16 +484,18 @@ public:
373
484
  }
374
485
  }
375
486
 
376
- AnalyticsScopeLog(const AnalyticsLogPtr &log, const char *beginMessage,
377
- const char *endMessage, const char *abortMessage = NULL
378
- ) {
379
- this->log = log.get();
380
- if (log != NULL) {
487
+ AnalyticsScopeLog(const AnalyticsLogPtr &_log,
488
+ const char *beginMessage,
489
+ const char *endMessage,
490
+ const char *abortMessage = NULL)
491
+ : log(_log.get())
492
+ {
493
+ if (_log != NULL) {
381
494
  type = GRANULAR;
382
495
  data.granular.endMessage = endMessage;
383
496
  data.granular.abortMessage = abortMessage;
384
497
  ok = abortMessage == NULL;
385
- log->message(beginMessage);
498
+ _log->message(beginMessage);
386
499
  }
387
500
  }
388
501
 
@@ -429,36 +542,37 @@ public:
429
542
  }
430
543
  };
431
544
 
545
+
432
546
  class AnalyticsLogger {
433
547
  private:
434
- /** A special lock type for AnalyticsLoggerSharedData that also
548
+ /** A special lock type for AnalyticsLoggerConnection that also
435
549
  * keeps a smart pointer to the data structure so that the mutex
436
550
  * is not destroyed prematurely.
437
551
  */
438
- struct SharedDataLock {
439
- AnalyticsLoggerSharedDataPtr sharedData;
552
+ struct ConnectionLock {
553
+ AnalyticsLoggerConnectionPtr connection;
440
554
  bool locked;
441
555
 
442
- SharedDataLock(const AnalyticsLoggerSharedDataPtr &d)
443
- : sharedData(d)
556
+ ConnectionLock(const AnalyticsLoggerConnectionPtr &c)
557
+ : connection(c)
444
558
  {
445
- d->lock.lock();
559
+ c->lock.lock();
446
560
  locked = true;
447
561
  }
448
562
 
449
- ~SharedDataLock() {
563
+ ~ConnectionLock() {
450
564
  if (locked) {
451
- sharedData->lock.unlock();
565
+ connection->lock.unlock();
452
566
  }
453
567
  }
454
568
 
455
- void reset(const AnalyticsLoggerSharedDataPtr &d, bool lockNow = true) {
569
+ void reset(const AnalyticsLoggerConnectionPtr &c, bool lockNow = true) {
456
570
  if (locked) {
457
- sharedData->lock.unlock();
571
+ connection->lock.unlock();
458
572
  }
459
- sharedData = d;
573
+ connection = c;
460
574
  if (lockNow) {
461
- sharedData->lock.lock();
575
+ connection->lock.lock();
462
576
  locked = true;
463
577
  } else {
464
578
  locked = false;
@@ -467,39 +581,84 @@ private:
467
581
 
468
582
  void lock() {
469
583
  assert(!locked);
470
- sharedData->lock.lock();
584
+ connection->lock.lock();
471
585
  locked = true;
472
586
  }
473
587
  };
474
588
 
475
- static const int RETRY_SLEEP = 200000; // microseconds
476
-
477
- string serverAddress;
478
- string username;
479
- string password;
480
- string nodeName;
589
+ const string serverAddress;
590
+ const string username;
591
+ const string password;
592
+ const string nodeName;
481
593
  RandomGenerator randomGenerator;
482
594
 
483
- /** Lock protecting the fields that follow, but not the contents of the shared data. */
595
+ /** Lock protecting the fields that follow, but not the
596
+ * contents of the connection object.
597
+ */
484
598
  mutable boost::mutex lock;
485
599
 
486
600
  unsigned int maxConnectTries;
487
601
  unsigned long long reconnectTimeout;
488
602
  unsigned long long nextReconnectTime;
489
- /** @invariant sharedData != NULL */
490
- AnalyticsLoggerSharedDataPtr sharedData;
603
+ /** Normally never NULL, except when constructed with the default constructor
604
+ * or if serverName is empty. In those cases the AnalyticsLogger object is
605
+ * considered unusable.
606
+ */
607
+ AnalyticsLoggerConnectionPtr connection;
608
+
609
+ static string determineNodeName(const string &givenNodeName) {
610
+ if (givenNodeName.empty()) {
611
+ return getHostName();
612
+ } else {
613
+ return givenNodeName;
614
+ }
615
+ }
616
+
617
+ static bool isNetworkError(int code) {
618
+ return code == EPIPE || code == ECONNREFUSED || code == ECONNRESET
619
+ || code == EHOSTUNREACH || code == ENETDOWN || code == ENETUNREACH
620
+ || code == ETIMEDOUT;
621
+ }
491
622
 
492
623
  bool connected() const {
493
- return sharedData->client.connected();
624
+ return connection->connected();
494
625
  }
495
626
 
496
627
  void connect() {
497
628
  TRACE_POINT();
629
+ FileDescriptor fd;
498
630
  vector<string> args;
631
+ unsigned long long timeout = 15000000;
632
+
633
+ fd = connectToServer(serverAddress);
634
+ if (!readArrayMessage(fd, args, &timeout)) {
635
+ throw IOException("The logging agent closed the connection before sending a version identifier.");
636
+ }
637
+ if (args.size() != 2 || args[0] != "version") {
638
+ throw IOException("The logging agent server didn't sent a valid version identifier.");
639
+ }
640
+ if (args[1] != "1") {
641
+ string message = string("Unsupported logging agent protocol version ") +
642
+ args[1] + ".";
643
+ throw IOException(message);
644
+ }
645
+
646
+ UPDATE_TRACE_POINT();
647
+ writeScalarMessage(fd, username, &timeout);
648
+ writeScalarMessage(fd, password, &timeout);
649
+
650
+ UPDATE_TRACE_POINT();
651
+ if (!readArrayMessage(fd, args, &timeout)) {
652
+ throw IOException("The logging agent did not send an authentication response.");
653
+ } else if (args.size() != 1) {
654
+ throw IOException("The authentication response that the logging agent sent is not valid.");
655
+ } else if (args[0] != "ok") {
656
+ throw SecurityException("The logging agent server denied authentication: " + args[0]);
657
+ }
499
658
 
500
- sharedData->client.connect(serverAddress, username, password);
501
- sharedData->client.write("init", nodeName.c_str(), NULL);
502
- if (!sharedData->client.read(args)) {
659
+ UPDATE_TRACE_POINT();
660
+ writeArrayMessage(fd, &timeout, "init", nodeName.c_str(), NULL);
661
+ if (!readArrayMessage(fd, args, &timeout)) {
503
662
  throw SystemException("Cannot connect to logging server", ECONNREFUSED);
504
663
  } else if (args.size() != 1) {
505
664
  throw IOException("Logging server returned an invalid reply for the 'init' command");
@@ -509,58 +668,48 @@ private:
509
668
  throw IOException("Logging server returned an invalid reply for the 'init' command");
510
669
  }
511
670
 
512
- // Upon a write() error we want to attempt to read() the error
513
- // message before closing the socket.
514
- sharedData->client.setAutoDisconnect(false);
515
- }
516
-
517
- void disconnect(bool checkErrorResponse = false) {
518
- sharedData->disconnect(checkErrorResponse);
519
- // We create a new SharedData here so that existing AnalyticsLog
520
- // objects still refer to the old client object and don't interfere
521
- // with any newly-established connections.
522
- sharedData.reset(new AnalyticsLoggerSharedData());
523
- }
524
-
525
- bool isNetworkError(int code) const {
526
- return code == EPIPE || code == ECONNREFUSED || code == ECONNRESET
527
- || code == EHOSTUNREACH || code == ENETDOWN || code == ENETUNREACH
528
- || code == ETIMEDOUT;
671
+ connection = make_shared<AnalyticsLoggerConnection>(fd);
529
672
  }
530
673
 
531
674
  public:
532
675
  AnalyticsLogger() { }
533
676
 
534
- AnalyticsLogger(const string &serverAddress, const string &username,
535
- const string &password, const string &nodeName = "")
677
+ AnalyticsLogger(const string &_serverAddress, const string &_username,
678
+ const string &_password, const string &_nodeName = "")
679
+ : serverAddress(_serverAddress),
680
+ username(_username),
681
+ password(_password),
682
+ nodeName(determineNodeName(_nodeName))
536
683
  {
537
- this->serverAddress = serverAddress;
538
- this->username = username;
539
- this->password = password;
540
- if (nodeName.empty()) {
541
- this->nodeName = getHostName();
542
- } else {
543
- this->nodeName = nodeName;
544
- }
545
684
  if (!serverAddress.empty()) {
546
- sharedData.reset(new AnalyticsLoggerSharedData());
685
+ connection = make_shared<AnalyticsLoggerConnection>(FileDescriptor());
547
686
  }
548
687
  if (isLocalSocketAddress(serverAddress)) {
549
688
  maxConnectTries = 10;
550
689
  } else {
551
690
  maxConnectTries = 1;
552
691
  }
553
- maxConnectTries = 10;
554
692
  reconnectTimeout = 1000000;
555
693
  nextReconnectTime = 0;
556
694
  }
557
695
 
558
- AnalyticsLogPtr newTransaction(const string &groupName, const string &category = "requests",
696
+ template<typename T>
697
+ static bool instanceof(const std::exception &e) {
698
+ try {
699
+ dynamic_cast<const T &>(e);
700
+ return true;
701
+ } catch (const bad_cast &) {
702
+ return false;
703
+ }
704
+ }
705
+
706
+ AnalyticsLogPtr newTransaction(const string &groupName,
707
+ const string &category = "requests",
559
708
  const string &unionStationKey = string(),
560
709
  const string &filters = string())
561
710
  {
562
711
  if (serverAddress.empty()) {
563
- return ptr(new AnalyticsLog());
712
+ return make_shared<AnalyticsLog>();
564
713
  }
565
714
 
566
715
  unsigned long long timestamp = SystemTime::getUsec();
@@ -593,129 +742,200 @@ public:
593
742
  integerToHexatri<unsigned long long>(timestamp, timestampStr);
594
743
 
595
744
  unique_lock<boost::mutex> l(lock);
596
- SharedDataLock sl(sharedData);
745
+ if (SystemTime::getUsec() < nextReconnectTime) {
746
+ return make_shared<AnalyticsLog>();
747
+ }
748
+ ConnectionLock cl(connection);
597
749
 
598
- if (SystemTime::getUsec() >= nextReconnectTime) {
599
- unsigned int tryCount = 0;
600
-
601
- while (tryCount < maxConnectTries) {
602
- try {
603
- if (!connected()) {
604
- TRACE_POINT();
605
- connect();
606
- }
607
- sharedData->client.write("openTransaction",
608
- txnId,
609
- groupName.c_str(),
610
- "",
611
- category.c_str(),
612
- timestampStr,
613
- unionStationKey.c_str(),
614
- "true",
615
- "true",
616
- filters.c_str(),
617
- NULL);
618
-
619
- vector<string> args;
620
- sharedData->client.read(args);
621
- if (args.size() == 2 && args[0] == "error") {
622
- disconnect();
623
- throw IOException("The logging server responded with an error: " + args[1]);
624
- } else if (args.empty() || args[0] != "ok") {
625
- disconnect();
626
- throw IOException("The logging server sent an unexpected reply.");
627
- }
628
-
629
- return ptr(new AnalyticsLog(sharedData,
630
- string(txnId, end - txnId),
631
- groupName, category,
632
- unionStationKey));
633
- } catch (const SystemException &e) {
634
- TRACE_POINT();
635
- if (e.code() == ENOENT || isNetworkError(e.code())) {
636
- tryCount++;
637
- disconnect(true);
638
- sl.reset(sharedData, false);
639
- l.unlock();
640
- if (tryCount < maxConnectTries) {
641
- syscalls::usleep(RETRY_SLEEP);
642
- }
643
- l.lock();
644
- sl.lock();
645
- } else {
646
- disconnect();
647
- throw;
648
- }
750
+ if (!connected()) {
751
+ TRACE_POINT();
752
+ try {
753
+ connect();
754
+ cl.reset(connection);
755
+ } catch (const TimeoutException &) {
756
+ P_WARN("Timeout trying to connect to the logging agent at " << serverAddress << "; " <<
757
+ "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
758
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
759
+ return make_shared<AnalyticsLog>();
760
+ } catch (const tracable_exception &e) {
761
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
762
+ if (instanceof<IOException>(e) || instanceof<SystemException>(e)) {
763
+ P_WARN("Cannot connect to the logging agent at " << serverAddress <<
764
+ " (" << e.what() << "); will reconnect in " <<
765
+ reconnectTimeout / 1000000 << " second(s).");
766
+ return make_shared<AnalyticsLog>();
767
+ } else {
768
+ throw;
649
769
  }
770
+ }
771
+ }
772
+
773
+ ScopeGuard guard(boost::bind(
774
+ &AnalyticsLoggerConnection::disconnect,
775
+ connection.get()));
776
+ try {
777
+ unsigned long long timeout = 15000000;
778
+
779
+ writeArrayMessage(connection->fd, &timeout,
780
+ "openTransaction",
781
+ txnId,
782
+ groupName.c_str(),
783
+ "",
784
+ category.c_str(),
785
+ timestampStr,
786
+ unionStationKey.c_str(),
787
+ "true",
788
+ "true",
789
+ filters.c_str(),
790
+ NULL);
791
+
792
+ vector<string> args;
793
+ if (!readArrayMessage(connection->fd, args, &timeout)) {
794
+ P_WARN("The logging agent at " << serverAddress <<
795
+ " closed the connection (no error message given);" <<
796
+ " will reconnect in " << reconnectTimeout / 1000000 <<
797
+ " second(s).");
798
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
799
+ return make_shared<AnalyticsLog>();
800
+ } else if (args.size() == 2 && args[0] == "error") {
801
+ P_WARN("The logging agent at " << serverAddress <<
802
+ " closed the connection (error message: " << args[1] <<
803
+ "); will reconnect in " << reconnectTimeout / 1000000 <<
804
+ " second(s).");
805
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
806
+ return make_shared<AnalyticsLog>();
807
+ } else if (args.empty() || args[0] != "ok") {
808
+ P_WARN("The logging agent at " << serverAddress <<
809
+ " sent an unexpected reply;" <<
810
+ " will reconnect in " << reconnectTimeout / 1000000 <<
811
+ " second(s).");
812
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
813
+ return make_shared<AnalyticsLog>();
814
+ }
815
+
816
+ guard.clear();
817
+ return make_shared<AnalyticsLog>(connection,
818
+ string(txnId, end - txnId),
819
+ groupName, category,
820
+ unionStationKey);
821
+
822
+ } catch (const TimeoutException &) {
823
+ P_WARN("Timeout trying to communicate with the logging agent at " << serverAddress << "; " <<
824
+ "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
825
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
826
+ return make_shared<AnalyticsLog>();
827
+
828
+ } catch (const SystemException &e) {
829
+ if (e.code() == ENOENT || isNetworkError(e.code())) {
830
+ string errorResponse;
650
831
 
651
- // Failed to connect.
652
- P_WARN("Cannot connect to the logging agent (" << serverAddress << "); " <<
653
- "retrying in " << reconnectTimeout / 1000000 << " second(s).");
832
+ guard.clear();
833
+ if (connection->disconnect(errorResponse)) {
834
+ P_WARN("The logging agent at " << serverAddress <<
835
+ " closed the connection (error message: " << errorResponse <<
836
+ "); will reconnect in " << reconnectTimeout / 1000000 <<
837
+ " second(s).");
838
+ } else {
839
+ P_WARN("The logging agent at " << serverAddress <<
840
+ " closed the connection (no error message given);" <<
841
+ " will reconnect in " << reconnectTimeout / 1000000 <<
842
+ " second(s).");
843
+ }
654
844
  nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
845
+ return make_shared<AnalyticsLog>();
846
+ } else {
847
+ throw;
655
848
  }
656
849
  }
657
- return ptr(new AnalyticsLog());
658
850
  }
659
851
 
660
852
  AnalyticsLogPtr continueTransaction(const string &txnId, const string &groupName,
661
853
  const string &category = "requests", const string &unionStationKey = string())
662
854
  {
663
855
  if (serverAddress.empty() || txnId.empty()) {
664
- return ptr(new AnalyticsLog());
856
+ return make_shared<AnalyticsLog>();
665
857
  }
666
858
 
667
859
  char timestampStr[2 * sizeof(unsigned long long) + 1];
668
860
  integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestampStr);
669
861
 
670
862
  unique_lock<boost::mutex> l(lock);
671
- SharedDataLock sl(sharedData);
863
+ if (SystemTime::getUsec() < nextReconnectTime) {
864
+ return make_shared<AnalyticsLog>();
865
+ }
866
+ ConnectionLock cl(connection);
672
867
 
673
- if (SystemTime::getUsec() >= nextReconnectTime) {
674
- unsigned int tryCount = 0;
675
-
676
- while (tryCount < maxConnectTries) {
677
- try {
678
- if (!connected()) {
679
- TRACE_POINT();
680
- connect();
681
- }
682
- sharedData->client.write("openTransaction",
683
- txnId.c_str(),
684
- groupName.c_str(),
685
- "",
686
- category.c_str(),
687
- timestampStr,
688
- unionStationKey.c_str(),
689
- "true",
690
- NULL);
691
- return ptr(new AnalyticsLog(sharedData,
692
- txnId, groupName, category,
693
- unionStationKey));
694
- } catch (const SystemException &e) {
695
- TRACE_POINT();
696
- if (e.code() == EPIPE || isNetworkError(e.code())) {
697
- tryCount++;
698
- disconnect(true);
699
- sl.reset(sharedData, false);
700
- l.unlock();
701
- if (tryCount < maxConnectTries) {
702
- syscalls::usleep(RETRY_SLEEP);
703
- }
704
- l.lock();
705
- sl.lock();
706
- } else {
707
- disconnect();
708
- throw;
709
- }
868
+ if (!connected()) {
869
+ TRACE_POINT();
870
+ try {
871
+ connect();
872
+ cl.reset(connection);
873
+ } catch (const TimeoutException &) {
874
+ P_WARN("Timeout trying to connect to the logging agent at " << serverAddress << "; " <<
875
+ "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
876
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
877
+ return make_shared<AnalyticsLog>();
878
+ } catch (const tracable_exception &e) {
879
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
880
+ if (instanceof<IOException>(e) || instanceof<SystemException>(e)) {
881
+ P_WARN("Cannot connect to the logging agent at " << serverAddress <<
882
+ " (" << e.what() << "); will reconnect in " <<
883
+ reconnectTimeout / 1000000 << " second(s).");
884
+ return make_shared<AnalyticsLog>();
885
+ } else {
886
+ throw;
710
887
  }
711
888
  }
889
+ }
890
+
891
+ ScopeGuard guard(boost::bind(
892
+ &AnalyticsLoggerConnection::disconnect,
893
+ connection.get()));
894
+ try {
895
+ unsigned long long timeout = 15000000;
896
+ writeArrayMessage(connection->fd, &timeout,
897
+ "openTransaction",
898
+ txnId.c_str(),
899
+ groupName.c_str(),
900
+ "",
901
+ category.c_str(),
902
+ timestampStr,
903
+ unionStationKey.c_str(),
904
+ "true",
905
+ NULL);
906
+ guard.clear();
907
+ return make_shared<AnalyticsLog>(connection,
908
+ txnId, groupName, category,
909
+ unionStationKey);
712
910
 
713
- // Failed to connect.
714
- P_WARN("Cannot connect to the logging agent (" << serverAddress << "); " <<
715
- "retrying in " << reconnectTimeout / 1000000 << " second(s).");
911
+ } catch (const TimeoutException &) {
912
+ P_WARN("Timeout trying to communicate with the logging agent at " << serverAddress << "; " <<
913
+ "will reconnect in " << reconnectTimeout / 1000000 << " second(s).");
716
914
  nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
915
+ return make_shared<AnalyticsLog>();
916
+
917
+ } catch (const SystemException &e) {
918
+ if (e.code() == ENOENT || isNetworkError(e.code())) {
919
+ string errorResponse;
920
+
921
+ guard.clear();
922
+ if (connection->disconnect(errorResponse)) {
923
+ P_WARN("The logging agent at " << serverAddress <<
924
+ " closed the connection (error message: " << errorResponse <<
925
+ "); will reconnect in " << reconnectTimeout / 1000000 <<
926
+ " second(s).");
927
+ } else {
928
+ P_WARN("The logging agent at " << serverAddress <<
929
+ " closed the connection (no error message given);" <<
930
+ " will reconnect in " << reconnectTimeout / 1000000 <<
931
+ " second(s).");
932
+ }
933
+ nextReconnectTime = SystemTime::getUsec() + reconnectTimeout;
934
+ return make_shared<AnalyticsLog>();
935
+ } else {
936
+ throw;
937
+ }
717
938
  }
718
- return ptr(new AnalyticsLog());
719
939
  }
720
940
 
721
941
  void setMaxConnectTries(unsigned int value) {
@@ -746,8 +966,8 @@ public:
746
966
 
747
967
  FileDescriptor getConnection() const {
748
968
  lock_guard<boost::mutex> l(lock);
749
- lock_guard<boost::mutex> l2(sharedData->lock);
750
- return sharedData->client.getConnection();
969
+ lock_guard<boost::mutex> l2(connection->lock);
970
+ return connection->fd;
751
971
  }
752
972
 
753
973
  /**