trema 0.1.3

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 (560) hide show
  1. data/.mono.rant +4107 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +4 -0
  4. data/Doxyfile +1679 -0
  5. data/GPL2 +339 -0
  6. data/Gemfile +22 -0
  7. data/Gemfile.lock +71 -0
  8. data/README.md +135 -0
  9. data/Rakefile +140 -0
  10. data/Rantfile +834 -0
  11. data/VERSION +1 -0
  12. data/build.rb +32 -0
  13. data/cruise.rb +389 -0
  14. data/features/example.dumper.feature +87 -0
  15. data/features/example.learning_switch.feature +39 -0
  16. data/features/example.list_switches.feature +38 -0
  17. data/features/example.message.echo_reply.feature +26 -0
  18. data/features/example.message.echo_request.feature +25 -0
  19. data/features/example.message.features_request.feature +84 -0
  20. data/features/example.message.hello.feature +25 -0
  21. data/features/example.message.set_config.feature +27 -0
  22. data/features/example.multi_learning_switch.feature +135 -0
  23. data/features/example.packetin_filter_config.feature +91 -0
  24. data/features/example.repeater_hub.feature +49 -0
  25. data/features/example.switch_monitor.feature +39 -0
  26. data/features/packetin_filter.feature +49 -0
  27. data/features/step_definitions/kill_steps.rb +30 -0
  28. data/features/step_definitions/log_steps.rb +90 -0
  29. data/features/step_definitions/misc_steps.rb +64 -0
  30. data/features/step_definitions/off_steps.rb +30 -0
  31. data/features/step_definitions/run_steps.rb +91 -0
  32. data/features/step_definitions/send_packets_steps.rb +42 -0
  33. data/features/step_definitions/show_stats_steps.rb +43 -0
  34. data/features/step_definitions/stats_steps.rb +39 -0
  35. data/features/support/env.rb +75 -0
  36. data/features/support/hooks.rb +8 -0
  37. data/features/switch_manager.feature +35 -0
  38. data/features/trema-config.feature +68 -0
  39. data/features/trema.dump_flows.feature +25 -0
  40. data/features/trema.feature +25 -0
  41. data/features/trema.kill.feature +53 -0
  42. data/features/trema.killall.feature +30 -0
  43. data/features/trema.reset_stats.feature +14 -0
  44. data/features/trema.run.feature +46 -0
  45. data/features/trema.send_packets.feature +56 -0
  46. data/features/trema.show_stats.feature +67 -0
  47. data/features/tutorial.hello_trema.feature +27 -0
  48. data/features/tutorial.packet_in.feature +47 -0
  49. data/features/tutorial.switch_info.feature +55 -0
  50. data/ruby/.gitignore +4 -0
  51. data/ruby/blocker.rb +78 -0
  52. data/ruby/extconf.rb +71 -0
  53. data/ruby/sub-process.rb +291 -0
  54. data/ruby/trema/action-common.c +60 -0
  55. data/ruby/trema/action-common.h +42 -0
  56. data/ruby/trema/action-enqueue.c +161 -0
  57. data/ruby/trema/action-enqueue.h +40 -0
  58. data/ruby/trema/action-output.c +169 -0
  59. data/ruby/trema/action-output.h +42 -0
  60. data/ruby/trema/action-set-dl-dst.c +131 -0
  61. data/ruby/trema/action-set-dl-dst.h +44 -0
  62. data/ruby/trema/action-set-dl-src.c +131 -0
  63. data/ruby/trema/action-set-dl-src.h +44 -0
  64. data/ruby/trema/action-set-nw-dst.c +135 -0
  65. data/ruby/trema/action-set-nw-dst.h +42 -0
  66. data/ruby/trema/action-set-nw-src.c +140 -0
  67. data/ruby/trema/action-set-nw-src.h +42 -0
  68. data/ruby/trema/action-set-nw-tos.c +124 -0
  69. data/ruby/trema/action-set-nw-tos.h +42 -0
  70. data/ruby/trema/action-set-tp-dst.c +122 -0
  71. data/ruby/trema/action-set-tp-dst.h +42 -0
  72. data/ruby/trema/action-set-tp-src.c +124 -0
  73. data/ruby/trema/action-set-tp-src.h +42 -0
  74. data/ruby/trema/action-set-vlan-pcp.c +128 -0
  75. data/ruby/trema/action-set-vlan-pcp.h +42 -0
  76. data/ruby/trema/action-set-vlan-vid.c +125 -0
  77. data/ruby/trema/action-set-vlan-vid.h +42 -0
  78. data/ruby/trema/action-strip-vlan.c +81 -0
  79. data/ruby/trema/action-strip-vlan.h +42 -0
  80. data/ruby/trema/action-vendor.c +121 -0
  81. data/ruby/trema/action-vendor.h +42 -0
  82. data/ruby/trema/aggregate-stats-reply.rb +70 -0
  83. data/ruby/trema/app.rb +112 -0
  84. data/ruby/trema/barrier-reply.c +99 -0
  85. data/ruby/trema/barrier-reply.h +46 -0
  86. data/ruby/trema/barrier-request.c +108 -0
  87. data/ruby/trema/barrier-request.h +44 -0
  88. data/ruby/trema/cli.rb +269 -0
  89. data/ruby/trema/command.rb +40 -0
  90. data/ruby/trema/command/dump_flows.rb +62 -0
  91. data/ruby/trema/command/kill.rb +71 -0
  92. data/ruby/trema/command/killall.rb +56 -0
  93. data/ruby/trema/command/reset_stats.rb +61 -0
  94. data/ruby/trema/command/ruby.rb +55 -0
  95. data/ruby/trema/command/run.rb +120 -0
  96. data/ruby/trema/command/send_packets.rb +130 -0
  97. data/ruby/trema/command/shell.rb +61 -0
  98. data/ruby/trema/command/show_stats.rb +84 -0
  99. data/ruby/trema/command/usage.rb +61 -0
  100. data/ruby/trema/command/version.rb +39 -0
  101. data/ruby/trema/controller.c +595 -0
  102. data/ruby/trema/controller.h +44 -0
  103. data/ruby/trema/controller.rb +81 -0
  104. data/ruby/trema/daemon.rb +167 -0
  105. data/ruby/trema/dsl.rb +34 -0
  106. data/ruby/trema/dsl/configuration.rb +153 -0
  107. data/ruby/trema/dsl/context.rb +71 -0
  108. data/ruby/trema/dsl/link.rb +41 -0
  109. data/ruby/trema/dsl/parser.rb +70 -0
  110. data/ruby/trema/dsl/run.rb +49 -0
  111. data/ruby/trema/dsl/runner.rb +165 -0
  112. data/ruby/trema/dsl/stanza.rb +53 -0
  113. data/ruby/trema/dsl/switch.rb +78 -0
  114. data/ruby/trema/dsl/syntax-error.rb +33 -0
  115. data/ruby/trema/dsl/syntax.rb +109 -0
  116. data/ruby/trema/dsl/vhost.rb +108 -0
  117. data/ruby/trema/dsl/vswitch.rb +47 -0
  118. data/ruby/trema/echo-reply.c +107 -0
  119. data/ruby/trema/echo-reply.h +42 -0
  120. data/ruby/trema/echo-request.c +140 -0
  121. data/ruby/trema/echo-request.h +42 -0
  122. data/ruby/trema/error.c +253 -0
  123. data/ruby/trema/error.h +44 -0
  124. data/ruby/trema/exact-match.rb +36 -0
  125. data/ruby/trema/executables.rb +95 -0
  126. data/ruby/trema/features-reply.c +238 -0
  127. data/ruby/trema/features-reply.h +60 -0
  128. data/ruby/trema/features-request.c +109 -0
  129. data/ruby/trema/features-request.h +44 -0
  130. data/ruby/trema/flow-removed.c +275 -0
  131. data/ruby/trema/flow-removed.h +46 -0
  132. data/ruby/trema/flow-stats-reply.rb +109 -0
  133. data/ruby/trema/flow.rb +56 -0
  134. data/ruby/trema/get-config-reply.c +159 -0
  135. data/ruby/trema/get-config-reply.h +52 -0
  136. data/ruby/trema/get-config-request.c +107 -0
  137. data/ruby/trema/get-config-request.h +44 -0
  138. data/ruby/trema/hello.c +110 -0
  139. data/ruby/trema/hello.h +44 -0
  140. data/ruby/trema/host.rb +257 -0
  141. data/ruby/trema/ip.rb +101 -0
  142. data/ruby/trema/link.rb +176 -0
  143. data/ruby/trema/list-switches-reply.c +46 -0
  144. data/ruby/trema/list-switches-reply.h +40 -0
  145. data/ruby/trema/logger.c +162 -0
  146. data/ruby/trema/logger.h +44 -0
  147. data/ruby/trema/mac.rb +151 -0
  148. data/ruby/trema/match.c +594 -0
  149. data/ruby/trema/match.h +36 -0
  150. data/ruby/trema/monkey-patch/integer.rb +35 -0
  151. data/ruby/trema/monkey-patch/integer/base-conversions.rb +36 -0
  152. data/ruby/trema/monkey-patch/integer/ranges.rb +51 -0
  153. data/ruby/trema/monkey-patch/module.rb +33 -0
  154. data/ruby/trema/monkey-patch/module/deprecation.rb +41 -0
  155. data/ruby/trema/monkey-patch/string.rb +33 -0
  156. data/ruby/trema/monkey-patch/string/inflectors.rb +54 -0
  157. data/ruby/trema/network-component.rb +153 -0
  158. data/ruby/trema/ofctl.rb +62 -0
  159. data/ruby/trema/open-vswitch.rb +154 -0
  160. data/ruby/trema/openflow-error.c +191 -0
  161. data/ruby/trema/openflow-error.h +53 -0
  162. data/ruby/trema/openflow-switch.rb +88 -0
  163. data/ruby/trema/ordered-hash.rb +74 -0
  164. data/ruby/trema/packet-queue.rb +178 -0
  165. data/ruby/trema/packet_in.c +736 -0
  166. data/ruby/trema/packet_in.h +46 -0
  167. data/ruby/trema/packetin-filter.rb +126 -0
  168. data/ruby/trema/path.rb +135 -0
  169. data/ruby/trema/phost.rb +69 -0
  170. data/ruby/trema/port-mod.c +226 -0
  171. data/ruby/trema/port-mod.h +36 -0
  172. data/ruby/trema/port-stats-reply.rb +111 -0
  173. data/ruby/trema/port-status.c +156 -0
  174. data/ruby/trema/port-status.h +45 -0
  175. data/ruby/trema/port.c +295 -0
  176. data/ruby/trema/port.h +47 -0
  177. data/ruby/trema/process.rb +76 -0
  178. data/ruby/trema/queue-get-config-reply.c +200 -0
  179. data/ruby/trema/queue-get-config-reply.h +47 -0
  180. data/ruby/trema/queue-get-config-request.c +141 -0
  181. data/ruby/trema/queue-get-config-request.h +44 -0
  182. data/ruby/trema/queue-stats-reply.rb +78 -0
  183. data/ruby/trema/set-config.c +171 -0
  184. data/ruby/trema/set-config.h +44 -0
  185. data/ruby/trema/shell.rb +39 -0
  186. data/ruby/trema/shell/down.rb +39 -0
  187. data/ruby/trema/shell/killall.rb +40 -0
  188. data/ruby/trema/shell/link.rb +61 -0
  189. data/ruby/trema/shell/reset_stats.rb +50 -0
  190. data/ruby/trema/shell/run.rb +67 -0
  191. data/ruby/trema/shell/send_packets.rb +42 -0
  192. data/ruby/trema/shell/show_stats.rb +49 -0
  193. data/ruby/trema/shell/up.rb +43 -0
  194. data/ruby/trema/shell/vhost.rb +44 -0
  195. data/ruby/trema/shell/vswitch.rb +49 -0
  196. data/ruby/trema/stats-helper.rb +65 -0
  197. data/ruby/trema/stats-reply.c +483 -0
  198. data/ruby/trema/stats-reply.h +53 -0
  199. data/ruby/trema/stats-request.c +634 -0
  200. data/ruby/trema/stats-request.h +42 -0
  201. data/ruby/trema/switch-daemon.rb +74 -0
  202. data/ruby/trema/switch-disconnected.c +40 -0
  203. data/ruby/trema/switch-disconnected.h +38 -0
  204. data/ruby/trema/switch-manager.rb +121 -0
  205. data/ruby/trema/switch.rb +37 -0
  206. data/ruby/trema/table-stats-reply.rb +87 -0
  207. data/ruby/trema/timers.rb +97 -0
  208. data/ruby/trema/trema.c +122 -0
  209. data/ruby/trema/tremashark.rb +39 -0
  210. data/ruby/trema/util.rb +84 -0
  211. data/ruby/trema/vendor-request.c +193 -0
  212. data/ruby/trema/vendor-request.h +44 -0
  213. data/ruby/trema/vendor-stats-reply.rb +62 -0
  214. data/ruby/trema/vendor.c +152 -0
  215. data/ruby/trema/vendor.h +52 -0
  216. data/ruby/trema/version.rb +30 -0
  217. data/spec/spec_helper.rb +153 -0
  218. data/spec/support/openflow-message.rb +94 -0
  219. data/spec/trema/action-enqueue_spec.rb +100 -0
  220. data/spec/trema/action-output_spec.rb +116 -0
  221. data/spec/trema/action-set-dl-dst_spec.rb +95 -0
  222. data/spec/trema/action-set-dl-src_spec.rb +92 -0
  223. data/spec/trema/action-set-nw-dst_spec.rb +96 -0
  224. data/spec/trema/action-set-nw-src_spec.rb +97 -0
  225. data/spec/trema/action-set-nw-tos_spec.rb +88 -0
  226. data/spec/trema/action-set-tp-dst_spec.rb +88 -0
  227. data/spec/trema/action-set-tp-src_spec.rb +88 -0
  228. data/spec/trema/action-set-vlan-pcp_spec.rb +91 -0
  229. data/spec/trema/action-set-vlan-vid_spec.rb +91 -0
  230. data/spec/trema/action-strip-vlan_spec.rb +57 -0
  231. data/spec/trema/action-vendor_spec.rb +90 -0
  232. data/spec/trema/app_spec.rb +90 -0
  233. data/spec/trema/barrier-reply_spec.rb +45 -0
  234. data/spec/trema/barrier-request_spec.rb +83 -0
  235. data/spec/trema/cli_spec.rb +160 -0
  236. data/spec/trema/controller_spec.rb +100 -0
  237. data/spec/trema/dsl/configuration_spec.rb +122 -0
  238. data/spec/trema/dsl/link_spec.rb +54 -0
  239. data/spec/trema/dsl/run_spec.rb +78 -0
  240. data/spec/trema/dsl/runner_spec.rb +239 -0
  241. data/spec/trema/dsl/switch_spec.rb +77 -0
  242. data/spec/trema/dsl/syntax_spec.rb +121 -0
  243. data/spec/trema/dsl/vhost_spec.rb +148 -0
  244. data/spec/trema/dsl/vswitch_spec.rb +90 -0
  245. data/spec/trema/echo-reply_spec.rb +49 -0
  246. data/spec/trema/echo-request_spec.rb +75 -0
  247. data/spec/trema/error_spec.rb +142 -0
  248. data/spec/trema/executables_spec.rb +75 -0
  249. data/spec/trema/features-reply_spec.rb +57 -0
  250. data/spec/trema/features-request_spec.rb +66 -0
  251. data/spec/trema/flow-removed_spec.rb +146 -0
  252. data/spec/trema/get-config-reply_spec.rb +43 -0
  253. data/spec/trema/get-config-request_spec.rb +82 -0
  254. data/spec/trema/hello_spec.rb +49 -0
  255. data/spec/trema/host_spec.rb +193 -0
  256. data/spec/trema/link_spec.rb +64 -0
  257. data/spec/trema/list-switches-reply_spec.rb +48 -0
  258. data/spec/trema/logger_spec.rb +48 -0
  259. data/spec/trema/mac_spec.rb +115 -0
  260. data/spec/trema/match_spec.rb +113 -0
  261. data/spec/trema/open-vswitch_spec.rb +123 -0
  262. data/spec/trema/openflow-error_spec.rb +141 -0
  263. data/spec/trema/openflow-switch_spec.rb +56 -0
  264. data/spec/trema/packet-in_spec.rb +168 -0
  265. data/spec/trema/packet-out_spec.rb +128 -0
  266. data/spec/trema/packetin-filter_spec.rb +41 -0
  267. data/spec/trema/port-mod_spec.rb +101 -0
  268. data/spec/trema/port-status_spec.rb +108 -0
  269. data/spec/trema/port_spec.rb +61 -0
  270. data/spec/trema/process_spec.rb +71 -0
  271. data/spec/trema/queue-get-config-reply_spec.rb +66 -0
  272. data/spec/trema/queue-get-config-request_spec.rb +69 -0
  273. data/spec/trema/set-config_spec.rb +80 -0
  274. data/spec/trema/shell/vhost_spec.rb +57 -0
  275. data/spec/trema/shell/vswitch_spec.rb +89 -0
  276. data/spec/trema/stats-reply_spec.rb +306 -0
  277. data/spec/trema/stats-request_spec.rb +151 -0
  278. data/spec/trema/switch-disconnected_spec.rb +58 -0
  279. data/spec/trema/switch-manager_spec.rb +43 -0
  280. data/spec/trema/tremashark_spec.rb +41 -0
  281. data/spec/trema/util_spec.rb +93 -0
  282. data/spec/trema/vendor-request_spec.rb +79 -0
  283. data/src/examples/cbench_switch/README +21 -0
  284. data/src/examples/cbench_switch/cbench-switch.rb +39 -0
  285. data/src/examples/cbench_switch/cbench_switch.c +68 -0
  286. data/src/examples/dumper/dumper.c +370 -0
  287. data/src/examples/dumper/dumper.conf +7 -0
  288. data/src/examples/dumper/dumper.rb +196 -0
  289. data/src/examples/hello_trema/README +13 -0
  290. data/src/examples/hello_trema/hello_trema.c +51 -0
  291. data/src/examples/hello_trema/hello_trema.conf +3 -0
  292. data/src/examples/hello_trema/hello_trema.rb +35 -0
  293. data/src/examples/learning_switch/README +15 -0
  294. data/src/examples/learning_switch/fdb.rb +112 -0
  295. data/src/examples/learning_switch/learning-switch.rb +88 -0
  296. data/src/examples/learning_switch/learning_switch.c +236 -0
  297. data/src/examples/learning_switch/learning_switch.conf +18 -0
  298. data/src/examples/list_switches/README +19 -0
  299. data/src/examples/list_switches/list-switches.rb +45 -0
  300. data/src/examples/list_switches/list_switches.c +81 -0
  301. data/src/examples/list_switches/list_switches.conf +15 -0
  302. data/src/examples/match_compare/match-compare.conf +30 -0
  303. data/src/examples/match_compare/match-compare.rb +99 -0
  304. data/src/examples/multi_learning_switch/README +14 -0
  305. data/src/examples/multi_learning_switch/multi-learning-switch.rb +96 -0
  306. data/src/examples/multi_learning_switch/multi_learning_switch.c +296 -0
  307. data/src/examples/multi_learning_switch/multi_learning_switch.conf +17 -0
  308. data/src/examples/openflow_message/README +11 -0
  309. data/src/examples/openflow_message/echo-reply.rb +59 -0
  310. data/src/examples/openflow_message/echo-request.rb +58 -0
  311. data/src/examples/openflow_message/echo_reply.c +70 -0
  312. data/src/examples/openflow_message/echo_request.c +70 -0
  313. data/src/examples/openflow_message/example.rb +63 -0
  314. data/src/examples/openflow_message/features-request.rb +97 -0
  315. data/src/examples/openflow_message/features_request.c +168 -0
  316. data/src/examples/openflow_message/hello.c +70 -0
  317. data/src/examples/openflow_message/hello.rb +58 -0
  318. data/src/examples/openflow_message/set-config.rb +59 -0
  319. data/src/examples/openflow_message/set_config.c +70 -0
  320. data/src/examples/packet_in/README +15 -0
  321. data/src/examples/packet_in/packet_in.c +55 -0
  322. data/src/examples/packet_in/packet_in.conf +15 -0
  323. data/src/examples/packet_in/packet_in.rb +34 -0
  324. data/src/examples/packetin_filter_config/README +12 -0
  325. data/src/examples/packetin_filter_config/add_filter.c +73 -0
  326. data/src/examples/packetin_filter_config/delete_filter.c +65 -0
  327. data/src/examples/packetin_filter_config/delete_filter_strict.c +75 -0
  328. data/src/examples/packetin_filter_config/dump_filter.c +65 -0
  329. data/src/examples/packetin_filter_config/dump_filter_strict.c +75 -0
  330. data/src/examples/packetin_filter_config/packetin_filter_config.c +134 -0
  331. data/src/examples/packetin_filter_config/packetin_filter_config.conf +7 -0
  332. data/src/examples/packetin_filter_config/utils.c +102 -0
  333. data/src/examples/packetin_filter_config/utils.h +42 -0
  334. data/src/examples/repeater_hub/README +8 -0
  335. data/src/examples/repeater_hub/repeater-hub.rb +43 -0
  336. data/src/examples/repeater_hub/repeater-hub_spec.rb +156 -0
  337. data/src/examples/repeater_hub/repeater_hub.c +83 -0
  338. data/src/examples/repeater_hub/repeater_hub.conf +28 -0
  339. data/src/examples/switch_info/README +13 -0
  340. data/src/examples/switch_info/switch_info.c +80 -0
  341. data/src/examples/switch_info/switch_info.conf +3 -0
  342. data/src/examples/switch_info/switch_info.rb +46 -0
  343. data/src/examples/switch_monitor/switch-monitor.conf +3 -0
  344. data/src/examples/switch_monitor/switch-monitor.rb +58 -0
  345. data/src/examples/switch_monitor/switch_monitor.c +154 -0
  346. data/src/examples/traffic_monitor/counter.c +74 -0
  347. data/src/examples/traffic_monitor/counter.h +48 -0
  348. data/src/examples/traffic_monitor/counter.rb +46 -0
  349. data/src/examples/traffic_monitor/fdb.c +76 -0
  350. data/src/examples/traffic_monitor/fdb.h +50 -0
  351. data/src/examples/traffic_monitor/fdb.rb +44 -0
  352. data/src/examples/traffic_monitor/traffic-monitor.rb +100 -0
  353. data/src/examples/traffic_monitor/traffic_monitor.c +163 -0
  354. data/src/examples/traffic_monitor/traffic_monitor.conf +16 -0
  355. data/src/lib/arp.h +61 -0
  356. data/src/lib/bool.h +49 -0
  357. data/src/lib/buffer.c +305 -0
  358. data/src/lib/buffer.h +56 -0
  359. data/src/lib/byteorder.c +547 -0
  360. data/src/lib/byteorder.h +110 -0
  361. data/src/lib/checks.h +42 -0
  362. data/src/lib/daemon.c +302 -0
  363. data/src/lib/daemon.h +42 -0
  364. data/src/lib/doubly_linked_list.c +281 -0
  365. data/src/lib/doubly_linked_list.h +88 -0
  366. data/src/lib/ether.c +48 -0
  367. data/src/lib/ether.h +94 -0
  368. data/src/lib/etherip.h +46 -0
  369. data/src/lib/event_handler.c +389 -0
  370. data/src/lib/event_handler.h +64 -0
  371. data/src/lib/hash_table.c +417 -0
  372. data/src/lib/hash_table.h +138 -0
  373. data/src/lib/icmp.h +74 -0
  374. data/src/lib/igmp.h +50 -0
  375. data/src/lib/ipv4.h +50 -0
  376. data/src/lib/linked_list.c +199 -0
  377. data/src/lib/linked_list.h +84 -0
  378. data/src/lib/log.c +402 -0
  379. data/src/lib/log.h +78 -0
  380. data/src/lib/match.h +84 -0
  381. data/src/lib/match_table.c +608 -0
  382. data/src/lib/match_table.h +51 -0
  383. data/src/lib/message_queue.c +143 -0
  384. data/src/lib/message_queue.h +61 -0
  385. data/src/lib/messenger.c +1714 -0
  386. data/src/lib/messenger.h +145 -0
  387. data/src/lib/openflow_application_interface.c +1673 -0
  388. data/src/lib/openflow_application_interface.h +329 -0
  389. data/src/lib/openflow_message.c +4051 -0
  390. data/src/lib/openflow_message.h +288 -0
  391. data/src/lib/openflow_service_interface.h +59 -0
  392. data/src/lib/packet_info.c +230 -0
  393. data/src/lib/packet_info.h +209 -0
  394. data/src/lib/packet_parser.c +502 -0
  395. data/src/lib/packetin_filter_interface.c +294 -0
  396. data/src/lib/packetin_filter_interface.h +127 -0
  397. data/src/lib/persistent_storage.c +480 -0
  398. data/src/lib/persistent_storage.h +46 -0
  399. data/src/lib/stat.c +213 -0
  400. data/src/lib/stat.h +44 -0
  401. data/src/lib/tcp.h +67 -0
  402. data/src/lib/timer.c +350 -0
  403. data/src/lib/timer.h +53 -0
  404. data/src/lib/trema.c +710 -0
  405. data/src/lib/trema.h +79 -0
  406. data/src/lib/trema_private.c +177 -0
  407. data/src/lib/trema_private.h +60 -0
  408. data/src/lib/trema_wrapper.c +56 -0
  409. data/src/lib/trema_wrapper.h +64 -0
  410. data/src/lib/udp.h +43 -0
  411. data/src/lib/utility.c +515 -0
  412. data/src/lib/utility.h +67 -0
  413. data/src/lib/wrapper.c +100 -0
  414. data/src/lib/wrapper.h +76 -0
  415. data/src/packetin_filter/README +17 -0
  416. data/src/packetin_filter/packetin_filter.c +575 -0
  417. data/src/switch_manager/README +20 -0
  418. data/src/switch_manager/cookie_table.c +292 -0
  419. data/src/switch_manager/cookie_table.h +72 -0
  420. data/src/switch_manager/dpid_table.c +110 -0
  421. data/src/switch_manager/dpid_table.h +46 -0
  422. data/src/switch_manager/management_interface.h +44 -0
  423. data/src/switch_manager/ofpmsg_recv.c +482 -0
  424. data/src/switch_manager/ofpmsg_recv.h +42 -0
  425. data/src/switch_manager/ofpmsg_send.c +235 -0
  426. data/src/switch_manager/ofpmsg_send.h +50 -0
  427. data/src/switch_manager/secure_channel_listener.c +281 -0
  428. data/src/switch_manager/secure_channel_listener.h +42 -0
  429. data/src/switch_manager/secure_channel_receiver.c +126 -0
  430. data/src/switch_manager/secure_channel_receiver.h +43 -0
  431. data/src/switch_manager/secure_channel_sender.c +126 -0
  432. data/src/switch_manager/secure_channel_sender.h +43 -0
  433. data/src/switch_manager/service_interface.c +181 -0
  434. data/src/switch_manager/service_interface.h +46 -0
  435. data/src/switch_manager/switch.c +538 -0
  436. data/src/switch_manager/switch.h +51 -0
  437. data/src/switch_manager/switch_manager.c +448 -0
  438. data/src/switch_manager/switch_manager.h +63 -0
  439. data/src/switch_manager/switchinfo.h +72 -0
  440. data/src/switch_manager/xid_table.c +184 -0
  441. data/src/switch_manager/xid_table.h +56 -0
  442. data/src/tremashark/README +78 -0
  443. data/src/tremashark/packet_capture.c +357 -0
  444. data/src/tremashark/pcap_private.h +47 -0
  445. data/src/tremashark/pcap_queue.c +197 -0
  446. data/src/tremashark/pcap_queue.h +58 -0
  447. data/src/tremashark/plugin/.gitignore +6 -0
  448. data/src/tremashark/plugin/packet-trema/.gitignore +5 -0
  449. data/src/tremashark/plugin/packet-trema/Makefile +77 -0
  450. data/src/tremashark/plugin/packet-trema/Makefile.am +110 -0
  451. data/src/tremashark/plugin/packet-trema/Makefile.common +31 -0
  452. data/src/tremashark/plugin/packet-trema/moduleinfo.h +41 -0
  453. data/src/tremashark/plugin/packet-trema/packet-trema.c +1659 -0
  454. data/src/tremashark/plugin/packet-trema/plugin.c +31 -0
  455. data/src/tremashark/plugin/user_dlts +2 -0
  456. data/src/tremashark/queue.c +168 -0
  457. data/src/tremashark/queue.h +60 -0
  458. data/src/tremashark/stdin_relay.c +257 -0
  459. data/src/tremashark/syslog_relay.c +247 -0
  460. data/src/tremashark/tremashark.c +556 -0
  461. data/trema +93 -0
  462. data/trema-config +61 -0
  463. data/unittests/buffer_stubs.c +74 -0
  464. data/unittests/cmockery_trema.c +123 -0
  465. data/unittests/cmockery_trema.h +96 -0
  466. data/unittests/lib/buffer_test.c +370 -0
  467. data/unittests/lib/byteorder_test.c +1717 -0
  468. data/unittests/lib/daemon_test.c +664 -0
  469. data/unittests/lib/doubly_linked_list_test.c +346 -0
  470. data/unittests/lib/ether_test.c +127 -0
  471. data/unittests/lib/hash_table_test.c +278 -0
  472. data/unittests/lib/linked_list_test.c +343 -0
  473. data/unittests/lib/log_test.c +459 -0
  474. data/unittests/lib/match_table_test.c +1509 -0
  475. data/unittests/lib/message_queue_test.c +379 -0
  476. data/unittests/lib/messenger_test.c +438 -0
  477. data/unittests/lib/openflow_application_interface_test.c +3488 -0
  478. data/unittests/lib/openflow_message_test.c +7337 -0
  479. data/unittests/lib/packet_info_test.c +544 -0
  480. data/unittests/lib/packet_parser_test.c +703 -0
  481. data/unittests/lib/packetin_filter_interface_test.c +723 -0
  482. data/unittests/lib/persistent_storage_test.c +802 -0
  483. data/unittests/lib/stat_test.c +291 -0
  484. data/unittests/lib/test_packets/arp_rep.cap +0 -0
  485. data/unittests/lib/test_packets/arp_req.cap +0 -0
  486. data/unittests/lib/test_packets/icmp_echo_rep.cap +0 -0
  487. data/unittests/lib/test_packets/icmp_echo_req.cap +0 -0
  488. data/unittests/lib/test_packets/igmp_query_v2.cap +0 -0
  489. data/unittests/lib/test_packets/ipx.cap +0 -0
  490. data/unittests/lib/test_packets/lldp.cap +0 -0
  491. data/unittests/lib/test_packets/lldp_over_ip.cap +0 -0
  492. data/unittests/lib/test_packets/tcp.cap +0 -0
  493. data/unittests/lib/test_packets/tcp_syn.cap +0 -0
  494. data/unittests/lib/test_packets/udp.cap +0 -0
  495. data/unittests/lib/test_packets/udp_frag_head.cap +0 -0
  496. data/unittests/lib/test_packets/udp_frag_next.cap +0 -0
  497. data/unittests/lib/test_packets/vtag_icmp_echo_rep.cap +0 -0
  498. data/unittests/lib/test_packets/vtag_icmp_echo_req.cap +0 -0
  499. data/unittests/lib/timer_test.c +248 -0
  500. data/unittests/lib/trema_private_test.c +323 -0
  501. data/unittests/lib/trema_test.c +985 -0
  502. data/unittests/lib/utility_test.c +628 -0
  503. data/unittests/lib/wrapper_test.c +201 -0
  504. data/unittests/packetin_filter/packetin_filter_test.c +477 -0
  505. data/unittests/switch_manager/switch_manager_test.c +1178 -0
  506. data/unittests/wrapper_stubs.c +39 -0
  507. data/vendor/.gitignore +6 -0
  508. data/vendor/README +30 -0
  509. data/vendor/cmockery-20110428.tar.gz +0 -0
  510. data/vendor/oflops-0.03.tar.gz +0 -0
  511. data/vendor/oflops_no_snmp+1.0.0.patch +340 -0
  512. data/vendor/openflow-1.0.0.tar.gz +0 -0
  513. data/vendor/openflow.git.tar.gz +0 -0
  514. data/vendor/openvswitch-1.2.2.tar.gz +0 -0
  515. data/vendor/ruby-ifconfig-1.2/COPYING +340 -0
  516. data/vendor/ruby-ifconfig-1.2/Changelog +16 -0
  517. data/vendor/ruby-ifconfig-1.2/INSTALL +239 -0
  518. data/vendor/ruby-ifconfig-1.2/README +38 -0
  519. data/vendor/ruby-ifconfig-1.2/Rakefile +14 -0
  520. data/vendor/ruby-ifconfig-1.2/TODO +8 -0
  521. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/darwin.txt +17 -0
  522. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/dragonflybsd.txt +10 -0
  523. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/dragonflybsd_netstat.txt +14 -0
  524. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/freebsd.txt +17 -0
  525. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/freebsd_netstat.txt +24 -0
  526. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/linux.txt +60 -0
  527. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/linux_ethernet.txt +20 -0
  528. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/netbsd.txt +10 -0
  529. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/openbsd.txt +36 -0
  530. data/vendor/ruby-ifconfig-1.2/ifconfig_examples/sunos.txt +10 -0
  531. data/vendor/ruby-ifconfig-1.2/lib/ifconfig.rb +71 -0
  532. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/bsd/ifconfig.rb +72 -0
  533. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/bsd/interface_types.rb +69 -0
  534. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/bsd/network_types.rb +3 -0
  535. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/common/ifconfig.rb +84 -0
  536. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/common/interface_types.rb +130 -0
  537. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/common/network_types.rb +49 -0
  538. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/linux/ifconfig.rb +43 -0
  539. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/linux/interface_types.rb +112 -0
  540. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/linux/network_types.rb +55 -0
  541. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/sunos/ifconfig.rb +38 -0
  542. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/sunos/interface_types.rb +77 -0
  543. data/vendor/ruby-ifconfig-1.2/lib/ifconfig/sunos/network_types.rb +4 -0
  544. data/vendor/ruby-ifconfig-1.2/setup.rb +1306 -0
  545. data/vendor/ruby-ifconfig-1.2/test/test_bsd.rb +35 -0
  546. data/vendor/ruby-ifconfig-1.2/test/test_darwin.rb +33 -0
  547. data/vendor/ruby-ifconfig-1.2/test/test_dragonflybsd.rb +35 -0
  548. data/vendor/ruby-ifconfig-1.2/test/test_helper.rb +4 -0
  549. data/vendor/ruby-ifconfig-1.2/test/test_linux.rb +31 -0
  550. data/vendor/ruby-ifconfig-1.2/test/test_netbsd.rb +33 -0
  551. data/vendor/ruby-ifconfig-1.2/test/test_openbsd.rb +33 -0
  552. data/vendor/ruby-ifconfig-1.2/test/test_sunos.rb +35 -0
  553. data/vendor/ruby-ifconfig-1.2/test/unit/tc_darwin.rb +40 -0
  554. data/vendor/ruby-ifconfig-1.2/test/unit/tc_dragonflybsd.rb +39 -0
  555. data/vendor/ruby-ifconfig-1.2/test/unit/tc_freebsd.rb +40 -0
  556. data/vendor/ruby-ifconfig-1.2/test/unit/tc_linux.rb +49 -0
  557. data/vendor/ruby-ifconfig-1.2/test/unit/tc_netbsd.rb +39 -0
  558. data/vendor/ruby-ifconfig-1.2/test/unit/tc_openbsd.rb +39 -0
  559. data/vendor/ruby-ifconfig-1.2/test/unit/tc_sunos.rb +44 -0
  560. metadata +856 -0
