sidekick-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +52 -0
  6. data/VERSION +1 -0
  7. data/lib/ext/README +1 -0
  8. data/lib/ext/bunny-0.6.0/LICENSE +20 -0
  9. data/lib/ext/bunny-0.6.0/README.rdoc +66 -0
  10. data/lib/ext/bunny-0.6.0/Rakefile +24 -0
  11. data/lib/ext/bunny-0.6.0/bunny.gemspec +65 -0
  12. data/lib/ext/bunny-0.6.0/examples/simple_08.rb +30 -0
  13. data/lib/ext/bunny-0.6.0/examples/simple_09.rb +30 -0
  14. data/lib/ext/bunny-0.6.0/examples/simple_ack_08.rb +33 -0
  15. data/lib/ext/bunny-0.6.0/examples/simple_ack_09.rb +33 -0
  16. data/lib/ext/bunny-0.6.0/examples/simple_consumer_08.rb +53 -0
  17. data/lib/ext/bunny-0.6.0/examples/simple_consumer_09.rb +53 -0
  18. data/lib/ext/bunny-0.6.0/examples/simple_fanout_08.rb +39 -0
  19. data/lib/ext/bunny-0.6.0/examples/simple_fanout_09.rb +39 -0
  20. data/lib/ext/bunny-0.6.0/examples/simple_headers_08.rb +40 -0
  21. data/lib/ext/bunny-0.6.0/examples/simple_headers_09.rb +40 -0
  22. data/lib/ext/bunny-0.6.0/examples/simple_publisher_08.rb +27 -0
  23. data/lib/ext/bunny-0.6.0/examples/simple_publisher_09.rb +27 -0
  24. data/lib/ext/bunny-0.6.0/examples/simple_topic_08.rb +59 -0
  25. data/lib/ext/bunny-0.6.0/examples/simple_topic_09.rb +59 -0
  26. data/lib/ext/bunny-0.6.0/lib/bunny/channel08.rb +39 -0
  27. data/lib/ext/bunny-0.6.0/lib/bunny/channel09.rb +39 -0
  28. data/lib/ext/bunny-0.6.0/lib/bunny/client08.rb +494 -0
  29. data/lib/ext/bunny-0.6.0/lib/bunny/client09.rb +460 -0
  30. data/lib/ext/bunny-0.6.0/lib/bunny/exchange08.rb +175 -0
  31. data/lib/ext/bunny-0.6.0/lib/bunny/exchange09.rb +177 -0
  32. data/lib/ext/bunny-0.6.0/lib/bunny/queue08.rb +389 -0
  33. data/lib/ext/bunny-0.6.0/lib/bunny/queue09.rb +395 -0
  34. data/lib/ext/bunny-0.6.0/lib/bunny/subscription08.rb +85 -0
  35. data/lib/ext/bunny-0.6.0/lib/bunny/subscription09.rb +85 -0
  36. data/lib/ext/bunny-0.6.0/lib/bunny.rb +87 -0
  37. data/lib/ext/bunny-0.6.0/lib/qrack/channel.rb +18 -0
  38. data/lib/ext/bunny-0.6.0/lib/qrack/client.rb +204 -0
  39. data/lib/ext/bunny-0.6.0/lib/qrack/protocol/protocol08.rb +132 -0
  40. data/lib/ext/bunny-0.6.0/lib/qrack/protocol/protocol09.rb +133 -0
  41. data/lib/ext/bunny-0.6.0/lib/qrack/protocol/spec08.rb +823 -0
  42. data/lib/ext/bunny-0.6.0/lib/qrack/protocol/spec09.rb +521 -0
  43. data/lib/ext/bunny-0.6.0/lib/qrack/qrack08.rb +23 -0
  44. data/lib/ext/bunny-0.6.0/lib/qrack/qrack09.rb +23 -0
  45. data/lib/ext/bunny-0.6.0/lib/qrack/queue.rb +53 -0
  46. data/lib/ext/bunny-0.6.0/lib/qrack/subscription.rb +102 -0
  47. data/lib/ext/bunny-0.6.0/lib/qrack/transport/buffer08.rb +276 -0
  48. data/lib/ext/bunny-0.6.0/lib/qrack/transport/buffer09.rb +276 -0
  49. data/lib/ext/bunny-0.6.0/lib/qrack/transport/frame08.rb +112 -0
  50. data/lib/ext/bunny-0.6.0/lib/qrack/transport/frame09.rb +94 -0
  51. data/lib/ext/bunny-0.6.0/spec/spec_08/bunny_spec.rb +65 -0
  52. data/lib/ext/bunny-0.6.0/spec/spec_08/connection_spec.rb +12 -0
  53. data/lib/ext/bunny-0.6.0/spec/spec_08/exchange_spec.rb +162 -0
  54. data/lib/ext/bunny-0.6.0/spec/spec_08/queue_spec.rb +206 -0
  55. data/lib/ext/bunny-0.6.0/spec/spec_09/bunny_spec.rb +65 -0
  56. data/lib/ext/bunny-0.6.0/spec/spec_09/connection_spec.rb +12 -0
  57. data/lib/ext/bunny-0.6.0/spec/spec_09/exchange_spec.rb +162 -0
  58. data/lib/ext/bunny-0.6.0/spec/spec_09/queue_spec.rb +205 -0
  59. data/lib/ext/eventmachine-0.12.10/.gitignore +14 -0
  60. data/lib/ext/eventmachine-0.12.10/README +82 -0
  61. data/lib/ext/eventmachine-0.12.10/Rakefile +374 -0
  62. data/lib/ext/eventmachine-0.12.10/docs/COPYING +60 -0
  63. data/lib/ext/eventmachine-0.12.10/docs/ChangeLog +211 -0
  64. data/lib/ext/eventmachine-0.12.10/docs/DEFERRABLES +133 -0
  65. data/lib/ext/eventmachine-0.12.10/docs/EPOLL +141 -0
  66. data/lib/ext/eventmachine-0.12.10/docs/GNU +281 -0
  67. data/lib/ext/eventmachine-0.12.10/docs/INSTALL +13 -0
  68. data/lib/ext/eventmachine-0.12.10/docs/KEYBOARD +38 -0
  69. data/lib/ext/eventmachine-0.12.10/docs/LEGAL +25 -0
  70. data/lib/ext/eventmachine-0.12.10/docs/LIGHTWEIGHT_CONCURRENCY +70 -0
  71. data/lib/ext/eventmachine-0.12.10/docs/PURE_RUBY +75 -0
  72. data/lib/ext/eventmachine-0.12.10/docs/RELEASE_NOTES +94 -0
  73. data/lib/ext/eventmachine-0.12.10/docs/SMTP +2 -0
  74. data/lib/ext/eventmachine-0.12.10/docs/SPAWNED_PROCESSES +89 -0
  75. data/lib/ext/eventmachine-0.12.10/docs/TODO +8 -0
  76. data/lib/ext/eventmachine-0.12.10/eventmachine.gemspec +40 -0
  77. data/lib/ext/eventmachine-0.12.10/examples/ex_channel.rb +43 -0
  78. data/lib/ext/eventmachine-0.12.10/examples/ex_queue.rb +2 -0
  79. data/lib/ext/eventmachine-0.12.10/examples/helper.rb +2 -0
  80. data/lib/ext/eventmachine-0.12.10/ext/binder.cpp +125 -0
  81. data/lib/ext/eventmachine-0.12.10/ext/binder.h +46 -0
  82. data/lib/ext/eventmachine-0.12.10/ext/cmain.cpp +827 -0
  83. data/lib/ext/eventmachine-0.12.10/ext/cplusplus.cpp +202 -0
  84. data/lib/ext/eventmachine-0.12.10/ext/ed.cpp +1893 -0
  85. data/lib/ext/eventmachine-0.12.10/ext/ed.h +424 -0
  86. data/lib/ext/eventmachine-0.12.10/ext/em.cpp +2282 -0
  87. data/lib/ext/eventmachine-0.12.10/ext/em.h +232 -0
  88. data/lib/ext/eventmachine-0.12.10/ext/emwin.cpp +300 -0
  89. data/lib/ext/eventmachine-0.12.10/ext/emwin.h +94 -0
  90. data/lib/ext/eventmachine-0.12.10/ext/epoll.cpp +26 -0
  91. data/lib/ext/eventmachine-0.12.10/ext/epoll.h +25 -0
  92. data/lib/ext/eventmachine-0.12.10/ext/eventmachine.h +122 -0
  93. data/lib/ext/eventmachine-0.12.10/ext/eventmachine_cpp.h +96 -0
  94. data/lib/ext/eventmachine-0.12.10/ext/extconf.rb +148 -0
  95. data/lib/ext/eventmachine-0.12.10/ext/fastfilereader/extconf.rb +83 -0
  96. data/lib/ext/eventmachine-0.12.10/ext/fastfilereader/mapper.cpp +214 -0
  97. data/lib/ext/eventmachine-0.12.10/ext/fastfilereader/mapper.h +59 -0
  98. data/lib/ext/eventmachine-0.12.10/ext/fastfilereader/rubymain.cpp +127 -0
  99. data/lib/ext/eventmachine-0.12.10/ext/files.cpp +94 -0
  100. data/lib/ext/eventmachine-0.12.10/ext/files.h +65 -0
  101. data/lib/ext/eventmachine-0.12.10/ext/kb.cpp +81 -0
  102. data/lib/ext/eventmachine-0.12.10/ext/page.cpp +107 -0
  103. data/lib/ext/eventmachine-0.12.10/ext/page.h +51 -0
  104. data/lib/ext/eventmachine-0.12.10/ext/pipe.cpp +349 -0
  105. data/lib/ext/eventmachine-0.12.10/ext/project.h +151 -0
  106. data/lib/ext/eventmachine-0.12.10/ext/rubymain.cpp +1166 -0
  107. data/lib/ext/eventmachine-0.12.10/ext/sigs.cpp +89 -0
  108. data/lib/ext/eventmachine-0.12.10/ext/sigs.h +32 -0
  109. data/lib/ext/eventmachine-0.12.10/ext/ssl.cpp +460 -0
  110. data/lib/ext/eventmachine-0.12.10/ext/ssl.h +94 -0
  111. data/lib/ext/eventmachine-0.12.10/java/.classpath +8 -0
  112. data/lib/ext/eventmachine-0.12.10/java/.project +17 -0
  113. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/EmReactor.java +570 -0
  114. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  115. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/EventableChannel.java +69 -0
  116. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/EventableDatagramChannel.java +189 -0
  117. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/EventableSocketChannel.java +364 -0
  118. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/Application.java +194 -0
  119. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/Connection.java +74 -0
  120. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/ConnectionFactory.java +37 -0
  121. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +46 -0
  122. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/PeriodicTimer.java +38 -0
  123. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/application/Timer.java +54 -0
  124. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/ApplicationTest.java +109 -0
  125. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/ConnectTest.java +148 -0
  126. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/EMTest.java +80 -0
  127. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/TestDatagrams.java +53 -0
  128. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/TestServers.java +75 -0
  129. data/lib/ext/eventmachine-0.12.10/java/src/com/rubyeventmachine/tests/TestTimers.java +90 -0
  130. data/lib/ext/eventmachine-0.12.10/lib/em/buftok.rb +138 -0
  131. data/lib/ext/eventmachine-0.12.10/lib/em/callback.rb +26 -0
  132. data/lib/ext/eventmachine-0.12.10/lib/em/channel.rb +57 -0
  133. data/lib/ext/eventmachine-0.12.10/lib/em/connection.rb +564 -0
  134. data/lib/ext/eventmachine-0.12.10/lib/em/deferrable.rb +192 -0
  135. data/lib/ext/eventmachine-0.12.10/lib/em/file_watch.rb +54 -0
  136. data/lib/ext/eventmachine-0.12.10/lib/em/future.rb +61 -0
  137. data/lib/ext/eventmachine-0.12.10/lib/em/messages.rb +66 -0
  138. data/lib/ext/eventmachine-0.12.10/lib/em/process_watch.rb +44 -0
  139. data/lib/ext/eventmachine-0.12.10/lib/em/processes.rb +119 -0
  140. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/header_and_content.rb +138 -0
  141. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/httpclient.rb +263 -0
  142. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/httpclient2.rb +590 -0
  143. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/line_and_text.rb +125 -0
  144. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/linetext2.rb +161 -0
  145. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/memcache.rb +323 -0
  146. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/object_protocol.rb +45 -0
  147. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/postgres3.rb +247 -0
  148. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/saslauth.rb +175 -0
  149. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/smtpclient.rb +357 -0
  150. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/smtpserver.rb +547 -0
  151. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/socks4.rb +66 -0
  152. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/stomp.rb +200 -0
  153. data/lib/ext/eventmachine-0.12.10/lib/em/protocols/tcptest.rb +53 -0
  154. data/lib/ext/eventmachine-0.12.10/lib/em/protocols.rb +36 -0
  155. data/lib/ext/eventmachine-0.12.10/lib/em/queue.rb +61 -0
  156. data/lib/ext/eventmachine-0.12.10/lib/em/spawnable.rb +85 -0
  157. data/lib/ext/eventmachine-0.12.10/lib/em/streamer.rb +130 -0
  158. data/lib/ext/eventmachine-0.12.10/lib/em/timers.rb +56 -0
  159. data/lib/ext/eventmachine-0.12.10/lib/em/version.rb +3 -0
  160. data/lib/ext/eventmachine-0.12.10/lib/eventmachine.rb +1592 -0
  161. data/lib/ext/eventmachine-0.12.10/lib/evma/callback.rb +32 -0
  162. data/lib/ext/eventmachine-0.12.10/lib/evma/container.rb +75 -0
  163. data/lib/ext/eventmachine-0.12.10/lib/evma/factory.rb +77 -0
  164. data/lib/ext/eventmachine-0.12.10/lib/evma/protocol.rb +87 -0
  165. data/lib/ext/eventmachine-0.12.10/lib/evma/reactor.rb +48 -0
  166. data/lib/ext/eventmachine-0.12.10/lib/evma.rb +32 -0
  167. data/lib/ext/eventmachine-0.12.10/lib/jeventmachine.rb +257 -0
  168. data/lib/ext/eventmachine-0.12.10/lib/pr_eventmachine.rb +1022 -0
  169. data/lib/ext/eventmachine-0.12.10/setup.rb +1585 -0
  170. data/lib/ext/eventmachine-0.12.10/tasks/cpp.rake_example +77 -0
  171. data/lib/ext/eventmachine-0.12.10/tests/client.crt +31 -0
  172. data/lib/ext/eventmachine-0.12.10/tests/client.key +51 -0
  173. data/lib/ext/eventmachine-0.12.10/tests/test_attach.rb +126 -0
  174. data/lib/ext/eventmachine-0.12.10/tests/test_basic.rb +284 -0
  175. data/lib/ext/eventmachine-0.12.10/tests/test_channel.rb +63 -0
  176. data/lib/ext/eventmachine-0.12.10/tests/test_connection_count.rb +35 -0
  177. data/lib/ext/eventmachine-0.12.10/tests/test_defer.rb +47 -0
  178. data/lib/ext/eventmachine-0.12.10/tests/test_epoll.rb +160 -0
  179. data/lib/ext/eventmachine-0.12.10/tests/test_error_handler.rb +35 -0
  180. data/lib/ext/eventmachine-0.12.10/tests/test_errors.rb +82 -0
  181. data/lib/ext/eventmachine-0.12.10/tests/test_exc.rb +55 -0
  182. data/lib/ext/eventmachine-0.12.10/tests/test_file_watch.rb +49 -0
  183. data/lib/ext/eventmachine-0.12.10/tests/test_futures.rb +198 -0
  184. data/lib/ext/eventmachine-0.12.10/tests/test_get_sock_opt.rb +30 -0
  185. data/lib/ext/eventmachine-0.12.10/tests/test_handler_check.rb +37 -0
  186. data/lib/ext/eventmachine-0.12.10/tests/test_hc.rb +218 -0
  187. data/lib/ext/eventmachine-0.12.10/tests/test_httpclient.rb +218 -0
  188. data/lib/ext/eventmachine-0.12.10/tests/test_httpclient2.rb +153 -0
  189. data/lib/ext/eventmachine-0.12.10/tests/test_inactivity_timeout.rb +50 -0
  190. data/lib/ext/eventmachine-0.12.10/tests/test_kb.rb +60 -0
  191. data/lib/ext/eventmachine-0.12.10/tests/test_ltp.rb +182 -0
  192. data/lib/ext/eventmachine-0.12.10/tests/test_ltp2.rb +317 -0
  193. data/lib/ext/eventmachine-0.12.10/tests/test_next_tick.rb +133 -0
  194. data/lib/ext/eventmachine-0.12.10/tests/test_object_protocol.rb +37 -0
  195. data/lib/ext/eventmachine-0.12.10/tests/test_pause.rb +70 -0
  196. data/lib/ext/eventmachine-0.12.10/tests/test_pending_connect_timeout.rb +48 -0
  197. data/lib/ext/eventmachine-0.12.10/tests/test_process_watch.rb +48 -0
  198. data/lib/ext/eventmachine-0.12.10/tests/test_processes.rb +128 -0
  199. data/lib/ext/eventmachine-0.12.10/tests/test_proxy_connection.rb +92 -0
  200. data/lib/ext/eventmachine-0.12.10/tests/test_pure.rb +125 -0
  201. data/lib/ext/eventmachine-0.12.10/tests/test_queue.rb +44 -0
  202. data/lib/ext/eventmachine-0.12.10/tests/test_running.rb +42 -0
  203. data/lib/ext/eventmachine-0.12.10/tests/test_sasl.rb +72 -0
  204. data/lib/ext/eventmachine-0.12.10/tests/test_send_file.rb +242 -0
  205. data/lib/ext/eventmachine-0.12.10/tests/test_servers.rb +76 -0
  206. data/lib/ext/eventmachine-0.12.10/tests/test_smtpclient.rb +83 -0
  207. data/lib/ext/eventmachine-0.12.10/tests/test_smtpserver.rb +85 -0
  208. data/lib/ext/eventmachine-0.12.10/tests/test_spawn.rb +322 -0
  209. data/lib/ext/eventmachine-0.12.10/tests/test_ssl_args.rb +79 -0
  210. data/lib/ext/eventmachine-0.12.10/tests/test_ssl_methods.rb +50 -0
  211. data/lib/ext/eventmachine-0.12.10/tests/test_ssl_verify.rb +82 -0
  212. data/lib/ext/eventmachine-0.12.10/tests/test_timers.rb +162 -0
  213. data/lib/ext/eventmachine-0.12.10/tests/test_ud.rb +36 -0
  214. data/lib/ext/eventmachine-0.12.10/tests/testem.rb +31 -0
  215. data/lib/ext/eventmachine-0.12.10/web/whatis +7 -0
  216. data/lib/ext/misc/README +1 -0
  217. data/lib/ext/misc/indifferent_access.rb +131 -0
  218. data/lib/ext/uuidtools-2.1.1/CHANGELOG +56 -0
  219. data/lib/ext/uuidtools-2.1.1/LICENSE +20 -0
  220. data/lib/ext/uuidtools-2.1.1/README +13 -0
  221. data/lib/ext/uuidtools-2.1.1/Rakefile +48 -0
  222. data/lib/ext/uuidtools-2.1.1/lib/compat/securerandom.rb +202 -0
  223. data/lib/ext/uuidtools-2.1.1/lib/uuidtools/version.rb +35 -0
  224. data/lib/ext/uuidtools-2.1.1/lib/uuidtools.rb +618 -0
  225. data/lib/ext/uuidtools-2.1.1/spec/spec.opts +1 -0
  226. data/lib/ext/uuidtools-2.1.1/spec/spec_helper.rb +7 -0
  227. data/lib/ext/uuidtools-2.1.1/spec/uuidtools/mac_address_spec.rb +15 -0
  228. data/lib/ext/uuidtools-2.1.1/spec/uuidtools/utility_spec.rb +21 -0
  229. data/lib/ext/uuidtools-2.1.1/spec/uuidtools/uuid_creation_spec.rb +121 -0
  230. data/lib/ext/uuidtools-2.1.1/spec/uuidtools/uuid_parsing_spec.rb +127 -0
  231. data/lib/ext/uuidtools-2.1.1/tasks/benchmark.rake +38 -0
  232. data/lib/ext/uuidtools-2.1.1/tasks/clobber.rake +2 -0
  233. data/lib/ext/uuidtools-2.1.1/tasks/gem.rake +68 -0
  234. data/lib/ext/uuidtools-2.1.1/tasks/git.rake +40 -0
  235. data/lib/ext/uuidtools-2.1.1/tasks/metrics.rake +22 -0
  236. data/lib/ext/uuidtools-2.1.1/tasks/rdoc.rake +29 -0
  237. data/lib/ext/uuidtools-2.1.1/tasks/rubyforge.rake +89 -0
  238. data/lib/ext/uuidtools-2.1.1/tasks/spec.rake +64 -0
  239. data/lib/ext/uuidtools-2.1.1/website/index.html +95 -0
  240. data/lib/sidekick/client/sidekick_client.rb +46 -0
  241. data/lib/sidekick/shared/sidekick_logger.rb +14 -0
  242. data/lib/sidekick/shared/sidekick_queue_publisher.rb +91 -0
  243. data/lib/sidekick-client.rb +7 -0
  244. data/sidekick-client.gemspec +289 -0
  245. data/test/helper.rb +10 -0
  246. data/test/test_sidekick-client.rb +7 -0
  247. metadata +311 -0
@@ -0,0 +1,202 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: cplusplus.cpp
6
+ Date: 27Jul07
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+ #include "project.h"
22
+
23
+
24
+ namespace EM {
25
+ static map<unsigned long, Eventable*> Eventables;
26
+ static map<unsigned long, void(*)()> Timers;
27
+ }
28
+
29
+
30
+ /*******
31
+ EM::Run
32
+ *******/
33
+
34
+ void EM::Run (void (*start_func)())
35
+ {
36
+ evma_set_epoll (1);
37
+ evma_initialize_library (EM::Callback);
38
+ if (start_func)
39
+ AddTimer (0, start_func);
40
+ evma_run_machine();
41
+ evma_release_library();
42
+ }
43
+
44
+ /************
45
+ EM::AddTimer
46
+ ************/
47
+
48
+ void EM::AddTimer (int milliseconds, void (*func)())
49
+ {
50
+ if (func) {
51
+ const unsigned long sig = evma_install_oneshot_timer (milliseconds);
52
+ #ifndef HAVE_MAKE_PAIR
53
+ Timers.insert (map<unsigned long, void(*)()>::value_type (sig, func));
54
+ #else
55
+ Timers.insert (make_pair (sig, func));
56
+ #endif
57
+ }
58
+ }
59
+
60
+
61
+ /***************
62
+ EM::StopReactor
63
+ ***************/
64
+
65
+ void EM::StopReactor()
66
+ {
67
+ evma_stop_machine();
68
+ }
69
+
70
+
71
+ /********************
72
+ EM::Acceptor::Accept
73
+ ********************/
74
+
75
+ void EM::Acceptor::Accept (const unsigned long signature)
76
+ {
77
+ Connection *c = MakeConnection();
78
+ c->Signature = signature;
79
+ #ifndef HAVE_MAKE_PAIR
80
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (c->Signature, c));
81
+ #else
82
+ Eventables.insert (make_pair (c->Signature, c));
83
+ #endif
84
+ c->PostInit();
85
+ }
86
+
87
+ /************************
88
+ EM::Connection::SendData
89
+ ************************/
90
+
91
+ void EM::Connection::SendData (const char *data)
92
+ {
93
+ if (data)
94
+ SendData (data, strlen (data));
95
+ }
96
+
97
+
98
+ /************************
99
+ EM::Connection::SendData
100
+ ************************/
101
+
102
+ void EM::Connection::SendData (const char *data, int length)
103
+ {
104
+ evma_send_data_to_connection (Signature, data, length);
105
+ }
106
+
107
+
108
+ /*********************
109
+ EM::Connection::Close
110
+ *********************/
111
+
112
+ void EM::Connection::Close (bool afterWriting)
113
+ {
114
+ evma_close_connection (Signature, afterWriting);
115
+ }
116
+
117
+
118
+ /***************************
119
+ EM::Connection::BindConnect
120
+ ***************************/
121
+
122
+ void EM::Connection::BindConnect (const char *bind_addr, int bind_port, const char *host, int port)
123
+ {
124
+ Signature = evma_connect_to_server (bind_addr, bind_port, host, port);
125
+ #ifndef HAVE_MAKE_PAIR
126
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
127
+ #else
128
+ Eventables.insert (make_pair (Signature, this));
129
+ #endif
130
+ }
131
+
132
+ /***********************
133
+ EM::Connection::Connect
134
+ ***********************/
135
+
136
+ void EM::Connection::Connect (const char *host, int port)
137
+ {
138
+ this->BindConnect(NULL, 0, host, port);
139
+ }
140
+
141
+ /*******************
142
+ EM::Acceptor::Start
143
+ *******************/
144
+
145
+ void EM::Acceptor::Start (const char *host, int port)
146
+ {
147
+ Signature = evma_create_tcp_server (host, port);
148
+ #ifndef HAVE_MAKE_PAIR
149
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
150
+ #else
151
+ Eventables.insert (make_pair (Signature, this));
152
+ #endif
153
+ }
154
+
155
+
156
+
157
+ /************
158
+ EM::Callback
159
+ ************/
160
+
161
+ void EM::Callback (const unsigned long sig, int ev, const char *data, const unsigned long length)
162
+ {
163
+ EM::Eventable *e;
164
+ void (*f)();
165
+
166
+ switch (ev) {
167
+ case EM_TIMER_FIRED:
168
+ f = Timers [length]; // actually a binding
169
+ if (f)
170
+ (*f)();
171
+ Timers.erase (length);
172
+ break;
173
+
174
+ case EM_CONNECTION_READ:
175
+ e = EM::Eventables [sig];
176
+ e->ReceiveData (data, length);
177
+ break;
178
+
179
+ case EM_CONNECTION_COMPLETED:
180
+ e = EM::Eventables [sig];
181
+ e->ConnectionCompleted();
182
+ break;
183
+
184
+ case EM_CONNECTION_ACCEPTED:
185
+ e = EM::Eventables [sig];
186
+ e->Accept (length); // actually a binding
187
+ break;
188
+
189
+ case EM_CONNECTION_UNBOUND:
190
+ e = EM::Eventables [sig];
191
+ e->Unbind();
192
+ EM::Eventables.erase (sig);
193
+ delete e;
194
+ break;
195
+
196
+ case EM_SSL_HANDSHAKE_COMPLETED:
197
+ e = EM::Eventables [sig];
198
+ e->SslHandshakeCompleted();
199
+ break;
200
+ }
201
+ }
202
+
@@ -0,0 +1,1893 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: ed.cpp
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #include "project.h"
21
+
22
+
23
+
24
+ /********************
25
+ SetSocketNonblocking
26
+ ********************/
27
+
28
+ bool SetSocketNonblocking (SOCKET sd)
29
+ {
30
+ #ifdef OS_UNIX
31
+ int val = fcntl (sd, F_GETFL, 0);
32
+ return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false;
33
+ #endif
34
+
35
+ #ifdef OS_WIN32
36
+ #ifdef BUILD_FOR_RUBY
37
+ // 14Jun09 Ruby provides its own wrappers for ioctlsocket. On 1.8 this is a simple wrapper,
38
+ // however, 1.9 keeps its own state about the socket.
39
+ // NOTE: F_GETFL is not supported
40
+ return (fcntl (sd, F_SETFL, O_NONBLOCK) == 0) ? true : false;
41
+ #else
42
+ unsigned long one = 1;
43
+ return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
44
+ #endif
45
+ #endif
46
+ }
47
+
48
+
49
+ /****************************************
50
+ EventableDescriptor::EventableDescriptor
51
+ ****************************************/
52
+
53
+ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
54
+ bCloseNow (false),
55
+ bCloseAfterWriting (false),
56
+ MySocket (sd),
57
+ EventCallback (NULL),
58
+ bCallbackUnbind (true),
59
+ UnbindReasonCode (0),
60
+ ProxyTarget(NULL),
61
+ ProxiedFrom(NULL),
62
+ MaxOutboundBufSize(0),
63
+ MyEventMachine (em),
64
+ PendingConnectTimeout(20000000)
65
+ {
66
+ /* There are three ways to close a socket, all of which should
67
+ * automatically signal to the event machine that this object
68
+ * should be removed from the polling scheduler.
69
+ * First is a hard close, intended for bad errors or possible
70
+ * security violations. It immediately closes the connection
71
+ * and puts this object into an error state.
72
+ * Second is to set bCloseNow, which will cause the event machine
73
+ * to delete this object (and thus close the connection in our
74
+ * destructor) the next chance it gets. bCloseNow also inhibits
75
+ * the writing of new data on the socket (but not necessarily
76
+ * the reading of new data).
77
+ * The third way is to set bCloseAfterWriting, which inhibits
78
+ * the writing of new data and converts to bCloseNow as soon
79
+ * as everything in the outbound queue has been written.
80
+ * bCloseAfterWriting is really for use only by protocol handlers
81
+ * (for example, HTTP writes an HTML page and then closes the
82
+ * connection). All of the error states we generate internally
83
+ * cause an immediate close to be scheduled, which may have the
84
+ * effect of discarding outbound data.
85
+ */
86
+
87
+ if (sd == INVALID_SOCKET)
88
+ throw std::runtime_error ("bad eventable descriptor");
89
+ if (MyEventMachine == NULL)
90
+ throw std::runtime_error ("bad em in eventable descriptor");
91
+ CreatedAt = gCurrentLoopTime;
92
+
93
+ #ifdef HAVE_EPOLL
94
+ EpollEvent.events = 0;
95
+ EpollEvent.data.ptr = this;
96
+ #endif
97
+ }
98
+
99
+
100
+ /*****************************************
101
+ EventableDescriptor::~EventableDescriptor
102
+ *****************************************/
103
+
104
+ EventableDescriptor::~EventableDescriptor()
105
+ {
106
+ if (EventCallback && bCallbackUnbind)
107
+ (*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
108
+ if (ProxiedFrom) {
109
+ (*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
110
+ ProxiedFrom->StopProxy();
111
+ }
112
+ StopProxy();
113
+ Close();
114
+ }
115
+
116
+
117
+ /*************************************
118
+ EventableDescriptor::SetEventCallback
119
+ *************************************/
120
+
121
+ void EventableDescriptor::SetEventCallback (void(*cb)(const unsigned long, int, const char*, const unsigned long))
122
+ {
123
+ EventCallback = cb;
124
+ }
125
+
126
+
127
+ /**************************
128
+ EventableDescriptor::Close
129
+ **************************/
130
+
131
+ void EventableDescriptor::Close()
132
+ {
133
+ // Close the socket right now. Intended for emergencies.
134
+ if (MySocket != INVALID_SOCKET) {
135
+ shutdown (MySocket, 1);
136
+ closesocket (MySocket);
137
+ MySocket = INVALID_SOCKET;
138
+ }
139
+ }
140
+
141
+
142
+ /*********************************
143
+ EventableDescriptor::ShouldDelete
144
+ *********************************/
145
+
146
+ bool EventableDescriptor::ShouldDelete()
147
+ {
148
+ /* For use by a socket manager, which needs to know if this object
149
+ * should be removed from scheduling events and deleted.
150
+ * Has an immediate close been scheduled, or are we already closed?
151
+ * If either of these are the case, return true. In theory, the manager will
152
+ * then delete us, which in turn will make sure the socket is closed.
153
+ * Note, if bCloseAfterWriting is true, we check a virtual method to see
154
+ * if there is outbound data to write, and only request a close if there is none.
155
+ */
156
+
157
+ return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
158
+ }
159
+
160
+
161
+ /**********************************
162
+ EventableDescriptor::ScheduleClose
163
+ **********************************/
164
+
165
+ void EventableDescriptor::ScheduleClose (bool after_writing)
166
+ {
167
+ // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
168
+ if (after_writing)
169
+ bCloseAfterWriting = true;
170
+ else
171
+ bCloseNow = true;
172
+ }
173
+
174
+
175
+ /*************************************
176
+ EventableDescriptor::IsCloseScheduled
177
+ *************************************/
178
+
179
+ bool EventableDescriptor::IsCloseScheduled()
180
+ {
181
+ // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.
182
+ return (bCloseNow || bCloseAfterWriting);
183
+ }
184
+
185
+
186
+ /*******************************
187
+ EventableDescriptor::StartProxy
188
+ *******************************/
189
+
190
+ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long bufsize)
191
+ {
192
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (to));
193
+ if (ed) {
194
+ StopProxy();
195
+ ProxyTarget = ed;
196
+ ed->SetProxiedFrom(this, bufsize);
197
+ return;
198
+ }
199
+ throw std::runtime_error ("Tried to proxy to an invalid descriptor");
200
+ }
201
+
202
+
203
+ /******************************
204
+ EventableDescriptor::StopProxy
205
+ ******************************/
206
+
207
+ void EventableDescriptor::StopProxy()
208
+ {
209
+ if (ProxyTarget) {
210
+ ProxyTarget->SetProxiedFrom(NULL, 0);
211
+ ProxyTarget = NULL;
212
+ }
213
+ }
214
+
215
+
216
+ /***********************************
217
+ EventableDescriptor::SetProxiedFrom
218
+ ***********************************/
219
+
220
+ void EventableDescriptor::SetProxiedFrom(EventableDescriptor *from, const unsigned long bufsize)
221
+ {
222
+ ProxiedFrom = from;
223
+ MaxOutboundBufSize = bufsize;
224
+ }
225
+
226
+
227
+ /********************************************
228
+ EventableDescriptor::_GenericInboundDispatch
229
+ ********************************************/
230
+
231
+ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
232
+ {
233
+ assert(EventCallback);
234
+
235
+ if (ProxyTarget)
236
+ ProxyTarget->SendOutboundData(buf, size);
237
+ else
238
+ (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
239
+ }
240
+
241
+
242
+ /*********************************************
243
+ EventableDescriptor::GetPendingConnectTimeout
244
+ *********************************************/
245
+
246
+ float EventableDescriptor::GetPendingConnectTimeout()
247
+ {
248
+ return ((float)PendingConnectTimeout / 1000000);
249
+ }
250
+
251
+
252
+ /*********************************************
253
+ EventableDescriptor::SetPendingConnectTimeout
254
+ *********************************************/
255
+
256
+ int EventableDescriptor::SetPendingConnectTimeout (float value)
257
+ {
258
+ if (value > 0) {
259
+ PendingConnectTimeout = (Int64)(value * 1000000);
260
+ return 1;
261
+ }
262
+ return 0;
263
+ }
264
+
265
+
266
+ /******************************************
267
+ ConnectionDescriptor::ConnectionDescriptor
268
+ ******************************************/
269
+
270
+ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
271
+ EventableDescriptor (sd, em),
272
+ bPaused (false),
273
+ bConnectPending (false),
274
+ bNotifyReadable (false),
275
+ bNotifyWritable (false),
276
+ bWatchOnly (false),
277
+ bReadAttemptedAfterClose (false),
278
+ bWriteAttemptedAfterClose (false),
279
+ OutboundDataSize (0),
280
+ #ifdef WITH_SSL
281
+ SslBox (NULL),
282
+ bHandshakeSignaled (false),
283
+ bSslVerifyPeer (false),
284
+ bSslPeerAccepted(false),
285
+ #endif
286
+ #ifdef HAVE_KQUEUE
287
+ bGotExtraKqueueEvent(false),
288
+ #endif
289
+ bIsServer (false),
290
+ LastIo (gCurrentLoopTime),
291
+ InactivityTimeout (0)
292
+ {
293
+ // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData()
294
+ // 5May09: Moved EPOLLOUT into SetConnectPending() so it doesn't happen for attached read pipes
295
+ }
296
+
297
+
298
+ /*******************************************
299
+ ConnectionDescriptor::~ConnectionDescriptor
300
+ *******************************************/
301
+
302
+ ConnectionDescriptor::~ConnectionDescriptor()
303
+ {
304
+ // Run down any stranded outbound data.
305
+ for (size_t i=0; i < OutboundPages.size(); i++)
306
+ OutboundPages[i].Free();
307
+
308
+ #ifdef WITH_SSL
309
+ if (SslBox)
310
+ delete SslBox;
311
+ #endif
312
+ }
313
+
314
+
315
+ /**************************************************
316
+ STATIC: ConnectionDescriptor::SendDataToConnection
317
+ **************************************************/
318
+
319
+ int ConnectionDescriptor::SendDataToConnection (const unsigned long binding, const char *data, int data_length)
320
+ {
321
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
322
+ // TODO: Poor polymorphism here. We should be calling one virtual method
323
+ // instead of hacking out the runtime information of the target object.
324
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
325
+ if (cd)
326
+ return cd->SendOutboundData (data, data_length);
327
+ DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
328
+ if (ds)
329
+ return ds->SendOutboundData (data, data_length);
330
+ #ifdef OS_UNIX
331
+ PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
332
+ if (ps)
333
+ return ps->SendOutboundData (data, data_length);
334
+ #endif
335
+ return -1;
336
+ }
337
+
338
+
339
+ /*********************************************
340
+ STATIC: ConnectionDescriptor::CloseConnection
341
+ *********************************************/
342
+
343
+ void ConnectionDescriptor::CloseConnection (const unsigned long binding, bool after_writing)
344
+ {
345
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
346
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
347
+ if (ed)
348
+ ed->ScheduleClose (after_writing);
349
+ }
350
+
351
+ /***********************************************
352
+ STATIC: ConnectionDescriptor::ReportErrorStatus
353
+ ***********************************************/
354
+
355
+ int ConnectionDescriptor::ReportErrorStatus (const unsigned long binding)
356
+ {
357
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
358
+ // TODO: Poor polymorphism here. We should be calling one virtual method
359
+ // instead of hacking out the runtime information of the target object.
360
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
361
+ if (cd)
362
+ return cd->_ReportErrorStatus();
363
+ return -1;
364
+ }
365
+
366
+ /***********************************
367
+ ConnectionDescriptor::_UpdateEvents
368
+ ************************************/
369
+
370
+ void ConnectionDescriptor::_UpdateEvents()
371
+ {
372
+ _UpdateEvents(true, true);
373
+ }
374
+
375
+ void ConnectionDescriptor::_UpdateEvents(bool read, bool write)
376
+ {
377
+ if (MySocket == INVALID_SOCKET)
378
+ return;
379
+
380
+ #ifdef HAVE_EPOLL
381
+ unsigned int old = EpollEvent.events;
382
+
383
+ if (read) {
384
+ if (SelectForRead())
385
+ EpollEvent.events |= EPOLLIN;
386
+ else
387
+ EpollEvent.events &= ~EPOLLIN;
388
+ }
389
+
390
+ if (write) {
391
+ if (SelectForWrite())
392
+ EpollEvent.events |= EPOLLOUT;
393
+ else
394
+ EpollEvent.events &= ~EPOLLOUT;
395
+ }
396
+
397
+ if (old != EpollEvent.events)
398
+ MyEventMachine->Modify (this);
399
+ #endif
400
+
401
+ #ifdef HAVE_KQUEUE
402
+ if (read && SelectForRead())
403
+ MyEventMachine->ArmKqueueReader (this);
404
+ if (write && SelectForWrite())
405
+ MyEventMachine->ArmKqueueWriter (this);
406
+ #endif
407
+ }
408
+
409
+ /***************************************
410
+ ConnectionDescriptor::SetConnectPending
411
+ ****************************************/
412
+
413
+ void ConnectionDescriptor::SetConnectPending(bool f)
414
+ {
415
+ bConnectPending = f;
416
+ _UpdateEvents();
417
+ }
418
+
419
+
420
+ /**********************************
421
+ ConnectionDescriptor::SetWatchOnly
422
+ ***********************************/
423
+
424
+ void ConnectionDescriptor::SetWatchOnly(bool watching)
425
+ {
426
+ bWatchOnly = watching;
427
+ _UpdateEvents();
428
+ }
429
+
430
+
431
+ /*********************************
432
+ ConnectionDescriptor::HandleError
433
+ *********************************/
434
+
435
+ void ConnectionDescriptor::HandleError()
436
+ {
437
+ if (bWatchOnly) {
438
+ // An EPOLLHUP | EPOLLIN condition will call Read() before HandleError(), in which case the
439
+ // socket is already detached and invalid, so we don't need to do anything.
440
+ if (MySocket == INVALID_SOCKET) return;
441
+
442
+ // HandleError() is called on WatchOnly descriptors by the epoll reactor
443
+ // when it gets a EPOLLERR | EPOLLHUP. Usually this would show up as a readable and
444
+ // writable event on other reactors, so we have to fire those events ourselves.
445
+ if (bNotifyReadable) Read();
446
+ if (bNotifyWritable) Write();
447
+ } else {
448
+ ScheduleClose (false);
449
+ }
450
+ }
451
+
452
+
453
+ /***********************************
454
+ ConnectionDescriptor::ScheduleClose
455
+ ***********************************/
456
+
457
+ void ConnectionDescriptor::ScheduleClose (bool after_writing)
458
+ {
459
+ if (bWatchOnly)
460
+ throw std::runtime_error ("cannot close 'watch only' connections");
461
+
462
+ EventableDescriptor::ScheduleClose(after_writing);
463
+ }
464
+
465
+
466
+ /***************************************
467
+ ConnectionDescriptor::SetNotifyReadable
468
+ ****************************************/
469
+
470
+ void ConnectionDescriptor::SetNotifyReadable(bool readable)
471
+ {
472
+ if (!bWatchOnly)
473
+ throw std::runtime_error ("notify_readable must be on 'watch only' connections");
474
+
475
+ bNotifyReadable = readable;
476
+ _UpdateEvents(true, false);
477
+ }
478
+
479
+
480
+ /***************************************
481
+ ConnectionDescriptor::SetNotifyWritable
482
+ ****************************************/
483
+
484
+ void ConnectionDescriptor::SetNotifyWritable(bool writable)
485
+ {
486
+ if (!bWatchOnly)
487
+ throw std::runtime_error ("notify_writable must be on 'watch only' connections");
488
+
489
+ bNotifyWritable = writable;
490
+ _UpdateEvents(false, true);
491
+ }
492
+
493
+
494
+ /**************************************
495
+ ConnectionDescriptor::SendOutboundData
496
+ **************************************/
497
+
498
+ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
499
+ {
500
+ if (bWatchOnly)
501
+ throw std::runtime_error ("cannot send data on a 'watch only' connection");
502
+
503
+ if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() + length > MaxOutboundBufSize)
504
+ ProxiedFrom->Pause();
505
+
506
+ #ifdef WITH_SSL
507
+ if (SslBox) {
508
+ if (length > 0) {
509
+ int w = SslBox->PutPlaintext (data, length);
510
+ if (w < 0)
511
+ ScheduleClose (false);
512
+ else
513
+ _DispatchCiphertext();
514
+ }
515
+ // TODO: What's the correct return value?
516
+ return 1; // That's a wild guess, almost certainly wrong.
517
+ }
518
+ else
519
+ #endif
520
+ return _SendRawOutboundData (data, length);
521
+ }
522
+
523
+
524
+
525
+ /******************************************
526
+ ConnectionDescriptor::_SendRawOutboundData
527
+ ******************************************/
528
+
529
+ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
530
+ {
531
+ /* This internal method is called to schedule bytes that
532
+ * will be sent out to the remote peer.
533
+ * It's not directly accessed by the caller, who hits ::SendOutboundData,
534
+ * which may or may not filter or encrypt the caller's data before
535
+ * sending it here.
536
+ */
537
+
538
+ // Highly naive and incomplete implementation.
539
+ // There's no throttle for runaways (which should abort only this connection
540
+ // and not the whole process), and no coalescing of small pages.
541
+ // (Well, not so bad, small pages are coalesced in ::Write)
542
+
543
+ if (IsCloseScheduled())
544
+ //if (bCloseNow || bCloseAfterWriting)
545
+ return 0;
546
+
547
+ if (!data && (length > 0))
548
+ throw std::runtime_error ("bad outbound data");
549
+ char *buffer = (char *) malloc (length + 1);
550
+ if (!buffer)
551
+ throw std::runtime_error ("no allocation for outbound data");
552
+
553
+ memcpy (buffer, data, length);
554
+ buffer [length] = 0;
555
+ OutboundPages.push_back (OutboundPage (buffer, length));
556
+ OutboundDataSize += length;
557
+
558
+ _UpdateEvents(false, true);
559
+
560
+ return length;
561
+ }
562
+
563
+
564
+
565
+ /***********************************
566
+ ConnectionDescriptor::SelectForRead
567
+ ***********************************/
568
+
569
+ bool ConnectionDescriptor::SelectForRead()
570
+ {
571
+ /* A connection descriptor is always scheduled for read,
572
+ * UNLESS it's in a pending-connect state.
573
+ * On Linux, unlike Unix, a nonblocking socket on which
574
+ * connect has been called, does NOT necessarily select
575
+ * both readable and writable in case of error.
576
+ * The socket will select writable when the disposition
577
+ * of the connect is known. On the other hand, a socket
578
+ * which successfully connects and selects writable may
579
+ * indeed have some data available on it, so it will
580
+ * select readable in that case, violating expectations!
581
+ * So we will not poll for readability until the socket
582
+ * is known to be in a connected state.
583
+ */
584
+
585
+ if (bPaused)
586
+ return false;
587
+ else if (bConnectPending)
588
+ return false;
589
+ else if (bWatchOnly)
590
+ return bNotifyReadable ? true : false;
591
+ else
592
+ return true;
593
+ }
594
+
595
+
596
+ /************************************
597
+ ConnectionDescriptor::SelectForWrite
598
+ ************************************/
599
+
600
+ bool ConnectionDescriptor::SelectForWrite()
601
+ {
602
+ /* Cf the notes under SelectForRead.
603
+ * In a pending-connect state, we ALWAYS select for writable.
604
+ * In a normal state, we only select for writable when we
605
+ * have outgoing data to send.
606
+ */
607
+
608
+ if (bPaused)
609
+ return false;
610
+ else if (bConnectPending)
611
+ return true;
612
+ else if (bWatchOnly)
613
+ return bNotifyWritable ? true : false;
614
+ else
615
+ return (GetOutboundDataSize() > 0);
616
+ }
617
+
618
+ /***************************
619
+ ConnectionDescriptor::Pause
620
+ ***************************/
621
+
622
+ bool ConnectionDescriptor::Pause()
623
+ {
624
+ if (bWatchOnly)
625
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
626
+
627
+ bool old = bPaused;
628
+ bPaused = true;
629
+ _UpdateEvents();
630
+ return old == false;
631
+ }
632
+
633
+ /****************************
634
+ ConnectionDescriptor::Resume
635
+ ****************************/
636
+
637
+ bool ConnectionDescriptor::Resume()
638
+ {
639
+ if (bWatchOnly)
640
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
641
+
642
+ bool old = bPaused;
643
+ bPaused = false;
644
+ _UpdateEvents();
645
+ return old == true;
646
+ }
647
+
648
+ /**************************
649
+ ConnectionDescriptor::Read
650
+ **************************/
651
+
652
+ void ConnectionDescriptor::Read()
653
+ {
654
+ /* Read and dispatch data on a socket that has selected readable.
655
+ * It's theoretically possible to get and dispatch incoming data on
656
+ * a socket that has already been scheduled for closing or close-after-writing.
657
+ * In those cases, we'll leave it up the to protocol handler to "do the
658
+ * right thing" (which probably means to ignore the incoming data).
659
+ *
660
+ * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
661
+ * here with the socket already closed, after the process receives
662
+ * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
663
+ * was one in which network connections were doing a lot of interleaved reads
664
+ * and writes.
665
+ * Since we always write before reading (in order to keep the outbound queues
666
+ * as light as possible), I think what happened is that an interrupt caused
667
+ * the socket to be closed in ConnectionDescriptor::Write. We'll then
668
+ * come here in the same pass through the main event loop, and won't get
669
+ * cleaned up until immediately after.
670
+ * We originally asserted that the socket was valid when we got here.
671
+ * To deal properly with the possibility that we are closed when we get here,
672
+ * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
673
+ * so even though this is really clunky, I added a flag to assert that we never
674
+ * come here more than once after being closed. (FCianfrocca)
675
+ */
676
+
677
+ int sd = GetSocket();
678
+ //assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
679
+ if (sd == INVALID_SOCKET) {
680
+ assert (!bReadAttemptedAfterClose);
681
+ bReadAttemptedAfterClose = true;
682
+ return;
683
+ }
684
+
685
+ if (bWatchOnly) {
686
+ if (bNotifyReadable && EventCallback)
687
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
688
+ return;
689
+ }
690
+
691
+ LastIo = gCurrentLoopTime;
692
+
693
+ int total_bytes_read = 0;
694
+ char readbuffer [16 * 1024 + 1];
695
+
696
+ for (int i=0; i < 10; i++) {
697
+ // Don't read just one buffer and then move on. This is faster
698
+ // if there is a lot of incoming.
699
+ // But don't read indefinitely. Give other sockets a chance to run.
700
+ // NOTICE, we're reading one less than the buffer size.
701
+ // That's so we can put a guard byte at the end of what we send
702
+ // to user code.
703
+
704
+
705
+ int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
706
+ //cerr << "<R:" << r << ">";
707
+
708
+ if (r > 0) {
709
+ total_bytes_read += r;
710
+
711
+ // Add a null-terminator at the the end of the buffer
712
+ // that we will send to the callback.
713
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
714
+ // to be able to depend on this behavior, so they will have
715
+ // the option to do some things faster. Additionally it's
716
+ // a security guard against buffer overflows.
717
+ readbuffer [r] = 0;
718
+ _DispatchInboundData (readbuffer, r);
719
+ }
720
+ else if (r == 0) {
721
+ break;
722
+ }
723
+ else {
724
+ // Basically a would-block, meaning we've read everything there is to read.
725
+ break;
726
+ }
727
+
728
+ }
729
+
730
+
731
+ if (total_bytes_read == 0) {
732
+ // If we read no data on a socket that selected readable,
733
+ // it generally means the other end closed the connection gracefully.
734
+ ScheduleClose (false);
735
+ //bCloseNow = true;
736
+ }
737
+
738
+ }
739
+
740
+
741
+
742
+ /******************************************
743
+ ConnectionDescriptor::_DispatchInboundData
744
+ ******************************************/
745
+
746
+ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
747
+ {
748
+ #ifdef WITH_SSL
749
+ if (SslBox) {
750
+ SslBox->PutCiphertext (buffer, size);
751
+
752
+ int s;
753
+ char B [2048];
754
+ while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
755
+ _CheckHandshakeStatus();
756
+ B [s] = 0;
757
+ _GenericInboundDispatch(B, s);
758
+ }
759
+
760
+ // If our SSL handshake had a problem, shut down the connection.
761
+ if (s == -2) {
762
+ ScheduleClose(false);
763
+ return;
764
+ }
765
+
766
+ _CheckHandshakeStatus();
767
+ _DispatchCiphertext();
768
+ }
769
+ else {
770
+ _GenericInboundDispatch(buffer, size);
771
+ }
772
+ #endif
773
+
774
+ #ifdef WITHOUT_SSL
775
+ _GenericInboundDispatch(buffer, size);
776
+ #endif
777
+ }
778
+
779
+
780
+
781
+ /*******************************************
782
+ ConnectionDescriptor::_CheckHandshakeStatus
783
+ *******************************************/
784
+
785
+ void ConnectionDescriptor::_CheckHandshakeStatus()
786
+ {
787
+ #ifdef WITH_SSL
788
+ if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
789
+ bHandshakeSignaled = true;
790
+ if (EventCallback)
791
+ (*EventCallback)(GetBinding(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
792
+ }
793
+ #endif
794
+ }
795
+
796
+
797
+
798
+ /***************************
799
+ ConnectionDescriptor::Write
800
+ ***************************/
801
+
802
+ void ConnectionDescriptor::Write()
803
+ {
804
+ /* A socket which is in a pending-connect state will select
805
+ * writable when the disposition of the connect is known.
806
+ * At that point, check to be sure there are no errors,
807
+ * and if none, then promote the socket out of the pending
808
+ * state.
809
+ * TODO: I haven't figured out how Windows signals errors on
810
+ * unconnected sockets. Maybe it does the untraditional but
811
+ * logical thing and makes the socket selectable for error.
812
+ * If so, it's unsupported here for the time being, and connect
813
+ * errors will have to be caught by the timeout mechanism.
814
+ */
815
+
816
+ if (bConnectPending) {
817
+ int error;
818
+ socklen_t len;
819
+ len = sizeof(error);
820
+ #ifdef OS_UNIX
821
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
822
+ #endif
823
+ #ifdef OS_WIN32
824
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
825
+ #endif
826
+ if ((o == 0) && (error == 0)) {
827
+ if (EventCallback)
828
+ (*EventCallback)(GetBinding(), EM_CONNECTION_COMPLETED, "", 0);
829
+
830
+ // 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called
831
+ // from EventMachine_t::AttachFD as well.
832
+ SetConnectPending (false);
833
+ }
834
+ else
835
+ ScheduleClose (false);
836
+ //bCloseNow = true;
837
+ }
838
+ else {
839
+
840
+ if (bNotifyWritable) {
841
+ if (EventCallback)
842
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
843
+
844
+ _UpdateEvents(false, true);
845
+ return;
846
+ }
847
+
848
+ assert(!bWatchOnly);
849
+
850
+ /* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using
851
+ EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again,
852
+ we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause
853
+ ::Write to be called in a busy-loop.
854
+ */
855
+ #ifdef HAVE_KQUEUE
856
+ if (MyEventMachine->UsingKqueue()) {
857
+ if (OutboundDataSize == 0 && !bGotExtraKqueueEvent) {
858
+ bGotExtraKqueueEvent = true;
859
+ return;
860
+ } else if (OutboundDataSize > 0) {
861
+ bGotExtraKqueueEvent = false;
862
+ }
863
+ }
864
+ #endif
865
+
866
+ _WriteOutboundData();
867
+ }
868
+ }
869
+
870
+
871
+ /****************************************
872
+ ConnectionDescriptor::_WriteOutboundData
873
+ ****************************************/
874
+
875
+ void ConnectionDescriptor::_WriteOutboundData()
876
+ {
877
+ /* This is a helper function called by ::Write.
878
+ * It's possible for a socket to select writable and then no longer
879
+ * be writable by the time we get around to writing. The kernel might
880
+ * have used up its available output buffers between the select call
881
+ * and when we get here. So this condition is not an error.
882
+ *
883
+ * 20Jul07, added the same kind of protection against an invalid socket
884
+ * that is at the top of ::Read. Not entirely how this could happen in
885
+ * real life (connection-reset from the remote peer, perhaps?), but I'm
886
+ * doing it to address some reports of crashing under heavy loads.
887
+ */
888
+
889
+ int sd = GetSocket();
890
+ //assert (sd != INVALID_SOCKET);
891
+ if (sd == INVALID_SOCKET) {
892
+ assert (!bWriteAttemptedAfterClose);
893
+ bWriteAttemptedAfterClose = true;
894
+ return;
895
+ }
896
+
897
+ LastIo = gCurrentLoopTime;
898
+ size_t nbytes = 0;
899
+
900
+ #ifdef HAVE_WRITEV
901
+ int iovcnt = OutboundPages.size();
902
+ // Max of 16 outbound pages at a time
903
+ if (iovcnt > 16) iovcnt = 16;
904
+
905
+ struct iovec iov[ iovcnt ];
906
+
907
+ for(int i = 0; i < iovcnt; i++){
908
+ OutboundPage *op = &(OutboundPages[i]);
909
+ iov[i].iov_base = (void *)(op->Buffer + op->Offset);
910
+ iov[i].iov_len = op->Length - op->Offset;
911
+
912
+ nbytes += iov[i].iov_len;
913
+ }
914
+ #else
915
+ char output_buffer [16 * 1024];
916
+
917
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
918
+ OutboundPage *op = &(OutboundPages[0]);
919
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
920
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
921
+ nbytes += (op->Length - op->Offset);
922
+ op->Free();
923
+ OutboundPages.pop_front();
924
+ }
925
+ else {
926
+ int len = sizeof(output_buffer) - nbytes;
927
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
928
+ op->Offset += len;
929
+ nbytes += len;
930
+ }
931
+ }
932
+ #endif
933
+
934
+ // We should never have gotten here if there were no data to write,
935
+ // so assert that as a sanity check.
936
+ // Don't bother to make sure nbytes is less than output_buffer because
937
+ // if it were we probably would have crashed already.
938
+ assert (nbytes > 0);
939
+
940
+ assert (GetSocket() != INVALID_SOCKET);
941
+ #ifdef HAVE_WRITEV
942
+ int bytes_written = writev (GetSocket(), iov, iovcnt);
943
+ #else
944
+ int bytes_written = write (GetSocket(), output_buffer, nbytes);
945
+ #endif
946
+
947
+ bool err = false;
948
+ if (bytes_written < 0) {
949
+ err = true;
950
+ bytes_written = 0;
951
+ }
952
+
953
+ assert (bytes_written >= 0);
954
+ OutboundDataSize -= bytes_written;
955
+
956
+ if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
957
+ ProxiedFrom->Resume();
958
+
959
+ #ifdef HAVE_WRITEV
960
+ if (!err) {
961
+ unsigned int sent = bytes_written;
962
+ deque<OutboundPage>::iterator op = OutboundPages.begin();
963
+
964
+ for (int i = 0; i < iovcnt; i++) {
965
+ if (iov[i].iov_len <= sent) {
966
+ // Sent this page in full, free it.
967
+ op->Free();
968
+ OutboundPages.pop_front();
969
+
970
+ sent -= iov[i].iov_len;
971
+ } else {
972
+ // Sent part (or none) of this page, increment offset to send the remainder
973
+ op->Offset += sent;
974
+ break;
975
+ }
976
+
977
+ // Shouldn't be possible run out of pages before the loop ends
978
+ assert(op != OutboundPages.end());
979
+ *op++;
980
+ }
981
+ }
982
+ #else
983
+ if ((size_t)bytes_written < nbytes) {
984
+ int len = nbytes - bytes_written;
985
+ char *buffer = (char*) malloc (len + 1);
986
+ if (!buffer)
987
+ throw std::runtime_error ("bad alloc throwing back data");
988
+ memcpy (buffer, output_buffer + bytes_written, len);
989
+ buffer [len] = 0;
990
+ OutboundPages.push_front (OutboundPage (buffer, len));
991
+ }
992
+ #endif
993
+
994
+ _UpdateEvents(false, true);
995
+
996
+ if (err) {
997
+ #ifdef OS_UNIX
998
+ if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
999
+ #endif
1000
+ #ifdef OS_WIN32
1001
+ if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
1002
+ #endif
1003
+ Close();
1004
+ }
1005
+ }
1006
+
1007
+
1008
+ /****************************************
1009
+ ConnectionDescriptor::_ReportErrorStatus
1010
+ ****************************************/
1011
+
1012
+ int ConnectionDescriptor::_ReportErrorStatus()
1013
+ {
1014
+ int error;
1015
+ socklen_t len;
1016
+ len = sizeof(error);
1017
+ #ifdef OS_UNIX
1018
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
1019
+ #endif
1020
+ #ifdef OS_WIN32
1021
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
1022
+ #endif
1023
+ if ((o == 0) && (error == 0))
1024
+ return 0;
1025
+ else
1026
+ return 1;
1027
+ }
1028
+
1029
+
1030
+ /******************************
1031
+ ConnectionDescriptor::StartTls
1032
+ ******************************/
1033
+
1034
+ void ConnectionDescriptor::StartTls()
1035
+ {
1036
+ #ifdef WITH_SSL
1037
+ if (SslBox)
1038
+ throw std::runtime_error ("SSL/TLS already running on connection");
1039
+
1040
+ SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding());
1041
+ _DispatchCiphertext();
1042
+ #endif
1043
+
1044
+ #ifdef WITHOUT_SSL
1045
+ throw std::runtime_error ("Encryption not available on this event-machine");
1046
+ #endif
1047
+ }
1048
+
1049
+
1050
+ /*********************************
1051
+ ConnectionDescriptor::SetTlsParms
1052
+ *********************************/
1053
+
1054
+ void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer)
1055
+ {
1056
+ #ifdef WITH_SSL
1057
+ if (SslBox)
1058
+ throw std::runtime_error ("call SetTlsParms before calling StartTls");
1059
+ if (privkey_filename && *privkey_filename)
1060
+ PrivateKeyFilename = privkey_filename;
1061
+ if (certchain_filename && *certchain_filename)
1062
+ CertChainFilename = certchain_filename;
1063
+ bSslVerifyPeer = verify_peer;
1064
+ #endif
1065
+
1066
+ #ifdef WITHOUT_SSL
1067
+ throw std::runtime_error ("Encryption not available on this event-machine");
1068
+ #endif
1069
+ }
1070
+
1071
+
1072
+ /*********************************
1073
+ ConnectionDescriptor::GetPeerCert
1074
+ *********************************/
1075
+
1076
+ #ifdef WITH_SSL
1077
+ X509 *ConnectionDescriptor::GetPeerCert()
1078
+ {
1079
+ if (!SslBox)
1080
+ throw std::runtime_error ("SSL/TLS not running on this connection");
1081
+ return SslBox->GetPeerCert();
1082
+ }
1083
+ #endif
1084
+
1085
+
1086
+ /***********************************
1087
+ ConnectionDescriptor::VerifySslPeer
1088
+ ***********************************/
1089
+
1090
+ #ifdef WITH_SSL
1091
+ bool ConnectionDescriptor::VerifySslPeer(const char *cert)
1092
+ {
1093
+ bSslPeerAccepted = false;
1094
+
1095
+ if (EventCallback)
1096
+ (*EventCallback)(GetBinding(), EM_SSL_VERIFY, cert, strlen(cert));
1097
+
1098
+ return bSslPeerAccepted;
1099
+ }
1100
+ #endif
1101
+
1102
+
1103
+ /***********************************
1104
+ ConnectionDescriptor::AcceptSslPeer
1105
+ ***********************************/
1106
+
1107
+ #ifdef WITH_SSL
1108
+ void ConnectionDescriptor::AcceptSslPeer()
1109
+ {
1110
+ bSslPeerAccepted = true;
1111
+ }
1112
+ #endif
1113
+
1114
+
1115
+ /*****************************************
1116
+ ConnectionDescriptor::_DispatchCiphertext
1117
+ *****************************************/
1118
+
1119
+ #ifdef WITH_SSL
1120
+ void ConnectionDescriptor::_DispatchCiphertext()
1121
+ {
1122
+ assert (SslBox);
1123
+
1124
+
1125
+ char BigBuf [2048];
1126
+ bool did_work;
1127
+
1128
+ do {
1129
+ did_work = false;
1130
+
1131
+ // try to drain ciphertext
1132
+ while (SslBox->CanGetCiphertext()) {
1133
+ int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf));
1134
+ assert (r > 0);
1135
+ _SendRawOutboundData (BigBuf, r);
1136
+ did_work = true;
1137
+ }
1138
+
1139
+ // Pump the SslBox, in case it has queued outgoing plaintext
1140
+ // This will return >0 if data was written,
1141
+ // 0 if no data was written, and <0 if there was a fatal error.
1142
+ bool pump;
1143
+ do {
1144
+ pump = false;
1145
+ int w = SslBox->PutPlaintext (NULL, 0);
1146
+ if (w > 0) {
1147
+ did_work = true;
1148
+ pump = true;
1149
+ }
1150
+ else if (w < 0)
1151
+ ScheduleClose (false);
1152
+ } while (pump);
1153
+
1154
+ // try to put plaintext. INCOMPLETE, doesn't belong here?
1155
+ // In SendOutboundData, we're spooling plaintext directly
1156
+ // into SslBox. That may be wrong, we may need to buffer it
1157
+ // up here!
1158
+ /*
1159
+ const char *ptr;
1160
+ int ptr_length;
1161
+ while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) {
1162
+ assert (ptr && (ptr_length > 0));
1163
+ int w = SslMachine.PutPlaintext (ptr, ptr_length);
1164
+ if (w > 0) {
1165
+ OutboundPlaintext.DiscardBytes (w);
1166
+ did_work = true;
1167
+ }
1168
+ else
1169
+ break;
1170
+ }
1171
+ */
1172
+
1173
+ } while (did_work);
1174
+
1175
+ }
1176
+ #endif
1177
+
1178
+
1179
+
1180
+ /*******************************
1181
+ ConnectionDescriptor::Heartbeat
1182
+ *******************************/
1183
+
1184
+ void ConnectionDescriptor::Heartbeat()
1185
+ {
1186
+ /* Only allow a certain amount of time to go by while waiting
1187
+ * for a pending connect. If it expires, then kill the socket.
1188
+ * For a connected socket, close it if its inactivity timer
1189
+ * has expired.
1190
+ */
1191
+
1192
+ if (bConnectPending) {
1193
+ if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
1194
+ ScheduleClose (false);
1195
+ //bCloseNow = true;
1196
+ }
1197
+ else {
1198
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1199
+ ScheduleClose (false);
1200
+ //bCloseNow = true;
1201
+ }
1202
+ }
1203
+
1204
+
1205
+ /****************************************
1206
+ LoopbreakDescriptor::LoopbreakDescriptor
1207
+ ****************************************/
1208
+
1209
+ LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em):
1210
+ EventableDescriptor (sd, parent_em)
1211
+ {
1212
+ /* This is really bad and ugly. Change someday if possible.
1213
+ * We have to know about an event-machine (probably the one that owns us),
1214
+ * so we can pass newly-created connections to it.
1215
+ */
1216
+
1217
+ bCallbackUnbind = false;
1218
+
1219
+ #ifdef HAVE_EPOLL
1220
+ EpollEvent.events = EPOLLIN;
1221
+ #endif
1222
+ #ifdef HAVE_KQUEUE
1223
+ MyEventMachine->ArmKqueueReader (this);
1224
+ #endif
1225
+ }
1226
+
1227
+
1228
+
1229
+
1230
+ /*************************
1231
+ LoopbreakDescriptor::Read
1232
+ *************************/
1233
+
1234
+ void LoopbreakDescriptor::Read()
1235
+ {
1236
+ // TODO, refactor, this code is probably in the wrong place.
1237
+ assert (MyEventMachine);
1238
+ MyEventMachine->_ReadLoopBreaker();
1239
+ }
1240
+
1241
+
1242
+ /**************************
1243
+ LoopbreakDescriptor::Write
1244
+ **************************/
1245
+
1246
+ void LoopbreakDescriptor::Write()
1247
+ {
1248
+ // Why are we here?
1249
+ throw std::runtime_error ("bad code path in loopbreak");
1250
+ }
1251
+
1252
+ /**************************************
1253
+ AcceptorDescriptor::AcceptorDescriptor
1254
+ **************************************/
1255
+
1256
+ AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em):
1257
+ EventableDescriptor (sd, parent_em)
1258
+ {
1259
+ #ifdef HAVE_EPOLL
1260
+ EpollEvent.events = EPOLLIN;
1261
+ #endif
1262
+ #ifdef HAVE_KQUEUE
1263
+ MyEventMachine->ArmKqueueReader (this);
1264
+ #endif
1265
+ }
1266
+
1267
+
1268
+ /***************************************
1269
+ AcceptorDescriptor::~AcceptorDescriptor
1270
+ ***************************************/
1271
+
1272
+ AcceptorDescriptor::~AcceptorDescriptor()
1273
+ {
1274
+ }
1275
+
1276
+ /****************************************
1277
+ STATIC: AcceptorDescriptor::StopAcceptor
1278
+ ****************************************/
1279
+
1280
+ void AcceptorDescriptor::StopAcceptor (const unsigned long binding)
1281
+ {
1282
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
1283
+ AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
1284
+ if (ad)
1285
+ ad->ScheduleClose (false);
1286
+ else
1287
+ throw std::runtime_error ("failed to close nonexistent acceptor");
1288
+ }
1289
+
1290
+
1291
+ /************************
1292
+ AcceptorDescriptor::Read
1293
+ ************************/
1294
+
1295
+ void AcceptorDescriptor::Read()
1296
+ {
1297
+ /* Accept up to a certain number of sockets on the listening connection.
1298
+ * Don't try to accept all that are present, because this would allow a DoS attack
1299
+ * in which no data were ever read or written. We should accept more than one,
1300
+ * if available, to keep the partially accepted sockets from backing up in the kernel.
1301
+ */
1302
+
1303
+ /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
1304
+ * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
1305
+ * and then block when we call accept. For example, the other end resets the connection after
1306
+ * the socket selects readable and before we call accept. The kernel will remove the dead
1307
+ * socket from the accept queue. If the accept queue is now empty, accept will block.
1308
+ */
1309
+
1310
+
1311
+ struct sockaddr_in pin;
1312
+ socklen_t addrlen = sizeof (pin);
1313
+
1314
+ for (int i=0; i < 10; i++) {
1315
+ int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
1316
+ if (sd == INVALID_SOCKET) {
1317
+ // This breaks the loop when we've accepted everything on the kernel queue,
1318
+ // up to 10 new connections. But what if the *first* accept fails?
1319
+ // Does that mean anything serious is happening, beyond the situation
1320
+ // described in the note above?
1321
+ break;
1322
+ }
1323
+
1324
+ // Set the newly-accepted socket non-blocking.
1325
+ // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
1326
+ // attribute that we applied to the acceptor socket into the accepted one.
1327
+ if (!SetSocketNonblocking (sd)) {
1328
+ //int val = fcntl (sd, F_GETFL, 0);
1329
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
1330
+ shutdown (sd, 1);
1331
+ closesocket (sd);
1332
+ continue;
1333
+ }
1334
+
1335
+
1336
+ // Disable slow-start (Nagle algorithm). Eventually make this configurable.
1337
+ int one = 1;
1338
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
1339
+
1340
+
1341
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
1342
+ if (!cd)
1343
+ throw std::runtime_error ("no newly accepted connection");
1344
+ cd->SetServerMode();
1345
+ if (EventCallback) {
1346
+ (*EventCallback) (GetBinding(), EM_CONNECTION_ACCEPTED, NULL, cd->GetBinding());
1347
+ }
1348
+ #ifdef HAVE_EPOLL
1349
+ cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
1350
+ #endif
1351
+ assert (MyEventMachine);
1352
+ MyEventMachine->Add (cd);
1353
+ #ifdef HAVE_KQUEUE
1354
+ if (cd->SelectForWrite())
1355
+ MyEventMachine->ArmKqueueWriter (cd);
1356
+ MyEventMachine->ArmKqueueReader (cd);
1357
+ #endif
1358
+ }
1359
+
1360
+ }
1361
+
1362
+
1363
+ /*************************
1364
+ AcceptorDescriptor::Write
1365
+ *************************/
1366
+
1367
+ void AcceptorDescriptor::Write()
1368
+ {
1369
+ // Why are we here?
1370
+ throw std::runtime_error ("bad code path in acceptor");
1371
+ }
1372
+
1373
+
1374
+ /*****************************
1375
+ AcceptorDescriptor::Heartbeat
1376
+ *****************************/
1377
+
1378
+ void AcceptorDescriptor::Heartbeat()
1379
+ {
1380
+ // No-op
1381
+ }
1382
+
1383
+
1384
+ /*******************************
1385
+ AcceptorDescriptor::GetSockname
1386
+ *******************************/
1387
+
1388
+ bool AcceptorDescriptor::GetSockname (struct sockaddr *s)
1389
+ {
1390
+ bool ok = false;
1391
+ if (s) {
1392
+ socklen_t len = sizeof(*s);
1393
+ int gp = getsockname (GetSocket(), s, &len);
1394
+ if (gp == 0)
1395
+ ok = true;
1396
+ }
1397
+ return ok;
1398
+ }
1399
+
1400
+
1401
+
1402
+ /**************************************
1403
+ DatagramDescriptor::DatagramDescriptor
1404
+ **************************************/
1405
+
1406
+ DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1407
+ EventableDescriptor (sd, parent_em),
1408
+ OutboundDataSize (0),
1409
+ LastIo (gCurrentLoopTime),
1410
+ InactivityTimeout (0)
1411
+ {
1412
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1413
+
1414
+ /* Provisionally added 19Oct07. All datagram sockets support broadcasting.
1415
+ * Until now, sending to a broadcast address would give EACCES (permission denied)
1416
+ * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order
1417
+ * to accept a packet to a broadcast address. Solaris doesn't require it. I think
1418
+ * Windows DOES require it but I'm not sure.
1419
+ *
1420
+ * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST
1421
+ * on a UDP socket in order to enable broadcasting. The reason for requiring the option
1422
+ * in the first place is so that applications don't send broadcast datagrams by mistake.
1423
+ * I imagine that could happen if a user of an application typed in an address that happened
1424
+ * to be a broadcast address on that particular subnet.
1425
+ *
1426
+ * This is provisional because someone may eventually come up with a good reason not to
1427
+ * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API
1428
+ * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T
1429
+ * EXPLICITLY SET THE OPTION.
1430
+ */
1431
+
1432
+ int oval = 1;
1433
+ setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1434
+
1435
+ #ifdef HAVE_EPOLL
1436
+ EpollEvent.events = EPOLLIN;
1437
+ #endif
1438
+ #ifdef HAVE_KQUEUE
1439
+ MyEventMachine->ArmKqueueReader (this);
1440
+ #endif
1441
+ }
1442
+
1443
+
1444
+ /***************************************
1445
+ DatagramDescriptor::~DatagramDescriptor
1446
+ ***************************************/
1447
+
1448
+ DatagramDescriptor::~DatagramDescriptor()
1449
+ {
1450
+ // Run down any stranded outbound data.
1451
+ for (size_t i=0; i < OutboundPages.size(); i++)
1452
+ OutboundPages[i].Free();
1453
+ }
1454
+
1455
+
1456
+ /*****************************
1457
+ DatagramDescriptor::Heartbeat
1458
+ *****************************/
1459
+
1460
+ void DatagramDescriptor::Heartbeat()
1461
+ {
1462
+ // Close it if its inactivity timer has expired.
1463
+
1464
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1465
+ ScheduleClose (false);
1466
+ //bCloseNow = true;
1467
+ }
1468
+
1469
+
1470
+ /************************
1471
+ DatagramDescriptor::Read
1472
+ ************************/
1473
+
1474
+ void DatagramDescriptor::Read()
1475
+ {
1476
+ int sd = GetSocket();
1477
+ assert (sd != INVALID_SOCKET);
1478
+ LastIo = gCurrentLoopTime;
1479
+
1480
+ // This is an extremely large read buffer.
1481
+ // In many cases you wouldn't expect to get any more than 4K.
1482
+ char readbuffer [16 * 1024];
1483
+
1484
+ for (int i=0; i < 10; i++) {
1485
+ // Don't read just one buffer and then move on. This is faster
1486
+ // if there is a lot of incoming.
1487
+ // But don't read indefinitely. Give other sockets a chance to run.
1488
+ // NOTICE, we're reading one less than the buffer size.
1489
+ // That's so we can put a guard byte at the end of what we send
1490
+ // to user code.
1491
+
1492
+ struct sockaddr_in sin;
1493
+ socklen_t slen = sizeof (sin);
1494
+ memset (&sin, 0, slen);
1495
+
1496
+ int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
1497
+ //cerr << "<R:" << r << ">";
1498
+
1499
+ // In UDP, a zero-length packet is perfectly legal.
1500
+ if (r >= 0) {
1501
+
1502
+ // Add a null-terminator at the the end of the buffer
1503
+ // that we will send to the callback.
1504
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
1505
+ // to be able to depend on this behavior, so they will have
1506
+ // the option to do some things faster. Additionally it's
1507
+ // a security guard against buffer overflows.
1508
+ readbuffer [r] = 0;
1509
+
1510
+
1511
+ // Set up a "temporary" return address so that callers can "reply" to us
1512
+ // from within the callback we are about to invoke. That means that ordinary
1513
+ // calls to "send_data_to_connection" (which is of course misnamed in this
1514
+ // case) will result in packets being sent back to the same place that sent
1515
+ // us this one.
1516
+ // There is a different call (evma_send_datagram) for cases where the caller
1517
+ // actually wants to send a packet somewhere else.
1518
+
1519
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1520
+ memcpy (&ReturnAddress, &sin, slen);
1521
+
1522
+ _GenericInboundDispatch(readbuffer, r);
1523
+
1524
+ }
1525
+ else {
1526
+ // Basically a would-block, meaning we've read everything there is to read.
1527
+ break;
1528
+ }
1529
+
1530
+ }
1531
+
1532
+
1533
+ }
1534
+
1535
+
1536
+ /*************************
1537
+ DatagramDescriptor::Write
1538
+ *************************/
1539
+
1540
+ void DatagramDescriptor::Write()
1541
+ {
1542
+ /* It's possible for a socket to select writable and then no longer
1543
+ * be writable by the time we get around to writing. The kernel might
1544
+ * have used up its available output buffers between the select call
1545
+ * and when we get here. So this condition is not an error.
1546
+ * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData,
1547
+ * but differs in the that the outbound data pages (received from the
1548
+ * user) are _message-structured._ That is, we send each of them out
1549
+ * one message at a time.
1550
+ * TODO, we are currently suppressing the EMSGSIZE error!!!
1551
+ */
1552
+
1553
+ int sd = GetSocket();
1554
+ assert (sd != INVALID_SOCKET);
1555
+ LastIo = gCurrentLoopTime;
1556
+
1557
+ assert (OutboundPages.size() > 0);
1558
+
1559
+ // Send out up to 10 packets, then cycle the machine.
1560
+ for (int i = 0; i < 10; i++) {
1561
+ if (OutboundPages.size() <= 0)
1562
+ break;
1563
+ OutboundPage *op = &(OutboundPages[0]);
1564
+
1565
+ // The nasty cast to (char*) is needed because Windows is brain-dead.
1566
+ int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1567
+ int e = errno;
1568
+
1569
+ OutboundDataSize -= op->Length;
1570
+ op->Free();
1571
+ OutboundPages.pop_front();
1572
+
1573
+ if (s == SOCKET_ERROR) {
1574
+ #ifdef OS_UNIX
1575
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
1576
+ #endif
1577
+ #ifdef OS_WIN32
1578
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1579
+ #endif
1580
+ Close();
1581
+ break;
1582
+ }
1583
+ }
1584
+ }
1585
+
1586
+ #ifdef HAVE_EPOLL
1587
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
1588
+ assert (MyEventMachine);
1589
+ MyEventMachine->Modify (this);
1590
+ #endif
1591
+ #ifdef HAVE_KQUEUE
1592
+ if (SelectForWrite())
1593
+ MyEventMachine->ArmKqueueWriter (this);
1594
+ #endif
1595
+ }
1596
+
1597
+
1598
+ /**********************************
1599
+ DatagramDescriptor::SelectForWrite
1600
+ **********************************/
1601
+
1602
+ bool DatagramDescriptor::SelectForWrite()
1603
+ {
1604
+ /* Changed 15Nov07, per bug report by Mark Zvillius.
1605
+ * The outbound data size will be zero if there are zero-length outbound packets,
1606
+ * so we now select writable in case the outbound page buffer is not empty.
1607
+ * Note that the superclass ShouldDelete method still checks for outbound data size,
1608
+ * which may be wrong.
1609
+ */
1610
+ //return (GetOutboundDataSize() > 0); (Original)
1611
+ return (OutboundPages.size() > 0);
1612
+ }
1613
+
1614
+
1615
+ /************************************
1616
+ DatagramDescriptor::SendOutboundData
1617
+ ************************************/
1618
+
1619
+ int DatagramDescriptor::SendOutboundData (const char *data, int length)
1620
+ {
1621
+ // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1622
+ // That means it needs to move to a common ancestor.
1623
+
1624
+ if (IsCloseScheduled())
1625
+ //if (bCloseNow || bCloseAfterWriting)
1626
+ return 0;
1627
+
1628
+ if (!data && (length > 0))
1629
+ throw std::runtime_error ("bad outbound data");
1630
+ char *buffer = (char *) malloc (length + 1);
1631
+ if (!buffer)
1632
+ throw std::runtime_error ("no allocation for outbound data");
1633
+ memcpy (buffer, data, length);
1634
+ buffer [length] = 0;
1635
+ OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress));
1636
+ OutboundDataSize += length;
1637
+
1638
+ #ifdef HAVE_EPOLL
1639
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1640
+ assert (MyEventMachine);
1641
+ MyEventMachine->Modify (this);
1642
+ #endif
1643
+ #ifdef HAVE_KQUEUE
1644
+ MyEventMachine->ArmKqueueWriter (this);
1645
+ #endif
1646
+
1647
+ return length;
1648
+ }
1649
+
1650
+
1651
+ /****************************************
1652
+ DatagramDescriptor::SendOutboundDatagram
1653
+ ****************************************/
1654
+
1655
+ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, const char *address, int port)
1656
+ {
1657
+ // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1658
+ // That means it needs to move to a common ancestor.
1659
+ // TODO: Refactor this so there's no overlap with SendOutboundData.
1660
+
1661
+ if (IsCloseScheduled())
1662
+ //if (bCloseNow || bCloseAfterWriting)
1663
+ return 0;
1664
+
1665
+ if (!address || !*address || !port)
1666
+ return 0;
1667
+
1668
+ sockaddr_in pin;
1669
+ unsigned long HostAddr;
1670
+
1671
+ HostAddr = inet_addr (address);
1672
+ if (HostAddr == INADDR_NONE) {
1673
+ // The nasty cast to (char*) is because Windows is brain-dead.
1674
+ hostent *hp = gethostbyname ((char*)address);
1675
+ if (!hp)
1676
+ return 0;
1677
+ HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
1678
+ }
1679
+
1680
+ memset (&pin, 0, sizeof(pin));
1681
+ pin.sin_family = AF_INET;
1682
+ pin.sin_addr.s_addr = HostAddr;
1683
+ pin.sin_port = htons (port);
1684
+
1685
+
1686
+ if (!data && (length > 0))
1687
+ throw std::runtime_error ("bad outbound data");
1688
+ char *buffer = (char *) malloc (length + 1);
1689
+ if (!buffer)
1690
+ throw std::runtime_error ("no allocation for outbound data");
1691
+ memcpy (buffer, data, length);
1692
+ buffer [length] = 0;
1693
+ OutboundPages.push_back (OutboundPage (buffer, length, pin));
1694
+ OutboundDataSize += length;
1695
+
1696
+ #ifdef HAVE_EPOLL
1697
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1698
+ assert (MyEventMachine);
1699
+ MyEventMachine->Modify (this);
1700
+ #endif
1701
+ #ifdef HAVE_KQUEUE
1702
+ MyEventMachine->ArmKqueueWriter (this);
1703
+ #endif
1704
+
1705
+ return length;
1706
+ }
1707
+
1708
+
1709
+ /****************************************
1710
+ STATIC: DatagramDescriptor::SendDatagram
1711
+ ****************************************/
1712
+
1713
+ int DatagramDescriptor::SendDatagram (const unsigned long binding, const char *data, int length, const char *address, int port)
1714
+ {
1715
+ DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
1716
+ if (dd)
1717
+ return dd->SendOutboundDatagram (data, length, address, port);
1718
+ else
1719
+ return -1;
1720
+ }
1721
+
1722
+
1723
+ /*********************************
1724
+ ConnectionDescriptor::GetPeername
1725
+ *********************************/
1726
+
1727
+ bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1728
+ {
1729
+ bool ok = false;
1730
+ if (s) {
1731
+ socklen_t len = sizeof(*s);
1732
+ int gp = getpeername (GetSocket(), s, &len);
1733
+ if (gp == 0)
1734
+ ok = true;
1735
+ }
1736
+ return ok;
1737
+ }
1738
+
1739
+ /*********************************
1740
+ ConnectionDescriptor::GetSockname
1741
+ *********************************/
1742
+
1743
+ bool ConnectionDescriptor::GetSockname (struct sockaddr *s)
1744
+ {
1745
+ bool ok = false;
1746
+ if (s) {
1747
+ socklen_t len = sizeof(*s);
1748
+ int gp = getsockname (GetSocket(), s, &len);
1749
+ if (gp == 0)
1750
+ ok = true;
1751
+ }
1752
+ return ok;
1753
+ }
1754
+
1755
+
1756
+ /**********************************************
1757
+ ConnectionDescriptor::GetCommInactivityTimeout
1758
+ **********************************************/
1759
+
1760
+ float ConnectionDescriptor::GetCommInactivityTimeout()
1761
+ {
1762
+ return ((float)InactivityTimeout / 1000000);
1763
+ }
1764
+
1765
+
1766
+ /**********************************************
1767
+ ConnectionDescriptor::SetCommInactivityTimeout
1768
+ **********************************************/
1769
+
1770
+ int ConnectionDescriptor::SetCommInactivityTimeout (float value)
1771
+ {
1772
+ if (value > 0) {
1773
+ InactivityTimeout = (Int64)(value * 1000000);
1774
+ return 1;
1775
+ }
1776
+ return 0;
1777
+ }
1778
+
1779
+ /*******************************
1780
+ DatagramDescriptor::GetPeername
1781
+ *******************************/
1782
+
1783
+ bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1784
+ {
1785
+ bool ok = false;
1786
+ if (s) {
1787
+ memset (s, 0, sizeof(struct sockaddr));
1788
+ memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1789
+ ok = true;
1790
+ }
1791
+ return ok;
1792
+ }
1793
+
1794
+ /*******************************
1795
+ DatagramDescriptor::GetSockname
1796
+ *******************************/
1797
+
1798
+ bool DatagramDescriptor::GetSockname (struct sockaddr *s)
1799
+ {
1800
+ bool ok = false;
1801
+ if (s) {
1802
+ socklen_t len = sizeof(*s);
1803
+ int gp = getsockname (GetSocket(), s, &len);
1804
+ if (gp == 0)
1805
+ ok = true;
1806
+ }
1807
+ return ok;
1808
+ }
1809
+
1810
+
1811
+
1812
+ /********************************************
1813
+ DatagramDescriptor::GetCommInactivityTimeout
1814
+ ********************************************/
1815
+
1816
+ float DatagramDescriptor::GetCommInactivityTimeout()
1817
+ {
1818
+ return ((float)InactivityTimeout / 1000000);
1819
+ }
1820
+
1821
+ /********************************************
1822
+ DatagramDescriptor::SetCommInactivityTimeout
1823
+ ********************************************/
1824
+
1825
+ int DatagramDescriptor::SetCommInactivityTimeout (float value)
1826
+ {
1827
+ if (value > 0) {
1828
+ InactivityTimeout = (Int64)(value * 1000000);
1829
+ return 1;
1830
+ }
1831
+ return 0;
1832
+ }
1833
+
1834
+
1835
+ /************************************
1836
+ InotifyDescriptor::InotifyDescriptor
1837
+ *************************************/
1838
+
1839
+ InotifyDescriptor::InotifyDescriptor (EventMachine_t *em):
1840
+ EventableDescriptor(0, em)
1841
+ {
1842
+ bCallbackUnbind = false;
1843
+
1844
+ #ifndef HAVE_INOTIFY
1845
+ throw std::runtime_error("no inotify support on this system");
1846
+ #else
1847
+
1848
+ int fd = inotify_init();
1849
+ if (fd == -1) {
1850
+ char buf[200];
1851
+ snprintf (buf, sizeof(buf)-1, "unable to create inotify descriptor: %s", strerror(errno));
1852
+ throw std::runtime_error (buf);
1853
+ }
1854
+
1855
+ MySocket = fd;
1856
+ SetSocketNonblocking(MySocket);
1857
+ #ifdef HAVE_EPOLL
1858
+ EpollEvent.events = EPOLLIN;
1859
+ #endif
1860
+
1861
+ #endif
1862
+ }
1863
+
1864
+
1865
+ /*************************************
1866
+ InotifyDescriptor::~InotifyDescriptor
1867
+ **************************************/
1868
+
1869
+ InotifyDescriptor::~InotifyDescriptor()
1870
+ {
1871
+ close(MySocket);
1872
+ MySocket = INVALID_SOCKET;
1873
+ }
1874
+
1875
+ /***********************
1876
+ InotifyDescriptor::Read
1877
+ ************************/
1878
+
1879
+ void InotifyDescriptor::Read()
1880
+ {
1881
+ assert (MyEventMachine);
1882
+ MyEventMachine->_ReadInotifyEvents();
1883
+ }
1884
+
1885
+
1886
+ /************************
1887
+ InotifyDescriptor::Write
1888
+ *************************/
1889
+
1890
+ void InotifyDescriptor::Write()
1891
+ {
1892
+ throw std::runtime_error("bad code path in inotify");
1893
+ }