@@ -0,0 +1,51 @@
1
+ /*
2
+ * OpenFlow flow matching library
3
+ *
4
+ * Author: Kazushi SUGYO
5
+ *
6
+ * Copyright (C) 2008-2012 NEC Corporation
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License, version 2, as
10
+ * published by the Free Software Foundation.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+
23
+ #ifndef MATCH_TABLE_H
24
+ #define MATCH_TABLE_H
25
+
26
+
27
+ #include <openflow.h>
28
+ #include "hash_table.h"
29
+ #include "linked_list.h"
30
+
31
+
32
+ void init_match_table( void );
33
+ void finalize_match_table( void );
34
+ bool insert_match_entry( struct ofp_match match, uint16_t priority, void *data );
35
+ void *lookup_match_strict_entry( struct ofp_match match, uint16_t priority );
36
+ void *lookup_match_entry( struct ofp_match match );
37
+ bool update_match_entry( struct ofp_match match, uint16_t priority, void *data );
38
+ void *delete_match_strict_entry( struct ofp_match match, uint16_t priority );
39
+ void foreach_match_table( void function( struct ofp_match match, uint16_t priority, void *data, void *user_data ), void *user_data );
40
+ void map_match_table( struct ofp_match match, void function( struct ofp_match match, uint16_t priority, void *data, void *user_data ), void *user_data );
41
+
42
+
43
+ #endif // MATCH_TABLE_H
44
+
45
+
46
+ /*
47
+ * Local variables:
48
+ * c-basic-offset: 2
49
+ * indent-tabs-mode: nil
50
+ * End:
51
+ */
@@ -0,0 +1,143 @@
1
+ /*
2
+ * Author: Yasunobu Chiba
3
+ *
4
+ * Copyright (C) 2008-2012 NEC Corporation
5
+ *
6
+ * This program is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License, version 2, as
8
+ * published by the Free Software Foundation.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License along
16
+ * with this program; if not, write to the Free Software Foundation, Inc.,
17
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
+ */
19
+
20
+
21
+ #include <assert.h>
22
+ #include "wrapper.h"
23
+ #include "message_queue.h"
24
+
25
+
26
+ message_queue *
27
+ create_message_queue( void ) {
28
+ message_queue *new_queue = xmalloc( sizeof( message_queue ) );
29
+ new_queue->head = xmalloc( sizeof( message_queue_element ) );
30
+ new_queue->head->data = NULL;
31
+ new_queue->head->next = NULL;
32
+ new_queue->divider = new_queue->tail = new_queue->head;
33
+ new_queue->length = 0;
34
+
35
+ return new_queue;
36
+ }
37
+
38
+
39
+ bool
40
+ delete_message_queue( message_queue *queue ) {
41
+ if ( queue == NULL ) {
42
+ die( "queue must not be NULL" );
43
+ }
44
+
45
+ while( queue->head != NULL ) {
46
+ message_queue_element *element = queue->head;
47
+ if ( queue->head->data != NULL ) {
48
+ free_buffer( element->data );
49
+ }
50
+ queue->head = queue->head->next;
51
+ xfree( element );
52
+ }
53
+ xfree( queue );
54
+
55
+ return true;
56
+ }
57
+
58
+
59
+ static void
60
+ collect_garbage( message_queue *queue ) {
61
+ while ( queue->head != queue->divider ) {
62
+ message_queue_element *element = queue->head;
63
+ queue->head = queue->head->next;
64
+ xfree( element );
65
+ }
66
+ }
67
+
68
+
69
+ bool
70
+ enqueue_message( message_queue *queue, buffer *message ) {
71
+ if ( queue == NULL ) {
72
+ die( "queues must not be NULL" );
73
+ }
74
+ if ( message == NULL ) {
75
+ die( "message must not be NULL" );
76
+ }
77
+
78
+ message_queue_element *new_tail = xmalloc( sizeof( message_queue_element ) );
79
+ new_tail->data = message;
80
+ new_tail->next = NULL;
81
+
82
+ queue->tail->next = new_tail;
83
+ queue->tail = new_tail;
84
+ queue->length++;
85
+
86
+ collect_garbage( queue );
87
+
88
+ return true;
89
+ }
90
+
91
+
92
+ buffer *
93
+ dequeue_message( message_queue *queue ) {
94
+ if ( queue == NULL ) {
95
+ die( "queue must not be NULL" );
96
+ }
97
+ if ( queue->divider == queue->tail ) {
98
+ return NULL;
99
+ }
100
+
101
+ message_queue_element *next = queue->divider->next;
102
+ buffer *message = next->data;
103
+ next->data = NULL; // data must be freed by caller
104
+ queue->divider = next;
105
+ queue->length--;
106
+
107
+ return message;
108
+ }
109
+
110
+
111
+ buffer *
112
+ peek_message( message_queue *queue ) {
113
+ if ( queue == NULL ) {
114
+ die( "queue must not be NULL" );
115
+ }
116
+
117
+ if ( queue->divider == queue->tail ) {
118
+ return NULL;
119
+ }
120
+
121
+ return queue->divider->next->data;
122
+ }
123
+
124
+
125
+ void foreach_message_queue( message_queue *queue, void function( buffer *message, void *user_data ), void *user_data ) {
126
+ if ( queue->divider == queue->tail ) {
127
+ return;
128
+ }
129
+ message_queue_element *element;
130
+ for ( element = queue->divider->next; element != NULL; element = element->next ) {
131
+ buffer *message = element->data;
132
+ assert( message != NULL );
133
+ function( message, user_data );
134
+ }
135
+ }
136
+
137
+
138
+ /*
139
+ * Local variables:
140
+ * c-basic-offset: 2
141
+ * indent-tabs-mode: nil
142
+ * End:
143
+ */
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Queue implementation
3
+ *
4
+ * Author: Yasunobu Chiba
5
+ *
6
+ * Copyright (C) 2008-2012 NEC Corporation
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License, version 2, as
10
+ * published by the Free Software Foundation.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+
23
+ #ifndef MESSAGE_QUEUE_H
24
+ #define MESSAGE_QUEUE_H
25
+
26
+
27
+ #include "bool.h"
28
+ #include "buffer.h"
29
+
30
+
31
+ typedef struct message_queue_element {
32
+ buffer *data;
33
+ struct message_queue_element *next;
34
+ } message_queue_element;
35
+
36
+
37
+ typedef struct {
38
+ message_queue_element *head;
39
+ message_queue_element *divider;
40
+ message_queue_element *tail;
41
+ unsigned int length;
42
+ } message_queue;
43
+
44
+
45
+ message_queue *create_message_queue( void );
46
+ bool delete_message_queue( message_queue *queue );
47
+ bool enqueue_message( message_queue *queue, buffer *message );
48
+ buffer *dequeue_message( message_queue *queue );
49
+ buffer *peek_message( message_queue *queue );
50
+ void foreach_message_queue( message_queue *queue, void function( buffer *message, void *user_data ), void *user_data );
51
+
52
+
53
+ #endif // MESSAGE_QUEUE_H
54
+
55
+
56
+ /*
57
+ * Local variables:
58
+ * c-basic-offset: 2
59
+ * indent-tabs-mode: nil
60
+ * End:
61
+ */
@@ -0,0 +1,1714 @@
1
+ /*
2
+ * Author: Toshio Koide
3
+ *
4
+ * Copyright (C) 2008-2012 NEC Corporation
5
+ *
6
+ * This program is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License, version 2, as
8
+ * published by the Free Software Foundation.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License along
16
+ * with this program; if not, write to the Free Software Foundation, Inc.,
17
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
+ */
19
+
20
+
21
+ #include <arpa/inet.h>
22
+ #include <assert.h>
23
+ #include <errno.h>
24
+ #include <fcntl.h>
25
+ #include <inttypes.h>
26
+ #include <linux/limits.h>
27
+ #include <linux/sockios.h>
28
+ #include <stdio.h>
29
+ #include <stdlib.h>
30
+ #include <sys/ioctl.h>
31
+ #include <sys/socket.h>
32
+ #include <sys/types.h>
33
+ #include <sys/un.h>
34
+ #include <unistd.h>
35
+ #include "doubly_linked_list.h"
36
+ #include "event_handler.h"
37
+ #include "hash_table.h"
38
+ #include "log.h"
39
+ #include "messenger.h"
40
+ #include "timer.h"
41
+ #include "wrapper.h"
42
+
43
+
44
+ #ifdef UNIT_TESTING
45
+
46
+ #define static
47
+
48
+ // Redirect socket functions to mock functions in the unit test.
49
+ #ifdef socket
50
+ #undef socket
51
+ #endif
52
+ #define socket mock_socket
53
+ extern int mock_socket( int domain, int type, int protocol );
54
+
55
+ #ifdef bind
56
+ #undef bind
57
+ #endif
58
+ #define bind mock_bind
59
+ extern int mock_bind( int sockfd, const struct sockaddr *addr, socklen_t addrlen );
60
+
61
+ #ifdef listen
62
+ #undef listen
63
+ #endif
64
+ #define listen mock_listen
65
+ extern int mock_listen( int sockfd, int backlog );
66
+
67
+ #ifdef close
68
+ #undef close
69
+ #endif
70
+ #define close mock_close
71
+ extern int mock_close( int fd );
72
+
73
+ #ifdef connect
74
+ #undef connect
75
+ #endif
76
+ #define connect mock_connect
77
+ extern int mock_connect( int sockfd, const struct sockaddr *addr, socklen_t addrlen );
78
+
79
+ #ifdef select
80
+ #undef select
81
+ #endif
82
+ #define select mock_select
83
+ extern int mock_select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout );
84
+
85
+ #ifdef accept
86
+ #undef accept
87
+ #endif
88
+ #define accept mock_accept
89
+ extern int mock_accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen );
90
+
91
+ #ifdef recv
92
+ #undef recv
93
+ #endif
94
+ #define recv mock_recv
95
+ extern ssize_t mock_recv( int sockfd, void *buf, size_t len, int flags );
96
+
97
+ #ifdef send
98
+ #undef send
99
+ #endif
100
+ #define send mock_send
101
+ extern ssize_t mock_send( int sockfd, const void *buf, size_t len, int flags );
102
+
103
+ #ifdef setsockopt
104
+ #undef setsockopt
105
+ #endif
106
+ #define setsockopt mock_setsockopt
107
+ extern int mock_setsockopt( int s, int level, int optname, const void *optval, socklen_t optlen );
108
+
109
+ #ifdef clock_gettime
110
+ #undef clock_gettime
111
+ #endif
112
+ #define clock_gettime mock_clock_gettime
113
+ extern int mock_clock_gettime( clockid_t clk_id, struct timespec *tp );
114
+
115
+ #ifdef error
116
+ #undef error
117
+ #endif
118
+ #define error mock_error
119
+ extern void mock_error( const char *format, ... );
120
+
121
+ #ifdef debug
122
+ #undef debug
123
+ #endif
124
+ #define debug mock_debug
125
+ extern void mock_debug( const char *format, ... );
126
+
127
+ #ifdef warn
128
+ #undef warn
129
+ #endif
130
+ #define warn mock_warn
131
+ extern void mock_warn( const char *format, ... );
132
+
133
+ #ifdef add_periodic_event_callback
134
+ #undef add_periodic_event_callback
135
+ #endif
136
+ #define add_periodic_event_callback mock_add_periodic_event_callback
137
+ extern bool mock_add_periodic_event_callback( const time_t seconds, void ( *callback )( void *user_data ), void *user_data );
138
+
139
+ #endif // UNIT_TESTING
140
+
141
+
142
+ enum {
143
+ MESSAGE_TYPE_NOTIFY,
144
+ MESSAGE_TYPE_REQUEST,
145
+ MESSAGE_TYPE_REPLY,
146
+ };
147
+
148
+ typedef struct message_buffer {
149
+ void *buffer;
150
+ size_t data_length;
151
+ size_t size;
152
+ size_t head_offset;
153
+ } message_buffer;
154
+
155
+ typedef struct messenger_socket {
156
+ int fd;
157
+ } messenger_socket;
158
+
159
+ typedef struct messenger_context {
160
+ uint32_t transaction_id;
161
+ int life_count;
162
+ void *user_data;
163
+ } messenger_context;
164
+
165
+ typedef struct receive_queue_callback {
166
+ void *function;
167
+ uint8_t message_type;
168
+ } receive_queue_callback;
169
+
170
+ typedef struct receive_queue {
171
+ char service_name[ MESSENGER_SERVICE_NAME_LENGTH ];
172
+ dlist_element *message_callbacks;
173
+ int listen_socket;
174
+ struct sockaddr_un listen_addr;
175
+ dlist_element *client_sockets;
176
+ message_buffer *buffer;
177
+ } receive_queue;
178
+
179
+ typedef struct send_queue {
180
+ char service_name[ MESSENGER_SERVICE_NAME_LENGTH ];
181
+ int server_socket;
182
+ int refused_count;
183
+ struct timespec reconnect_interval;
184
+ struct sockaddr_un server_addr;
185
+ message_buffer *buffer;
186
+ bool running_timer;
187
+ uint32_t overflow;
188
+ uint64_t overflow_total_length;
189
+ int socket_buffer_size;
190
+ } send_queue;
191
+
192
+
193
+ #define MESSENGER_RECV_BUFFER 100000
194
+ static const uint32_t messenger_send_queue_length = MESSENGER_RECV_BUFFER * 4;
195
+ static const uint32_t messenger_send_length_for_flush = MESSENGER_RECV_BUFFER;
196
+ static const uint32_t messenger_bucket_size = MESSENGER_RECV_BUFFER;
197
+ static const uint32_t messenger_recv_queue_length = MESSENGER_RECV_BUFFER * 2;
198
+ static const uint32_t messenger_recv_queue_reserved = MESSENGER_RECV_BUFFER;
199
+
200
+ char socket_directory[ PATH_MAX ];
201
+ static bool initialized = false;
202
+ static bool finalized = false;
203
+ static hash_table *receive_queues = NULL;
204
+ static hash_table *send_queues = NULL;
205
+ static hash_table *context_db = NULL;
206
+ static char *_dump_service_name = NULL;
207
+ static char *_dump_app_name = NULL;
208
+ static uint32_t last_transaction_id = 0;
209
+
210
+ static void on_accept( int fd, void *data );
211
+ static void on_recv( int fd, void *data );
212
+ static void on_send_write( int fd, void *data );
213
+ static void on_send_read( int fd, void *data );
214
+
215
+ static void
216
+ _delete_context( void *key, void *value, void *user_data ) {
217
+ assert( value != NULL );
218
+ UNUSED( key );
219
+ UNUSED( user_data );
220
+ messenger_context *context = value;
221
+
222
+ debug( "Deleting a context ( transaction_id = %#x, life_count = %d, user_data = %p ).",
223
+ context->transaction_id, context->life_count, context->user_data );
224
+
225
+ delete_hash_entry( context_db, &context->transaction_id );
226
+ xfree( context );
227
+ }
228
+
229
+
230
+ static void
231
+ delete_context( messenger_context *context ) {
232
+ assert( context != NULL );
233
+
234
+ _delete_context( &context->transaction_id, context, NULL );
235
+ }
236
+
237
+
238
+ static void
239
+ _age_context( void *key, void *value, void *user_data ) {
240
+ assert( value != NULL );
241
+ UNUSED( key );
242
+ UNUSED( user_data );
243
+ messenger_context *context = value;
244
+ context->life_count--;
245
+ if ( context->life_count <= 0 ) {
246
+ delete_context( context );
247
+ }
248
+ }
249
+
250
+
251
+ static void
252
+ age_context_db( void *user_data ) {
253
+ UNUSED( user_data );
254
+
255
+ debug( "Aging context database ( context_db = %p ).", context_db );
256
+
257
+ foreach_hash( context_db, _age_context, NULL );
258
+ }
259
+
260
+
261
+ bool
262
+ init_messenger( const char *working_directory ) {
263
+ assert( working_directory != NULL );
264
+
265
+ init_event_handler();
266
+
267
+ if ( initialized ) {
268
+ warn( "Messenger is already initialized." );
269
+ return true;
270
+ }
271
+
272
+ strcpy( socket_directory, working_directory );
273
+
274
+ receive_queues = create_hash( compare_string, hash_string );
275
+ send_queues = create_hash( compare_string, hash_string );
276
+ context_db = create_hash( compare_uint32, hash_uint32 );
277
+
278
+ initialized = true;
279
+ finalized = false;
280
+
281
+ return initialized;
282
+ }
283
+
284
+
285
+ static void
286
+ delete_context_db( void ) {
287
+ debug( "Deleting context database ( context_db = %p ).", context_db );
288
+
289
+ if ( context_db != NULL ) {
290
+ foreach_hash( context_db, _delete_context, NULL );
291
+ delete_hash( context_db );
292
+ context_db = NULL;
293
+ }
294
+ }
295
+
296
+
297
+ static void
298
+ free_message_buffer( message_buffer *buf ) {
299
+ assert( buf != NULL );
300
+
301
+ xfree( buf->buffer );
302
+ xfree( buf );
303
+ }
304
+
305
+
306
+ static void*
307
+ get_message_buffer_head( message_buffer *buf ) {
308
+ return ( char * ) buf->buffer + buf->head_offset;
309
+ }
310
+
311
+
312
+ static void
313
+ delete_send_queue( send_queue *sq ) {
314
+ assert( NULL != sq );
315
+
316
+ debug( "Deleting a send queue ( service_name = %s, fd = %d ).", sq->service_name, sq->server_socket );
317
+
318
+ free_message_buffer( sq->buffer );
319
+ if ( sq->server_socket != -1 ) {
320
+ set_readable( sq->server_socket, false );
321
+ set_writable( sq->server_socket, false );
322
+ delete_fd_handler( sq->server_socket );
323
+
324
+ close( sq->server_socket );
325
+ }
326
+ if ( send_queues != NULL ) {
327
+ delete_hash_entry( send_queues, sq->service_name );
328
+ }
329
+ else {
330
+ error( "All send queues are already deleted or not created yet." );
331
+ }
332
+ xfree( sq );
333
+ }
334
+
335
+
336
+ static void
337
+ delete_all_send_queues() {
338
+ hash_iterator iter;
339
+ hash_entry *e;
340
+
341
+ debug( "Deleting all send queues ( send_queues = %p ).", send_queues );
342
+
343
+ if ( send_queues != NULL ) {
344
+ init_hash_iterator( send_queues, &iter );
345
+ while ( ( e = iterate_hash_next( &iter ) ) != NULL ) {
346
+ delete_send_queue( e->value );
347
+ }
348
+ delete_hash( send_queues );
349
+ send_queues = NULL;
350
+ }
351
+ else {
352
+ error( "All send queues are already deleted or not created yet." );
353
+ }
354
+ }
355
+
356
+
357
+ static void
358
+ send_dump_message( uint16_t dump_type, const char *service_name, const void *data, uint32_t data_len ) {
359
+ assert( service_name != NULL );
360
+
361
+ debug( "Sending a dump message ( dump_type = %#x, service_name = %s, data = %p, data_len = %u ).",
362
+ dump_type, service_name, data, data_len );
363
+
364
+ size_t service_name_len, app_name_len;
365
+ char *dump_buf, *p;
366
+ message_dump_header *dump_hdr;
367
+ size_t dump_buf_len;
368
+
369
+ if ( _dump_service_name == NULL ) {
370
+ debug( "Dump service name is not set." );
371
+ return;
372
+ }
373
+ if ( strcmp( service_name, _dump_service_name ) == 0 ) {
374
+ debug( "Source service name and destination service name are the same ( service name = %s ).", service_name );
375
+ return;
376
+ }
377
+
378
+ struct timespec now;
379
+ if ( clock_gettime( CLOCK_REALTIME, &now ) == -1 ) {
380
+ error( "Failed to retrieve system-wide real-time clock ( %s [%d] ).", strerror( errno ), errno );
381
+ return;
382
+ }
383
+
384
+ service_name_len = strlen( service_name ) + 1;
385
+ app_name_len = strlen( _dump_app_name ) + 1;
386
+ dump_buf_len = sizeof( message_dump_header ) + app_name_len + service_name_len + data_len;
387
+ dump_buf = xmalloc( dump_buf_len );
388
+ dump_hdr = ( message_dump_header * ) dump_buf;
389
+
390
+ // header
391
+ dump_hdr->sent_time.sec = htonl( ( uint32_t ) now.tv_sec );
392
+ dump_hdr->sent_time.nsec = htonl( ( uint32_t ) now.tv_nsec );
393
+ dump_hdr->app_name_length = htons( ( uint16_t ) app_name_len );
394
+ dump_hdr->service_name_length = htons( ( uint16_t ) service_name_len );
395
+ dump_hdr->data_length = htonl( data_len );
396
+
397
+ // app name
398
+ p = dump_buf;
399
+ p += sizeof( message_dump_header );
400
+ memcpy( p, _dump_app_name, app_name_len );
401
+
402
+ // service name
403
+ p += app_name_len;
404
+ memcpy( p, service_name, service_name_len );
405
+
406
+ // data
407
+ p += service_name_len;
408
+ memcpy( p, data, data_len );
409
+
410
+ // send
411
+ send_message( _dump_service_name, dump_type, dump_buf, dump_buf_len );
412
+
413
+ xfree( dump_buf );
414
+ }
415
+
416
+
417
+ /**
418
+ * closes accepted sockets and listening socket, and releases memories.
419
+ */
420
+ static void
421
+ delete_receive_queue( void *service_name, void *_rq, void *user_data ) {
422
+ debug( "Deleting a receive queue ( service_name = %s, _rq = %p, user_data = %p ).", service_name, _rq, user_data );
423
+
424
+ receive_queue *rq = _rq;
425
+ messenger_socket *client_socket;
426
+ dlist_element *element;
427
+ receive_queue_callback *cb;
428
+
429
+ assert( rq != NULL );
430
+ for ( element = rq->message_callbacks->next; element; element = element->next ) {
431
+ cb = element->data;
432
+ debug( "Deleting a callback ( function = %p, message_type = %#x ).", cb->function, cb->message_type );
433
+ xfree( cb );
434
+ }
435
+ delete_dlist( rq->message_callbacks );
436
+
437
+ for ( element = rq->client_sockets->next; element; element = element->next ) {
438
+ client_socket = element->data;
439
+
440
+ debug( "Closing a client socket ( fd = %d ).", client_socket->fd );
441
+
442
+ set_readable( client_socket->fd, false );
443
+ delete_fd_handler( client_socket->fd );
444
+
445
+ close( client_socket->fd );
446
+ xfree( client_socket );
447
+ send_dump_message( MESSENGER_DUMP_RECV_CLOSED, rq->service_name, NULL, 0 );
448
+ }
449
+ delete_dlist( rq->client_sockets );
450
+
451
+ set_readable( rq->listen_socket, false );
452
+ delete_fd_handler( rq->listen_socket );
453
+
454
+ close( rq->listen_socket );
455
+ free_message_buffer( rq->buffer );
456
+ unlink( rq->listen_addr.sun_path );
457
+
458
+ if ( receive_queues != NULL ) {
459
+ delete_hash_entry( receive_queues, rq->service_name );
460
+ }
461
+ else {
462
+ error( "All receive queues are already deleted or not created yet." );
463
+ }
464
+ xfree( rq );
465
+ }
466
+
467
+
468
+ static void
469
+ delete_all_receive_queues() {
470
+ debug( "Deleting all receive queues ( receive_queues = %p ).", receive_queues );
471
+
472
+ if ( receive_queues != NULL ) {
473
+ foreach_hash( receive_queues, delete_receive_queue, NULL );
474
+ delete_hash( receive_queues );
475
+ receive_queues = NULL;
476
+ }
477
+ else {
478
+ error( "All receive queues are already deleted or not created yet." );
479
+ }
480
+ }
481
+
482
+
483
+ bool
484
+ finalize_messenger() {
485
+ debug( "Finalizing messenger." );
486
+
487
+ if ( !initialized ) {
488
+ warn( "Messenger is not initialized yet." );
489
+ return false;
490
+ }
491
+ if ( finalized ) {
492
+ warn( "Messenger is already finalized." );
493
+ return true;
494
+ }
495
+
496
+ if ( messenger_dump_enabled() ) {
497
+ stop_messenger_dump();
498
+ }
499
+ if ( receive_queues != NULL ) {
500
+ delete_all_receive_queues();
501
+ }
502
+ if ( send_queues != NULL ) {
503
+ delete_all_send_queues();
504
+ }
505
+ if ( context_db != NULL ) {
506
+ delete_context_db();
507
+ }
508
+
509
+ initialized = false;
510
+ finalized = true;
511
+
512
+ finalize_event_handler();
513
+
514
+ return true;
515
+ }
516
+
517
+
518
+ static message_buffer *
519
+ create_message_buffer( size_t size ) {
520
+ message_buffer *buf = xmalloc( sizeof( message_buffer ) );
521
+
522
+ buf->buffer = xmalloc( size );
523
+ buf->size = size;
524
+ buf->data_length = 0;
525
+ buf->head_offset = 0;
526
+
527
+ return buf;
528
+ }
529
+
530
+
531
+ static receive_queue *
532
+ create_receive_queue( const char *service_name ) {
533
+ assert( service_name != NULL );
534
+ assert( strlen( service_name ) < MESSENGER_SERVICE_NAME_LENGTH );
535
+
536
+ debug( "Creating a receive queue (service_name = %s).", service_name );
537
+
538
+ assert( receive_queues != NULL );
539
+ receive_queue *rq = lookup_hash_entry( receive_queues, service_name );
540
+ if ( rq != NULL ) {
541
+ warn( "Receive queue for %s is already created.", service_name );
542
+ return rq;
543
+ }
544
+
545
+ rq = xmalloc( sizeof( receive_queue ) );
546
+ memset( rq->service_name, 0, MESSENGER_SERVICE_NAME_LENGTH );
547
+ strncpy( rq->service_name, service_name, MESSENGER_SERVICE_NAME_LENGTH );
548
+
549
+ memset( &rq->listen_addr, 0, sizeof( struct sockaddr_un ) );
550
+ rq->listen_addr.sun_family = AF_UNIX;
551
+ sprintf( rq->listen_addr.sun_path, "%s/trema.%s.sock", socket_directory, service_name );
552
+ debug( "Set sun_path to %s.", rq->listen_addr.sun_path );
553
+
554
+ rq->listen_socket = socket( AF_UNIX, SOCK_SEQPACKET, 0 );
555
+ if ( rq->listen_socket == -1 ) {
556
+ error( "Failed to call socket (errno = %s [%d]).", strerror( errno ), errno );
557
+ xfree( rq );
558
+ return NULL;
559
+ }
560
+
561
+ unlink( rq->listen_addr.sun_path ); // FIXME: handle error correctly
562
+
563
+ int ret;
564
+ ret = bind( rq->listen_socket, ( struct sockaddr * ) &rq->listen_addr, sizeof( struct sockaddr_un ) );
565
+ if ( ret == -1 ) {
566
+ error( "Failed to bind (fd = %d, sun_path = %s, errno = %s [%d]).",
567
+ rq->listen_socket, rq->listen_addr.sun_path, strerror( errno ), errno );
568
+ close( rq->listen_socket );
569
+ xfree( rq );
570
+ return NULL;
571
+ }
572
+
573
+ ret = listen( rq->listen_socket, SOMAXCONN );
574
+ if ( ret == -1 ) {
575
+ error( "Failed to listen (fd = %d, sun_path = %s, errno = %s [%d]).",
576
+ rq->listen_socket, rq->listen_addr.sun_path, strerror( errno ), errno );
577
+ close( rq->listen_socket );
578
+ xfree( rq );
579
+ return NULL;
580
+ }
581
+
582
+ ret = fcntl( rq->listen_socket, F_SETFL, O_NONBLOCK );
583
+ if ( ret < 0 ) {
584
+ error( "Failed to set O_NONBLOCK ( %s [%d] ).", strerror( errno ), errno );
585
+ close( rq->listen_socket );
586
+ xfree( rq );
587
+ return NULL;
588
+ }
589
+
590
+ set_fd_handler( rq->listen_socket, on_accept, rq, NULL, NULL );
591
+ set_readable( rq->listen_socket, true );
592
+
593
+ rq->message_callbacks = create_dlist();
594
+ rq->client_sockets = create_dlist();
595
+ rq->buffer = create_message_buffer( messenger_recv_queue_length );
596
+
597
+ insert_hash_entry( receive_queues, rq->service_name, rq );
598
+
599
+ return rq;
600
+ }
601
+
602
+
603
+ static bool
604
+ add_message_callback( const char *service_name, uint8_t message_type, void *callback ) {
605
+ assert( receive_queues != NULL );
606
+ assert( service_name != NULL );
607
+ assert( callback != NULL );
608
+
609
+ debug( "Adding a message callback (service_name = %s, message_type = %#x, callback = %p).",
610
+ service_name, message_type, callback );
611
+
612
+ receive_queue *rq = lookup_hash_entry( receive_queues, service_name );
613
+ if ( rq == NULL ) {
614
+ debug( "No receive queue found. Creating." );
615
+ rq = create_receive_queue( service_name );
616
+ if ( rq == NULL ) {
617
+ error( "Failed to create a receive queue." );
618
+ return false;
619
+ }
620
+ }
621
+
622
+ receive_queue_callback *cb = xmalloc( sizeof( receive_queue_callback ) );
623
+ cb->message_type = message_type;
624
+ cb->function = callback;
625
+ insert_after_dlist( rq->message_callbacks, cb );
626
+
627
+ return true;
628
+ }
629
+
630
+
631
+ static bool
632
+ _add_message_received_callback( const char *service_name, const callback_message_received callback ) {
633
+ assert( service_name != NULL );
634
+ assert( callback != NULL );
635
+
636
+ debug( "Adding a message received callback (service_name = %s, callback = %p).",
637
+ service_name, callback );
638
+
639
+ return add_message_callback( service_name, MESSAGE_TYPE_NOTIFY, callback );
640
+ }
641
+ bool ( *add_message_received_callback )( const char *service_name, const callback_message_received function ) = _add_message_received_callback;
642
+
643
+
644
+ static bool
645
+ _add_message_requested_callback( const char *service_name,
646
+ void ( *callback )( const messenger_context_handle *handle, uint16_t tag, void *data, size_t len ) ) {
647
+ assert( service_name != NULL );
648
+ assert( callback != NULL );
649
+
650
+ debug( "Adding a message requested callback ( service_name = %s, callback = %p ).",
651
+ service_name, callback );
652
+
653
+ return add_message_callback( service_name, MESSAGE_TYPE_REQUEST, callback );
654
+ }
655
+ bool ( *add_message_requested_callback )( const char *service_name, void ( *callback )( const messenger_context_handle *handle, uint16_t tag, void *data, size_t len ) ) = _add_message_requested_callback;
656
+
657
+
658
+ static bool
659
+ _add_message_replied_callback( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) {
660
+ assert( service_name != NULL );
661
+ assert( callback != NULL );
662
+
663
+ debug( "Adding a message replied callback ( service_name = %s, callback = %p ).",
664
+ service_name, callback );
665
+
666
+ return add_message_callback( service_name, MESSAGE_TYPE_REPLY, callback );
667
+ }
668
+ bool ( *add_message_replied_callback )( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) = _add_message_replied_callback;
669
+
670
+
671
+ static bool
672
+ delete_message_callback( const char *service_name, uint8_t message_type, void ( *callback ) ) {
673
+ assert( service_name != NULL );
674
+ assert( callback != NULL );
675
+
676
+ debug( "Deleting a message callback ( service_name = %s, message_type = %#x, callback = %p ).",
677
+ service_name, message_type, callback );
678
+
679
+ if ( receive_queues == NULL ) {
680
+ debug( "All receive queues are already deleted or not created yet." );
681
+ return false;
682
+ }
683
+
684
+ receive_queue *rq = lookup_hash_entry( receive_queues, service_name );
685
+ receive_queue_callback *cb;
686
+
687
+ if ( NULL != rq ) {
688
+ dlist_element *e;
689
+ for ( e = rq->message_callbacks->next; e; e = e->next ) {
690
+ cb = e->data;
691
+ if ( ( cb->function == callback ) && ( cb->message_type == message_type ) ) {
692
+ debug( "Deleting a callback ( message_type = %#x, callback = %p ).", message_type, callback );
693
+ xfree( cb );
694
+ delete_dlist_element( e );
695
+ if ( rq->message_callbacks->next == NULL ) {
696
+ debug( "No more callback for message_type = %#x.", message_type );
697
+ delete_receive_queue( rq->service_name, rq, NULL );
698
+ }
699
+ return true;
700
+ }
701
+ }
702
+ }
703
+
704
+ error( "No registered message callback found." );
705
+
706
+ return false;
707
+ }
708
+
709
+
710
+ static bool
711
+ _delete_message_received_callback( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len ) ) {
712
+ assert( service_name != NULL );
713
+ assert( callback != NULL );
714
+
715
+ debug( "Deleting a message received callback ( service_name = %s, callback = %p ).",
716
+ service_name, callback );
717
+
718
+ return delete_message_callback( service_name, MESSAGE_TYPE_NOTIFY, callback );
719
+ }
720
+ bool ( *delete_message_received_callback )( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len ) ) = _delete_message_received_callback;
721
+
722
+
723
+ static bool
724
+ _delete_message_requested_callback( const char *service_name,
725
+ void ( *callback )( const messenger_context_handle *handle, uint16_t tag, void *data, size_t len ) ) {
726
+ assert( service_name != NULL );
727
+ assert( callback != NULL );
728
+
729
+ debug( "Deleting a message requested callback ( service_name = %s, callback = %p ).",
730
+ service_name, callback );
731
+
732
+ return delete_message_callback( service_name, MESSAGE_TYPE_REQUEST, callback );
733
+ }
734
+ bool ( *delete_message_requested_callback )( const char *service_name, void ( *callback )( const messenger_context_handle *handle, uint16_t tag, void *data, size_t len ) ) = _delete_message_requested_callback;
735
+
736
+
737
+ static bool
738
+ _delete_message_replied_callback( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) {
739
+ assert( service_name != NULL );
740
+ assert( callback != NULL );
741
+
742
+ debug( "Deleting a message replied callback ( service_name = %s, callback = %p ).",
743
+ service_name, callback );
744
+
745
+ return delete_message_callback( service_name, MESSAGE_TYPE_REPLY, callback );
746
+ }
747
+ bool ( *delete_message_replied_callback )( const char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) = _delete_message_replied_callback;
748
+
749
+
750
+ static bool
751
+ _rename_message_received_callback( const char *old_service_name, const char *new_service_name ) {
752
+ assert( old_service_name != NULL );
753
+ assert( new_service_name != NULL );
754
+ assert( receive_queues != NULL );
755
+
756
+ debug( "Renaming a message received callback ( old_service_name = %s, new_service_name = %s ).",
757
+ old_service_name, new_service_name );
758
+
759
+ receive_queue *old_rq = lookup_hash_entry( receive_queues, old_service_name );
760
+ receive_queue *new_rq = lookup_hash_entry( receive_queues, new_service_name );
761
+ dlist_element *element;
762
+ receive_queue_callback *cb;
763
+
764
+ if ( old_rq == NULL ) {
765
+ error( "No receive queue for old service name ( %s ) found.", old_service_name );
766
+ return false;
767
+ }
768
+ else if ( new_rq != NULL ) {
769
+ error( "Receive queue for new service name ( %s ) is already created.", new_service_name );
770
+ return false;
771
+ }
772
+
773
+ for ( element = old_rq->message_callbacks->next; element; element = element->next ) {
774
+ cb = element->data;
775
+ add_message_callback( new_service_name, cb->message_type, cb->function );
776
+ }
777
+
778
+ delete_receive_queue( old_rq->service_name, old_rq, NULL );
779
+
780
+ return true;
781
+ }
782
+ bool ( *rename_message_received_callback )( const char *old_service_name, const char *new_service_name ) = _rename_message_received_callback;
783
+
784
+
785
+ static size_t
786
+ message_buffer_remain_bytes( message_buffer *buf ) {
787
+ assert( buf != NULL );
788
+
789
+ return buf->size - buf->data_length;
790
+ }
791
+
792
+
793
+ /**
794
+ * connects send_queue to the service
795
+ * return value: -1:error, 0:refused (retry), 1:connected
796
+ */
797
+ static int
798
+ send_queue_connect( send_queue *sq ) {
799
+ assert( sq != NULL );
800
+
801
+ sq->running_timer = false;
802
+ if ( ( sq->server_socket = socket( AF_UNIX, SOCK_SEQPACKET, 0 ) ) == -1 ) {
803
+ error( "Failed to call socket ( errno = %s [%d] ).", strerror( errno ), errno );
804
+ return -1;
805
+ }
806
+
807
+ if ( geteuid() == 0 ) {
808
+ int wmem_size = 1048576;
809
+ int ret = setsockopt( sq->server_socket, SOL_SOCKET, SO_SNDBUFFORCE, ( const void * ) &wmem_size, ( socklen_t ) sizeof( wmem_size ) );
810
+ if ( ret < 0 ) {
811
+ error( "Failed to set SO_SNDBUFFORCE to %d ( %s [%d] ).", wmem_size, strerror( errno ), errno );
812
+ close( sq->server_socket );
813
+ sq->server_socket = -1;
814
+ return -1;
815
+ }
816
+ }
817
+ int ret = fcntl( sq->server_socket, F_SETFL, O_NONBLOCK );
818
+ if ( ret < 0 ) {
819
+ error( "Failed to set O_NONBLOCK ( %s [%d] ).", strerror( errno ), errno );
820
+ close( sq->server_socket );
821
+ sq->server_socket = -1;
822
+ return -1;
823
+ }
824
+
825
+ if ( connect( sq->server_socket, ( struct sockaddr * ) &sq->server_addr, sizeof( struct sockaddr_un ) ) == -1 ) {
826
+ debug( "Connection refused ( service_name = %s, sun_path = %s, fd = %d, errno = %s [%d] ).",
827
+ sq->service_name, sq->server_addr.sun_path, sq->server_socket, strerror( errno ), errno );
828
+
829
+ send_dump_message( MESSENGER_DUMP_SEND_REFUSED, sq->service_name, NULL, 0 );
830
+ close( sq->server_socket );
831
+ sq->server_socket = -1;
832
+
833
+ return 0;
834
+ }
835
+
836
+ set_fd_handler( sq->server_socket, on_send_read, sq, &on_send_write, sq );
837
+ set_readable( sq->server_socket, true );
838
+
839
+ if ( sq->buffer != NULL && sq->buffer->data_length >= sizeof( message_header ) ) {
840
+ set_writable( sq->server_socket, true );
841
+ }
842
+
843
+ debug( "Connection established ( service_name = %s, sun_path = %s, fd = %d ).",
844
+ sq->service_name, sq->server_addr.sun_path, sq->server_socket );
845
+
846
+ socklen_t optlen = sizeof ( sq->socket_buffer_size );
847
+ if ( getsockopt( sq->server_socket, SOL_SOCKET, SO_SNDBUF, &sq->socket_buffer_size, &optlen ) == -1 ) {
848
+ sq->socket_buffer_size = 0;
849
+ }
850
+
851
+ send_dump_message( MESSENGER_DUMP_SEND_CONNECTED, sq->service_name, NULL, 0 );
852
+
853
+ return 1;
854
+ }
855
+
856
+
857
+ static int send_queue_connect_timer( send_queue *sq );
858
+
859
+ static int
860
+ send_queue_connect_timeout( send_queue *sq ) {
861
+ sq->running_timer = false;
862
+ return send_queue_connect_timer( sq );
863
+ }
864
+
865
+ // Remember to clean up timer if we delete the send_queue.
866
+
867
+ static int
868
+ send_queue_connect_timer( send_queue *sq ) {
869
+ struct itimerspec interval;
870
+ if ( sq->server_socket != -1 ) {
871
+ return 1;
872
+ }
873
+ if ( sq->running_timer ) {
874
+ sq->running_timer = false;
875
+ delete_timer_event( ( timer_callback )send_queue_connect_timeout, sq );
876
+ }
877
+
878
+ int ret = send_queue_connect( sq );
879
+
880
+ switch ( ret ) {
881
+ case -1:
882
+ // Print an error, and find a better way of indicating the send
883
+ // queue has an error.
884
+ sq->reconnect_interval.tv_sec = -1;
885
+ sq->reconnect_interval.tv_nsec = 0;
886
+ return -1;
887
+
888
+ case 0:
889
+ // Try again later.
890
+ sq->refused_count++;
891
+ sq->reconnect_interval.tv_sec = ( 1 << ( sq->refused_count > 4 ? 4 : sq->refused_count - 1 ) );
892
+
893
+ interval.it_interval.tv_sec = 0;
894
+ interval.it_interval.tv_nsec = 0;
895
+ interval.it_value = sq->reconnect_interval;
896
+ add_timer_event_callback( &interval, ( void (*)(void *) )send_queue_connect_timeout, ( void * ) sq );
897
+ sq->running_timer = true;
898
+
899
+ debug( "refused_count = %d, reconnect_interval = %u.", sq->refused_count, sq->reconnect_interval.tv_sec );
900
+ return 0;
901
+
902
+ case 1:
903
+ // Success.
904
+ sq->refused_count = 0;
905
+ sq->reconnect_interval.tv_sec = 0;
906
+ sq->reconnect_interval.tv_nsec = 0;
907
+ return 1;
908
+
909
+ default:
910
+ die( "Got invalid value from send_queue_connect_timer( send_queue* )." );
911
+ };
912
+
913
+ return -1;
914
+ }
915
+
916
+
917
+ static int
918
+ send_queue_try_connect( send_queue *sq ) {
919
+ // TODO: Add a proper check for this.
920
+ if ( sq->reconnect_interval.tv_sec != 0 ) {
921
+ return 0;
922
+ }
923
+
924
+ return send_queue_connect_timer( sq );
925
+ }
926
+
927
+
928
+ /**
929
+ * creates send_queue and connects to specified service name.
930
+ */
931
+ static send_queue *
932
+ create_send_queue( const char *service_name ) {
933
+ assert( service_name != NULL );
934
+
935
+ debug( "Creating a send queue ( service_name = %s ).", service_name );
936
+
937
+ send_queue *sq;
938
+
939
+ assert( send_queues != NULL );
940
+
941
+ sq = lookup_hash_entry( send_queues, service_name );
942
+ if ( NULL != sq ) {
943
+ warn( "Send queue for %s is already created.", service_name );
944
+ return sq;
945
+ }
946
+
947
+ sq = xmalloc( sizeof( send_queue ) );
948
+ memset( sq->service_name, 0, MESSENGER_SERVICE_NAME_LENGTH );
949
+ strncpy( sq->service_name, service_name, MESSENGER_SERVICE_NAME_LENGTH );
950
+
951
+ memset( &sq->server_addr, 0, sizeof( struct sockaddr_un ) );
952
+ sq->server_addr.sun_family = AF_UNIX;
953
+ sprintf( sq->server_addr.sun_path, "%s/trema.%s.sock", socket_directory, service_name );
954
+ debug( "Set sun_path to %s.", sq->server_addr.sun_path );
955
+
956
+ sq->server_socket = -1;
957
+ sq->buffer = NULL;
958
+ sq->refused_count = 0;
959
+ sq->reconnect_interval.tv_sec = 0;
960
+ sq->reconnect_interval.tv_nsec = 0;
961
+ sq->running_timer = false;
962
+ sq->overflow = 0;
963
+ sq->overflow_total_length = 0;
964
+ sq->socket_buffer_size = 0;
965
+
966
+ if ( send_queue_try_connect( sq ) == -1 ) {
967
+ xfree( sq );
968
+ error( "Failed to create a send queue for %s.", service_name );
969
+ return NULL;
970
+ }
971
+
972
+ sq->buffer = create_message_buffer( messenger_send_queue_length );
973
+
974
+ insert_hash_entry( send_queues, sq->service_name, sq );
975
+
976
+ return sq;
977
+ }
978
+
979
+
980
+ static bool
981
+ write_message_buffer( message_buffer *buf, const void *data, size_t len ) {
982
+ assert( buf != NULL );
983
+
984
+ if ( message_buffer_remain_bytes( buf ) < len ) {
985
+ return false;
986
+ }
987
+
988
+ if ( ( buf->head_offset + buf->data_length + len ) <= buf->size ) {
989
+ memcpy( ( char * ) get_message_buffer_head( buf ) + buf->data_length, data, len );
990
+ }
991
+ else {
992
+ memmove( buf->buffer, ( char * ) get_message_buffer_head( buf ), buf->data_length );
993
+ buf->head_offset = 0;
994
+ memcpy( ( char * ) buf->buffer + buf->data_length, data, len );
995
+ }
996
+ buf->data_length += len;
997
+
998
+ return true;
999
+ }
1000
+
1001
+
1002
+ static bool
1003
+ push_message_to_send_queue( const char *service_name, const uint8_t message_type, const uint16_t tag, const void *data, size_t len ) {
1004
+ assert( service_name != NULL );
1005
+
1006
+ debug( "Pushing a message to send queue ( service_name = %s, message_type = %#x, tag = %#x, data = %p, len = %u ).",
1007
+ service_name, message_type, tag, data, len );
1008
+
1009
+ message_header header;
1010
+
1011
+ if ( send_queues == NULL ) {
1012
+ error( "All send queues are already deleted or not created yet." );
1013
+ return false;
1014
+ }
1015
+
1016
+ send_queue *sq = lookup_hash_entry( send_queues, service_name );
1017
+
1018
+ if ( NULL == sq ) {
1019
+ sq = create_send_queue( service_name );
1020
+ assert( sq != NULL );
1021
+ }
1022
+
1023
+ header.version = 0;
1024
+ header.message_type = message_type;
1025
+ header.tag = htons( tag );
1026
+ uint32_t length = ( uint32_t ) ( sizeof( message_header ) + len );
1027
+ header.message_length = htonl( length );
1028
+
1029
+ if ( message_buffer_remain_bytes( sq->buffer ) < length ) {
1030
+ if ( sq->overflow == 0 ) {
1031
+ warn( "Could not write a message to send queue due to overflow ( service_name = %s, fd = %u, length = %u ).", sq->service_name, sq->server_socket, length );
1032
+ }
1033
+ ++sq->overflow;
1034
+ sq->overflow_total_length += length;
1035
+ send_dump_message( MESSENGER_DUMP_SEND_OVERFLOW, sq->service_name, NULL, 0 );
1036
+ return false;
1037
+ }
1038
+ if ( sq->overflow > 1 ) {
1039
+ warn( "Could not write a message to send queue due to overflow ( service_name = %s, fd = %u, count = %u, total length = %" PRIu64 " ).", sq->service_name, sq->server_socket, sq->overflow, sq->overflow_total_length );
1040
+ }
1041
+ sq->overflow = 0;
1042
+ sq->overflow_total_length = 0;
1043
+
1044
+ write_message_buffer( sq->buffer, &header, sizeof( message_header ) );
1045
+ write_message_buffer( sq->buffer, data, len );
1046
+
1047
+ if ( sq->server_socket == -1 ) {
1048
+ debug( "Tried to send message on closed send queue, connecting..." );
1049
+
1050
+ send_queue_try_connect( sq );
1051
+ return true;
1052
+ }
1053
+
1054
+ set_writable( sq->server_socket, true );
1055
+ if ( sq->buffer->data_length > messenger_send_length_for_flush ) {
1056
+ on_send_write( sq->server_socket, sq );
1057
+ }
1058
+ return true;
1059
+ }
1060
+
1061
+
1062
+ static bool
1063
+ _send_message( const char *service_name, const uint16_t tag, const void *data, size_t len ) {
1064
+ assert( service_name != NULL );
1065
+
1066
+ debug( "Sending a message ( service_name = %s, tag = %#x, data = %p, len = %u ).",
1067
+ service_name, tag, data, len );
1068
+
1069
+ return push_message_to_send_queue( service_name, MESSAGE_TYPE_NOTIFY, tag, data, len );
1070
+ }
1071
+ bool ( *send_message )( const char *service_name, const uint16_t tag, const void *data, size_t len ) = _send_message;
1072
+
1073
+
1074
+ static messenger_context *
1075
+ insert_context( void *user_data ) {
1076
+ messenger_context *context = xmalloc( sizeof( messenger_context ) );
1077
+
1078
+ context->transaction_id = ++last_transaction_id;
1079
+ context->life_count = 10;
1080
+ context->user_data = user_data;
1081
+
1082
+ debug( "Inserting a new context ( transaction_id = %#x, life_count = %d, user_data = %p ).",
1083
+ context->transaction_id, context->life_count, context->user_data );
1084
+
1085
+ messenger_context *old = insert_hash_entry( context_db, &context->transaction_id, context );
1086
+ if ( old != NULL ) {
1087
+ delete_context( old );
1088
+ }
1089
+
1090
+ return context;
1091
+ }
1092
+
1093
+
1094
+ static bool
1095
+ _send_request_message( const char *to_service_name, const char *from_service_name, const uint16_t tag, const void *data, size_t len, void *user_data ) {
1096
+ assert( to_service_name != NULL );
1097
+ assert( from_service_name != NULL );
1098
+
1099
+ debug( "Sending a request message ( to_service_name = %s, from_service_name = %s, tag = %#x, data = %p, len = %u, user_data = %p ).",
1100
+ to_service_name, from_service_name, tag, data, len, user_data );
1101
+
1102
+ char *request_data, *p;
1103
+ size_t from_service_name_len = strlen( from_service_name ) + 1;
1104
+ size_t handle_len = sizeof( messenger_context_handle ) + from_service_name_len;
1105
+ messenger_context *context;
1106
+ messenger_context_handle *handle;
1107
+ bool return_value;
1108
+
1109
+ context = insert_context( user_data );
1110
+
1111
+ request_data = xmalloc( handle_len + len );
1112
+ handle = ( messenger_context_handle * ) request_data;
1113
+ handle->transaction_id = htonl( context->transaction_id );
1114
+ handle->service_name_len = htons( ( uint16_t ) from_service_name_len );
1115
+ strcpy( handle->service_name, from_service_name );
1116
+ p = request_data + handle_len;
1117
+ memcpy( p, data, len );
1118
+
1119
+ return_value = push_message_to_send_queue( to_service_name, MESSAGE_TYPE_REQUEST, tag, request_data, handle_len + len );
1120
+
1121
+ xfree( request_data );
1122
+
1123
+ return return_value;
1124
+ }
1125
+ bool ( *send_request_message )( const char *to_service_name, const char *from_service_name, const uint16_t tag, const void *data, size_t len, void *user_data ) = _send_request_message;
1126
+
1127
+
1128
+ static bool
1129
+ _send_reply_message( const messenger_context_handle *handle, const uint16_t tag, const void *data, size_t len ) {
1130
+ assert( handle != NULL );
1131
+
1132
+ debug( "Sending a reply message ( handle = [ transaction_id = %#x, service_name_len = %u, service_name = %s ], "
1133
+ "tag = %#x, data = %p, len = %u ).",
1134
+ handle->transaction_id, handle->service_name_len, handle->service_name, tag, data, len );
1135
+
1136
+ char *reply_data;
1137
+ messenger_context_handle *reply_handle;
1138
+ bool return_value;
1139
+
1140
+ reply_data = xmalloc( sizeof( messenger_context_handle ) + len );
1141
+ reply_handle = ( messenger_context_handle * ) reply_data;
1142
+ reply_handle->transaction_id = htonl( handle->transaction_id );
1143
+ reply_handle->service_name_len = htons( 0 );
1144
+ memcpy( reply_handle->service_name, data, len );
1145
+
1146
+ return_value = push_message_to_send_queue( handle->service_name, MESSAGE_TYPE_REPLY, tag, reply_data, sizeof( messenger_context_handle ) + len );
1147
+
1148
+ xfree( reply_data );
1149
+
1150
+ return return_value;
1151
+ }
1152
+ bool ( *send_reply_message )( const messenger_context_handle *handle, const uint16_t tag, const void *data, size_t len ) = _send_reply_message;
1153
+
1154
+
1155
+ static void
1156
+ number_of_send_queue( int *connected_count, int *sending_count, int *reconnecting_count, int *closed_count ) {
1157
+ assert( connected_count != NULL );
1158
+ assert( sending_count != NULL );
1159
+ assert( reconnecting_count != NULL );
1160
+ assert( closed_count != NULL );
1161
+
1162
+ debug( "Checking queue statuses." );
1163
+
1164
+ hash_iterator iter;
1165
+ hash_entry *e;
1166
+
1167
+ *connected_count = 0;
1168
+ *sending_count = 0;
1169
+ *reconnecting_count = 0;
1170
+ *closed_count = 0;
1171
+
1172
+ if ( send_queues == NULL ) {
1173
+ error( "All send queues are already deleted or not created yet." );
1174
+ return;
1175
+ }
1176
+
1177
+ init_hash_iterator( send_queues, &iter );
1178
+ while ( ( e = iterate_hash_next( &iter ) ) != NULL ) {
1179
+ send_queue *sq = e->value;
1180
+ if ( sq->server_socket != -1 ) {
1181
+ if ( sq->buffer->data_length == 0 ) {
1182
+ ( *connected_count )++;
1183
+ }
1184
+ else {
1185
+ if ( sq->refused_count > 0 ) {
1186
+ ( *reconnecting_count )++;
1187
+ }
1188
+ else {
1189
+ ( *sending_count )++;
1190
+ }
1191
+ }
1192
+ }
1193
+ else {
1194
+ ( *closed_count )++;
1195
+ }
1196
+ }
1197
+
1198
+ debug( "connected_count = %d, reconnecting_count = %d, sending_count = %d, closed_count = %d.",
1199
+ *connected_count, *reconnecting_count, *sending_count, *closed_count );
1200
+ }
1201
+
1202
+
1203
+ static void
1204
+ add_recv_queue_client_fd( receive_queue *rq, int fd ) {
1205
+ assert( rq != NULL );
1206
+ assert( fd >= 0 );
1207
+
1208
+ debug( "Adding a client fd to receive queue ( fd = %d, service_name = %s ).", fd, rq->service_name );
1209
+
1210
+ messenger_socket *socket;
1211
+
1212
+ socket = xmalloc( sizeof( messenger_socket ) );
1213
+ socket->fd = fd;
1214
+ insert_after_dlist( rq->client_sockets, socket );
1215
+
1216
+ set_fd_handler( fd, on_recv, rq, NULL, NULL );
1217
+ set_readable( fd, true );
1218
+ }
1219
+
1220
+
1221
+ static void
1222
+ on_accept( int fd, void *data ) {
1223
+ receive_queue *rq = ( receive_queue* )data;
1224
+
1225
+ assert( rq != NULL );
1226
+
1227
+ int client_fd;
1228
+ struct sockaddr_un addr;
1229
+
1230
+ socklen_t addr_len = sizeof( struct sockaddr_un );
1231
+
1232
+ if ( ( client_fd = accept( fd, ( struct sockaddr * ) &addr, &addr_len ) ) == -1 ) {
1233
+ error( "Failed to accept ( fd = %d, errno = %s [%d] ).", fd, strerror( errno ), errno );
1234
+ return;
1235
+ }
1236
+
1237
+ if ( geteuid() == 0 ) {
1238
+ int rmem_size = 1048576;
1239
+ int ret = setsockopt( client_fd, SOL_SOCKET, SO_RCVBUFFORCE, ( const void * ) &rmem_size, ( socklen_t ) sizeof( rmem_size ) );
1240
+ if ( ret < 0 ) {
1241
+ error( "Failed to set SO_RCVBUFFORCE to %d ( %s [%d] ).", rmem_size, strerror( errno ), errno );
1242
+ close( client_fd );
1243
+ return;
1244
+ }
1245
+ }
1246
+ int ret = fcntl( client_fd, F_SETFL, O_NONBLOCK );
1247
+ if ( ret < 0 ) {
1248
+ error( "Failed to set O_NONBLOCK ( %s [%d] ).", strerror( errno ), errno );
1249
+ close( client_fd );
1250
+ return;
1251
+ }
1252
+
1253
+ add_recv_queue_client_fd( rq, client_fd );
1254
+ send_dump_message( MESSENGER_DUMP_RECV_CONNECTED, rq->service_name, NULL, 0 );
1255
+ }
1256
+
1257
+
1258
+ static int
1259
+ del_recv_queue_client_fd( receive_queue *rq, int fd ) {
1260
+ assert( rq != NULL );
1261
+ assert( fd >= 0 );
1262
+
1263
+ messenger_socket *socket;
1264
+ dlist_element *element;
1265
+
1266
+ debug( "Deleting a client fd from receive queue ( fd = %d, service_name = %s ).", fd, rq->service_name );
1267
+
1268
+ for ( element = rq->client_sockets->next; element; element = element->next ) {
1269
+ socket = element->data;
1270
+ if ( socket->fd == fd ) {
1271
+ set_readable( fd, false );
1272
+ delete_fd_handler( fd );
1273
+
1274
+ debug( "Deleting fd ( %d ).", fd );
1275
+ delete_dlist_element( element );
1276
+ xfree( socket );
1277
+ return 1;
1278
+ }
1279
+ }
1280
+
1281
+ return 0;
1282
+ }
1283
+
1284
+
1285
+ static void
1286
+ truncate_message_buffer( message_buffer *buf, size_t len ) {
1287
+ assert( buf != NULL );
1288
+
1289
+ if ( len == 0 || buf->data_length == 0 ) {
1290
+ return;
1291
+ }
1292
+
1293
+ if ( len > buf->data_length ) {
1294
+ len = buf->data_length;
1295
+ }
1296
+
1297
+ if ( ( buf->head_offset + len ) <= buf->size ) {
1298
+ buf->head_offset += len;
1299
+ }
1300
+ else {
1301
+ memmove( buf->buffer, ( char * ) buf->buffer + buf->head_offset + len, buf->data_length - len );
1302
+ buf->head_offset = 0;
1303
+ }
1304
+ buf->data_length -= len;
1305
+ }
1306
+
1307
+
1308
+ /**
1309
+ * pulls message data from recv_queue.
1310
+ * returns 1 if succeeded, otherwise 0.
1311
+ */
1312
+ static int
1313
+ pull_from_recv_queue( receive_queue *rq, uint8_t *message_type, uint16_t *tag, void *data, size_t *len, size_t maxlen ) {
1314
+ assert( rq != NULL );
1315
+ assert( message_type != NULL );
1316
+ assert( tag != NULL );
1317
+ assert( data != NULL );
1318
+ assert( len != NULL );
1319
+
1320
+ debug( "Pulling a message from receive queue ( service_name = %s ).", rq->service_name );
1321
+
1322
+ message_header *header;
1323
+
1324
+ if ( rq->buffer->data_length < sizeof( message_header ) ) {
1325
+ debug( "Queue length is smaller than a message header ( queue length = %u ).", rq->buffer->data_length );
1326
+ return 0;
1327
+ }
1328
+
1329
+ header = ( message_header * ) get_message_buffer_head( rq->buffer );
1330
+
1331
+ uint32_t length = ntohl( header->message_length );
1332
+ assert( length != 0 );
1333
+ assert( length < messenger_recv_queue_length );
1334
+ if ( rq->buffer->data_length < length ) {
1335
+ debug( "Queue length is smaller than message length ( queue length = %u, message length = %u ).",
1336
+ rq->buffer->data_length, length );
1337
+ return 0;
1338
+ }
1339
+
1340
+ *message_type = header->message_type;
1341
+ *tag = ntohs( header->tag );
1342
+ *len = length - sizeof( message_header );
1343
+ memcpy( data, header->value, *len > maxlen ? maxlen : *len );
1344
+ truncate_message_buffer( rq->buffer, length );
1345
+
1346
+ debug( "A message is retrieved from receive queue ( message_type = %#x, tag = %#x, len = %u, data = %p ).",
1347
+ *message_type, *tag, *len, data );
1348
+
1349
+ return 1;
1350
+ }
1351
+
1352
+
1353
+ static messenger_context *
1354
+ get_context( uint32_t transaction_id ) {
1355
+ debug( "Looking up a context ( transaction_id = %#x ).", transaction_id );
1356
+
1357
+ return lookup_hash_entry( context_db, &transaction_id );
1358
+ }
1359
+
1360
+
1361
+ static void
1362
+ call_message_callbacks( receive_queue *rq, const uint8_t message_type, const uint16_t tag, void *data, size_t len ) {
1363
+ assert( rq != NULL );
1364
+
1365
+ dlist_element *element;
1366
+ receive_queue_callback *cb;
1367
+
1368
+ debug( "Calling message callbacks ( service_name = %s, message_type = %#x, tag = %#x, data = %p, len = %u ).",
1369
+ rq->service_name, message_type, tag, data, len );
1370
+
1371
+ for ( element = rq->message_callbacks->next; element; element = element->next ) {
1372
+ cb = element->data;
1373
+ if ( cb->message_type != message_type ) {
1374
+ continue;
1375
+ }
1376
+ switch ( message_type ) {
1377
+ case MESSAGE_TYPE_NOTIFY:
1378
+ {
1379
+ void ( *received_callback )( uint16_t tag, void *data, size_t len );
1380
+ received_callback = cb->function;
1381
+
1382
+ debug( "Calling a callback ( %p ) for MESSAGE_TYPE_NOTIFY (%#x) ( tag = %#x, data = %p, len = %u ).",
1383
+ cb->function, message_type, tag, data, len );
1384
+
1385
+ received_callback( tag, data, len );
1386
+ }
1387
+ break;
1388
+ case MESSAGE_TYPE_REQUEST:
1389
+ {
1390
+ void ( *requested_callback )( const messenger_context_handle *handle, uint16_t tag, void *data, size_t len );
1391
+ messenger_context_handle *handle;
1392
+ char *requested_data;
1393
+ size_t header_len;
1394
+
1395
+ requested_callback = cb->function;
1396
+ handle = ( messenger_context_handle * ) data;
1397
+ handle->transaction_id = ntohl( handle->transaction_id );
1398
+ handle->service_name_len = ntohs( handle->service_name_len );
1399
+ header_len = sizeof( messenger_context_handle ) + handle->service_name_len;
1400
+ requested_data = ( ( char * ) data ) + header_len;
1401
+
1402
+ debug( "Calling a callback ( %p ) for MESSAGE_TYPE_REQUEST (%#x) ( handle = %p, tag = %#x, requested_data = %p, len = %u ).",
1403
+ cb->function, message_type, handle, tag, requested_data, len - header_len );
1404
+
1405
+ requested_callback( handle, tag, ( void * ) requested_data, len - header_len );
1406
+ }
1407
+ break;
1408
+ case MESSAGE_TYPE_REPLY:
1409
+ {
1410
+ debug( "Calling a callback ( %p ) for MESSAGE_TYPE_REPLY (%#x).", cb->function, message_type );
1411
+
1412
+ void ( *replied_callback )( uint16_t tag, void *data, size_t len, void *user_data );
1413
+ messenger_context_handle *reply_handle;
1414
+ messenger_context *context;
1415
+
1416
+ replied_callback = cb->function;
1417
+ reply_handle = data;
1418
+ reply_handle->transaction_id = ntohl( reply_handle->transaction_id );
1419
+ reply_handle->service_name_len = ntohs( reply_handle->service_name_len );
1420
+
1421
+ context = get_context( reply_handle->transaction_id );
1422
+
1423
+ if ( NULL != context ) {
1424
+ debug( "tag = %#x, data = %p, len = %u, user_data = %p.",
1425
+ tag, reply_handle->service_name, len - sizeof( messenger_context_handle ), context->user_data );
1426
+ replied_callback( tag, reply_handle->service_name, len - sizeof( messenger_context_handle ), context->user_data );
1427
+ delete_context( context );
1428
+ }
1429
+ else {
1430
+ warn( "No context found." );
1431
+ }
1432
+ }
1433
+ break;
1434
+ default:
1435
+ error( "Unknown message type ( %#x ).", message_type );
1436
+ assert( 0 );
1437
+ }
1438
+ }
1439
+ }
1440
+
1441
+
1442
+ static void
1443
+ on_recv( int fd, void *data ) {
1444
+ receive_queue *rq = ( receive_queue* )data;
1445
+
1446
+ assert( rq != NULL );
1447
+ assert( fd >= 0 );
1448
+
1449
+ debug( "Receiving data from remote ( fd = %d, service_name = %s ).", fd, rq->service_name );
1450
+
1451
+ uint8_t buf[ MESSENGER_RECV_BUFFER ];
1452
+ ssize_t recv_len;
1453
+ size_t buf_len;
1454
+ uint8_t message_type;
1455
+ uint16_t tag;
1456
+
1457
+ while ( ( buf_len = message_buffer_remain_bytes( rq->buffer ) ) > messenger_recv_queue_reserved ) {
1458
+ if ( buf_len > sizeof( buf ) ) {
1459
+ buf_len = sizeof( buf );
1460
+ }
1461
+ recv_len = recv( fd, buf, buf_len, 0 );
1462
+ if ( recv_len == -1 ) {
1463
+ if ( errno != EAGAIN && errno != EWOULDBLOCK ) {
1464
+ error( "Failed to recv ( fd = %d, errno = %s [%d] ).", fd, strerror( errno ), errno );
1465
+ send_dump_message( MESSENGER_DUMP_RECV_CLOSED, rq->service_name, NULL, 0 );
1466
+ del_recv_queue_client_fd( rq, fd );
1467
+ close( fd );
1468
+ }
1469
+ else {
1470
+ debug( "Failed to recv ( fd = %d, errno = %s [%d] ).", fd, strerror( errno ), errno );
1471
+ }
1472
+ break;
1473
+ }
1474
+ else if ( recv_len == 0 ) {
1475
+ debug( "Connection closed ( fd = %d, service_name = %s ).", fd, rq->service_name );
1476
+ send_dump_message( MESSENGER_DUMP_RECV_CLOSED, rq->service_name, NULL, 0 );
1477
+ del_recv_queue_client_fd( rq, fd );
1478
+ close( fd );
1479
+ break;
1480
+ }
1481
+
1482
+ if ( !write_message_buffer( rq->buffer, buf, ( size_t ) recv_len ) ) {
1483
+ warn( "Could not write a message to receive queue due to overflow ( service_name = %s, len = %u ).", rq->service_name, recv_len );
1484
+ send_dump_message( MESSENGER_DUMP_RECV_OVERFLOW, rq->service_name, buf, ( uint32_t ) recv_len );
1485
+ }
1486
+ else {
1487
+ debug( "Pushing a message to receive queue ( service_name = %s, len = %u ).", rq->service_name, recv_len );
1488
+ send_dump_message( MESSENGER_DUMP_RECEIVED, rq->service_name, buf, ( uint32_t ) recv_len );
1489
+ }
1490
+ }
1491
+
1492
+ while ( pull_from_recv_queue( rq, &message_type, &tag, buf, &buf_len, sizeof( buf ) ) == 1 ) {
1493
+ call_message_callbacks( rq, message_type, tag, buf, buf_len );
1494
+ }
1495
+ }
1496
+
1497
+
1498
+ static uint32_t
1499
+ get_send_data( send_queue *sq, size_t offset ) {
1500
+ assert( sq != NULL );
1501
+
1502
+ uint32_t bucket_size = messenger_bucket_size;
1503
+ if ( sq->socket_buffer_size != 0 ) {
1504
+ int used;
1505
+ if ( ioctl( sq->server_socket, SIOCOUTQ, &used ) == 0 ) {
1506
+ if ( used < sq->socket_buffer_size ) {
1507
+ bucket_size = ( uint32_t ) ( sq->socket_buffer_size - used ) << 1;
1508
+ if ( bucket_size > messenger_bucket_size ) {
1509
+ bucket_size = messenger_bucket_size;
1510
+ }
1511
+ }
1512
+ else {
1513
+ bucket_size = 1;
1514
+ }
1515
+ }
1516
+ }
1517
+
1518
+ uint32_t length = 0;
1519
+ message_header *header;
1520
+ while ( ( sq->buffer->data_length - offset ) >= sizeof( message_header ) ) {
1521
+ header = ( message_header * ) ( ( char * ) get_message_buffer_head( sq->buffer ) + offset );
1522
+ uint32_t message_length = ntohl( header->message_length );
1523
+ assert( message_length != 0 );
1524
+ assert( message_length < messenger_recv_queue_length );
1525
+ if ( length + message_length > bucket_size ) {
1526
+ if ( length == 0 ) {
1527
+ length = message_length;
1528
+ }
1529
+ break;
1530
+ }
1531
+ length += message_length;
1532
+ offset += message_length;
1533
+ }
1534
+ return length;
1535
+ }
1536
+
1537
+
1538
+ static void
1539
+ on_send_read( int fd, void *data ) {
1540
+ UNUSED( fd );
1541
+
1542
+ char buf[ 256 ];
1543
+ send_queue *sq = ( send_queue* )data;
1544
+
1545
+ if ( recv( sq->server_socket, buf, sizeof( buf ), 0 ) <= 0 ) {
1546
+ send_dump_message( MESSENGER_DUMP_SEND_CLOSED, sq->service_name, NULL, 0 );
1547
+
1548
+ set_readable( sq->server_socket, false );
1549
+ set_writable( sq->server_socket, false );
1550
+ delete_fd_handler( sq->server_socket );
1551
+
1552
+ close( sq->server_socket );
1553
+ sq->server_socket = -1;
1554
+
1555
+ // Tries to reconnecting immediately, else adds a reconnect timer.
1556
+ if ( sq->buffer->data_length > 0 ) {
1557
+ send_queue_try_connect( sq );
1558
+ }
1559
+ else {
1560
+ delete_send_queue( sq );
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+
1566
+ static void
1567
+ on_send_write( int fd, void *data ) {
1568
+ send_queue *sq = ( send_queue* )data;
1569
+
1570
+ assert( sq != NULL );
1571
+ assert( fd >= 0 );
1572
+
1573
+ debug( "Sending data to remote ( fd = %d, service_name = %s, buffer = %p, data_length = %u ).",
1574
+ fd, sq->service_name, get_message_buffer_head( sq->buffer ), sq->buffer->data_length );
1575
+
1576
+ if ( sq->buffer->data_length < sizeof( message_header ) ) {
1577
+ set_writable( sq->server_socket, false );
1578
+ return;
1579
+ }
1580
+
1581
+ void *send_data;
1582
+ size_t send_len;
1583
+ ssize_t sent_len;
1584
+ size_t sent_total = 0;
1585
+
1586
+ while ( ( send_len = get_send_data( sq, sent_total ) ) > 0 ) {
1587
+ send_data = ( ( char * ) get_message_buffer_head( sq->buffer ) + sent_total );
1588
+ sent_len = send( fd, send_data, send_len, MSG_DONTWAIT );
1589
+ if ( sent_len == -1 ) {
1590
+ int err = errno;
1591
+ if ( err != EAGAIN && err != EWOULDBLOCK ) {
1592
+ error( "Failed to send ( service_name = %s, fd = %d, errno = %s [%d] ).",
1593
+ sq->service_name, fd, strerror( err ), err );
1594
+ send_dump_message( MESSENGER_DUMP_SEND_CLOSED, sq->service_name, NULL, 0 );
1595
+
1596
+ set_readable( sq->server_socket, false );
1597
+ set_writable( sq->server_socket, false );
1598
+ delete_fd_handler( sq->server_socket );
1599
+
1600
+ close( sq->server_socket );
1601
+ sq->server_socket = -1;
1602
+ sq->refused_count = 0;
1603
+
1604
+ // Tries to reconnecting immediately, else adds a reconnect timer.
1605
+ send_queue_try_connect( sq );
1606
+ }
1607
+ truncate_message_buffer( sq->buffer, sent_total );
1608
+ if ( err == EMSGSIZE || err == ENOBUFS || err == ENOMEM ) {
1609
+ warn( "Dropping %u bytes data in send queue ( service_name = %s ).", sq->buffer->data_length, sq->service_name );
1610
+ truncate_message_buffer( sq->buffer, sq->buffer->data_length );
1611
+ }
1612
+ return;
1613
+ }
1614
+ assert( sent_len != 0 );
1615
+ assert( send_len == ( size_t ) sent_len );
1616
+ send_dump_message( MESSENGER_DUMP_SENT, sq->service_name, send_data, ( uint32_t ) sent_len );
1617
+ sent_total += ( size_t ) sent_len;
1618
+ }
1619
+
1620
+ truncate_message_buffer( sq->buffer, sent_total );
1621
+ if ( sq->buffer->data_length == 0 ) {
1622
+ set_writable( sq->server_socket, false );
1623
+ }
1624
+ }
1625
+
1626
+
1627
+ int
1628
+ flush_messenger() {
1629
+ int connected_count, sending_count, reconnecting_count, closed_count;
1630
+
1631
+ debug( "Flushing send queues." );
1632
+
1633
+ while ( true ) {
1634
+ number_of_send_queue( &connected_count, &sending_count, &reconnecting_count, &closed_count );
1635
+ if ( sending_count == 0 ) {
1636
+ return reconnecting_count;
1637
+ }
1638
+ run_event_handler_once( 100000 );
1639
+ }
1640
+ }
1641
+
1642
+
1643
+ bool
1644
+ start_messenger() {
1645
+ debug( "Starting messenger." );
1646
+
1647
+ add_periodic_event_callback( 10, age_context_db, NULL );
1648
+
1649
+ return true;
1650
+ }
1651
+
1652
+
1653
+ bool
1654
+ stop_messenger() {
1655
+ debug( "Terminating messenger." );
1656
+
1657
+ return true;
1658
+ }
1659
+
1660
+
1661
+ void
1662
+ start_messenger_dump( const char *dump_app_name, const char *dump_service_name ) {
1663
+ assert( dump_app_name != NULL );
1664
+ assert( dump_service_name != NULL );
1665
+
1666
+ debug( "Starting a message dumper ( dump_app_name = %s, dump_service_name = %s ).",
1667
+ dump_app_name, dump_service_name );
1668
+
1669
+ if ( messenger_dump_enabled() ) {
1670
+ stop_messenger_dump();
1671
+ }
1672
+ _dump_service_name = xstrdup( dump_service_name );
1673
+ _dump_app_name = xstrdup( dump_app_name );
1674
+ }
1675
+
1676
+
1677
+ void
1678
+ stop_messenger_dump( void ) {
1679
+ assert( _dump_service_name != NULL );
1680
+ assert( _dump_app_name != NULL );
1681
+
1682
+ debug( "Terminating a message dumper ( dump_app_name = %s, dump_service_name = %s ).",
1683
+ _dump_app_name, _dump_service_name );
1684
+
1685
+ assert( send_queues != NULL );
1686
+ send_queue *sq = lookup_hash_entry( send_queues, _dump_service_name );
1687
+ if ( sq != NULL ) {
1688
+ delete_send_queue( sq );
1689
+ }
1690
+
1691
+ xfree( _dump_service_name );
1692
+ _dump_service_name = NULL;
1693
+
1694
+ xfree( _dump_app_name );
1695
+ _dump_app_name = NULL;
1696
+ }
1697
+
1698
+
1699
+ bool
1700
+ messenger_dump_enabled( void ) {
1701
+ if ( _dump_service_name != NULL && _dump_app_name != NULL ) {
1702
+ return true;
1703
+ }
1704
+
1705
+ return false;
1706
+ }
1707
+
1708
+
1709
+ /*
1710
+ * Local variables:
1711
+ * c-basic-offset: 2
1712
+ * indent-tabs-mode: nil
1713
+ * End:
1714
+ */