trema 0.2.2.1 → 0.2.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 (250) hide show
  1. data/.gitmodules +3 -0
  2. data/.travis.yml +13 -0
  3. data/.yardopts +4 -0
  4. data/Gemfile +2 -3
  5. data/README.md +43 -97
  6. data/Rakefile +60 -4
  7. data/Rantfile +11 -10
  8. data/cruise.rb +4 -6
  9. data/features/example.packetin_filter_config.feature +10 -10
  10. data/features/example.switch_monitor.feature +14 -2
  11. data/features/step_definitions/kill_steps.rb +2 -2
  12. data/features/step_definitions/{off_steps.rb → killall_steps.rb} +2 -2
  13. data/features/step_definitions/misc_steps.rb +1 -1
  14. data/features/step_definitions/up_steps.rb +30 -0
  15. data/features/trema.feature +1 -0
  16. data/features/trema.run.feature +1 -0
  17. data/locale/README.ja.md +19 -0
  18. data/locale/ja/yard.po +3762 -0
  19. data/locale/yard.pot +3740 -0
  20. data/ruby/extconf.rb +4 -1
  21. data/ruby/trema/action-common.c +3 -17
  22. data/ruby/trema/action-common.h +3 -7
  23. data/ruby/trema/action.rb +33 -0
  24. data/ruby/trema/app.rb +1 -1
  25. data/ruby/trema/barrier-request.c +1 -0
  26. data/ruby/trema/command/run.rb +13 -9
  27. data/ruby/trema/command/usage.rb +1 -0
  28. data/ruby/trema/command/version.rb +1 -1
  29. data/ruby/trema/controller.c +133 -50
  30. data/ruby/trema/controller.rb +2 -2
  31. data/ruby/trema/desc-stats-reply.rb +77 -0
  32. data/ruby/trema/dsl/configuration.rb +3 -14
  33. data/ruby/trema/dsl/rswitch.rb +47 -0
  34. data/ruby/trema/dsl/runner.rb +4 -1
  35. data/ruby/trema/dsl/syntax.rb +11 -8
  36. data/ruby/trema/echo-reply.c +59 -45
  37. data/ruby/trema/echo-reply.h +1 -3
  38. data/ruby/trema/echo-request.c +49 -71
  39. data/ruby/trema/echo-request.h +0 -2
  40. data/ruby/trema/echo.c +99 -0
  41. data/ruby/trema/{action-enqueue.h → echo.h} +6 -7
  42. data/ruby/trema/enqueue.rb +87 -0
  43. data/ruby/trema/error.c +109 -104
  44. data/ruby/trema/error.h +0 -2
  45. data/ruby/trema/features-reply.c +89 -35
  46. data/ruby/trema/features-reply.h +0 -6
  47. data/ruby/trema/features-request.c +63 -37
  48. data/ruby/trema/features-request.h +0 -2
  49. data/ruby/trema/flow-mod.c +149 -0
  50. data/ruby/trema/{action-output.h → flow-mod.h} +6 -6
  51. data/ruby/trema/get-config-request.c +1 -0
  52. data/ruby/trema/hardware-switch.rb +88 -0
  53. data/ruby/trema/hello.c +55 -31
  54. data/ruby/trema/hello.h +0 -2
  55. data/ruby/trema/ip.rb +12 -2
  56. data/ruby/trema/logger.rb +29 -0
  57. data/ruby/trema/mac.rb +57 -36
  58. data/ruby/trema/match.c +7 -9
  59. data/ruby/trema/monkey-patch/integer/ranges.rb +0 -2
  60. data/ruby/trema/network-component.rb +1 -1
  61. data/ruby/trema/open-vswitch.rb +2 -2
  62. data/ruby/trema/openflow-switch.rb +3 -54
  63. data/ruby/trema/{packet_in.c → packet-in.c} +262 -175
  64. data/ruby/trema/{packet_in.h → packet-in.h} +0 -2
  65. data/ruby/trema/packet-queue.rb +4 -3
  66. data/ruby/trema/port-mod.c +8 -9
  67. data/ruby/trema/port-status-add.rb +60 -0
  68. data/ruby/trema/port-status-delete.rb +60 -0
  69. data/ruby/trema/port-status-modify.rb +60 -0
  70. data/ruby/trema/port-status.c +48 -15
  71. data/ruby/trema/port-status.h +6 -8
  72. data/ruby/trema/port.c +63 -8
  73. data/ruby/trema/queue-get-config-request.c +1 -0
  74. data/ruby/trema/ruby-switch.rb +62 -0
  75. data/ruby/trema/send-out-port.rb +97 -0
  76. data/ruby/trema/set-config.c +1 -0
  77. data/ruby/trema/set-eth-addr.rb +45 -0
  78. data/ruby/trema/set-eth-dst-addr.rb +54 -0
  79. data/ruby/trema/set-eth-src-addr.rb +54 -0
  80. data/ruby/trema/set-ip-addr.rb +47 -0
  81. data/ruby/trema/set-ip-dst-addr.rb +53 -0
  82. data/ruby/trema/set-ip-src-addr.rb +52 -0
  83. data/ruby/trema/set-ip-tos.rb +63 -0
  84. data/ruby/trema/set-transport-dst-port.rb +53 -0
  85. data/ruby/trema/set-transport-port.rb +52 -0
  86. data/ruby/trema/set-transport-src-port.rb +54 -0
  87. data/ruby/trema/set-vlan-priority.rb +65 -0
  88. data/ruby/trema/set-vlan-vid.rb +64 -0
  89. data/ruby/trema/shell/down.rb +1 -1
  90. data/ruby/trema/shell/link.rb +4 -4
  91. data/ruby/trema/shell/run.rb +8 -6
  92. data/ruby/trema/shell/up.rb +3 -3
  93. data/ruby/trema/stats-reply.c +27 -2
  94. data/ruby/trema/stats-request.c +64 -23
  95. data/ruby/trema/strip-vlan-header.rb +41 -0
  96. data/ruby/trema/switch.c +196 -0
  97. data/ruby/trema/{action-vendor.h → switch.h} +5 -7
  98. data/ruby/trema/switch.rb +28 -9
  99. data/ruby/trema/trema-ruby-utils.c +66 -0
  100. data/ruby/trema/{action-set-dl-src.h → trema-ruby-utils.h} +9 -11
  101. data/ruby/trema/trema.c +61 -61
  102. data/ruby/trema/vendor-action.rb +73 -0
  103. data/ruby/trema/vendor.c +121 -52
  104. data/ruby/trema/vendor.h +6 -10
  105. data/ruby/trema/version.rb +1 -1
  106. data/spec/spec_helper.rb +1 -1
  107. data/spec/support/action.rb +52 -0
  108. data/spec/support/mandatory-option.rb +56 -0
  109. data/spec/support/openflow-message.rb +91 -7
  110. data/spec/support/port-status.rb +38 -0
  111. data/spec/trema/controller_spec.rb +0 -26
  112. data/spec/trema/dsl/configuration_spec.rb +3 -3
  113. data/spec/trema/dsl/runner_spec.rb +12 -32
  114. data/spec/trema/dsl/syntax_spec.rb +2 -11
  115. data/spec/trema/echo-reply_spec.rb +49 -14
  116. data/spec/trema/echo-request_spec.rb +86 -34
  117. data/spec/trema/enqueue_spec.rb +76 -0
  118. data/spec/trema/error_spec.rb +43 -58
  119. data/spec/trema/features-reply_spec.rb +58 -24
  120. data/spec/trema/features-request_spec.rb +54 -28
  121. data/spec/trema/flow-mod_spec.rb +99 -0
  122. data/spec/trema/{openflow-switch_spec.rb → hardware-switch_spec.rb} +3 -3
  123. data/spec/trema/hello_spec.rb +28 -14
  124. data/spec/trema/ip_spec.rb +54 -0
  125. data/spec/trema/mac_spec.rb +49 -64
  126. data/spec/trema/match_spec.rb +1 -1
  127. data/spec/trema/open-vswitch_spec.rb +7 -7
  128. data/spec/trema/packet-in_spec.rb +73 -16
  129. data/spec/trema/port-status-add_spec.rb +32 -0
  130. data/spec/trema/port-status-delete_spec.rb +32 -0
  131. data/spec/trema/port-status-modify_spec.rb +71 -0
  132. data/spec/trema/port-status_spec.rb +5 -76
  133. data/spec/trema/{action-output_spec.rb → send-out-port_spec.rb} +20 -47
  134. data/spec/trema/set-eth-dst-addr_spec.rb +75 -0
  135. data/spec/trema/set-eth-src-addr_spec.rb +72 -0
  136. data/spec/trema/set-ip-dst-addr_spec.rb +58 -0
  137. data/spec/trema/set-ip-src-addr_spec.rb +58 -0
  138. data/spec/trema/set-ip-tos_spec.rb +65 -0
  139. data/spec/trema/set-transport-dst-port_spec.rb +65 -0
  140. data/spec/trema/set-transport-src-port_spec.rb +65 -0
  141. data/spec/trema/set-vlan-priority_spec.rb +65 -0
  142. data/spec/trema/set-vlan-vid_spec.rb +65 -0
  143. data/spec/trema/shell/vhost_spec.rb +4 -1
  144. data/spec/trema/shell/vswitch_spec.rb +11 -11
  145. data/spec/trema/stats-reply_spec.rb +59 -13
  146. data/spec/trema/stats-request_spec.rb +6 -0
  147. data/spec/trema/{action-strip-vlan_spec.rb → strip-vlan-header_spec.rb} +3 -17
  148. data/spec/trema/switch-daemon_spec.rb +39 -0
  149. data/spec/trema/vendor-action_spec.rb +81 -0
  150. data/spec/trema/vendor_spec.rb +76 -0
  151. data/spec/trema_spec.rb +56 -0
  152. data/src/examples/dumper/dumper.c +0 -8
  153. data/src/examples/dumper/dumper.rb +52 -52
  154. data/src/examples/hello_trema/hello_trema.c +0 -2
  155. data/src/examples/learning_switch/learning-switch.rb +3 -3
  156. data/src/examples/multi_learning_switch/multi-learning-switch.rb +3 -3
  157. data/src/examples/openflow_message/features-request.rb +3 -3
  158. data/src/examples/packetin_filter_config/utils.c +4 -4
  159. data/src/examples/repeater_hub/repeater-hub.rb +3 -3
  160. data/src/examples/switch_info/switch_info.rb +2 -2
  161. data/src/examples/switch_monitor/switch_monitor.c +1 -1
  162. data/src/examples/traffic_monitor/traffic-monitor.rb +3 -3
  163. data/src/lib/arp.h +4 -1
  164. data/src/lib/chibach.c +391 -0
  165. data/src/lib/chibach.h +71 -0
  166. data/src/lib/chibach_private.c +170 -0
  167. data/src/lib/chibach_private.h +52 -0
  168. data/src/lib/ether.c +2 -1
  169. data/src/lib/ether.h +0 -1
  170. data/src/lib/ipv4.h +13 -14
  171. data/{ruby/trema/action-set-nw-src.h → src/lib/ipv6.h} +13 -9
  172. data/src/lib/log.c +161 -58
  173. data/src/lib/log.h +11 -16
  174. data/src/lib/messenger.c +36 -1
  175. data/src/lib/messenger.h +1 -0
  176. data/src/lib/openflow_application_interface.c +128 -28
  177. data/src/lib/openflow_application_interface.h +31 -6
  178. data/src/lib/openflow_message.c +2 -1
  179. data/src/lib/openflow_service_interface.h +1 -0
  180. data/src/lib/openflow_switch_interface.c +1380 -0
  181. data/src/lib/openflow_switch_interface.h +264 -0
  182. data/src/lib/packet_info.c +94 -11
  183. data/src/lib/packet_info.h +22 -3
  184. data/src/lib/packet_parser.c +38 -2
  185. data/src/lib/secure_channel.c +498 -0
  186. data/{ruby/trema/vendor-request.h → src/lib/secure_channel.h} +11 -10
  187. data/src/lib/tcp.h +0 -3
  188. data/src/lib/trema.c +38 -5
  189. data/{ruby/trema/action-set-nw-dst.h → src/lib/trema.hpp} +17 -8
  190. data/src/lib/trema_wrapper.c +5 -0
  191. data/src/lib/trema_wrapper.h +4 -0
  192. data/src/lib/utility.c +93 -4
  193. data/src/lib/utility.h +1 -0
  194. data/src/lib/wrapper.c +30 -7
  195. data/src/lib/wrapper.h +2 -0
  196. data/src/switch_manager/ofpmsg_recv.c +44 -30
  197. data/src/switch_manager/ofpmsg_send.c +40 -1
  198. data/src/switch_manager/ofpmsg_send.h +2 -0
  199. data/src/switch_manager/switch.c +153 -8
  200. data/src/switch_manager/switch.h +1 -0
  201. data/src/switch_manager/switchinfo.h +5 -0
  202. data/src/tremashark/README +2 -2
  203. data/src/tremashark/plugin/packet-trema/packet-trema.c +1 -0
  204. data/trema +1 -1
  205. data/unittests/lib/log_test.c +158 -34
  206. data/unittests/lib/openflow_application_interface_test.c +252 -69
  207. data/unittests/lib/openflow_message_test.c +3 -1
  208. data/unittests/lib/packet_parser_test.c +60 -15
  209. data/unittests/lib/test_packets/icmp6_echo_rep.cap +0 -0
  210. data/unittests/lib/test_packets/icmp6_echo_req.cap +0 -0
  211. data/unittests/lib/trema_test.c +2 -0
  212. data/unittests/lib/utility_test.c +65 -2
  213. data/unittests/lib/wrapper_test.c +29 -0
  214. data/vendor/{README → README.md} +2 -12
  215. data/vendor/packet-openflow.diff +13 -0
  216. metadata +86 -53
  217. data/GPL2 +0 -339
  218. data/ruby/trema/action-enqueue.c +0 -161
  219. data/ruby/trema/action-output.c +0 -169
  220. data/ruby/trema/action-set-dl-dst.c +0 -131
  221. data/ruby/trema/action-set-dl-dst.h +0 -44
  222. data/ruby/trema/action-set-dl-src.c +0 -131
  223. data/ruby/trema/action-set-nw-dst.c +0 -135
  224. data/ruby/trema/action-set-nw-src.c +0 -140
  225. data/ruby/trema/action-set-nw-tos.c +0 -124
  226. data/ruby/trema/action-set-nw-tos.h +0 -42
  227. data/ruby/trema/action-set-tp-dst.c +0 -122
  228. data/ruby/trema/action-set-tp-dst.h +0 -42
  229. data/ruby/trema/action-set-tp-src.c +0 -124
  230. data/ruby/trema/action-set-tp-src.h +0 -42
  231. data/ruby/trema/action-set-vlan-pcp.c +0 -128
  232. data/ruby/trema/action-set-vlan-pcp.h +0 -42
  233. data/ruby/trema/action-set-vlan-vid.c +0 -125
  234. data/ruby/trema/action-set-vlan-vid.h +0 -42
  235. data/ruby/trema/action-strip-vlan.c +0 -81
  236. data/ruby/trema/action-strip-vlan.h +0 -42
  237. data/ruby/trema/action-vendor.c +0 -121
  238. data/ruby/trema/vendor-request.c +0 -193
  239. data/spec/trema/action-enqueue_spec.rb +0 -100
  240. data/spec/trema/action-set-dl-dst_spec.rb +0 -95
  241. data/spec/trema/action-set-dl-src_spec.rb +0 -92
  242. data/spec/trema/action-set-nw-dst_spec.rb +0 -96
  243. data/spec/trema/action-set-nw-src_spec.rb +0 -97
  244. data/spec/trema/action-set-nw-tos_spec.rb +0 -88
  245. data/spec/trema/action-set-tp-dst_spec.rb +0 -88
  246. data/spec/trema/action-set-tp-src_spec.rb +0 -88
  247. data/spec/trema/action-set-vlan-pcp_spec.rb +0 -91
  248. data/spec/trema/action-set-vlan-vid_spec.rb +0 -91
  249. data/spec/trema/action-vendor_spec.rb +0 -90
  250. data/spec/trema/vendor-request_spec.rb +0 -79
@@ -1,6 +1,4 @@
1
1
  /*
2
- * Author: Kazuya Suzuki
3
- *
4
2
  * Copyright (C) 2008-2012 NEC Corporation
5
3
  *
6
4
  * This program is free software; you can redistribute it and/or modify
@@ -20,6 +18,7 @@
20
18
 
21
19
  #include <assert.h>
22
20
  #include <stdint.h>
21
+ #include <arpa/inet.h>
23
22
  #include <net/ethernet.h>
24
23
  #include <netinet/ip.h>
25
24
  #include "packet_info.h"
@@ -202,6 +201,38 @@ parse_ipv4( buffer *buf ) {
202
201
  }
203
202
 
204
203
 
204
+ static void
205
+ parse_ipv6( buffer *buf ) {
206
+ assert( buf != NULL );
207
+
208
+ packet_info *packet_info = buf->user_data;
209
+ void *ptr = packet_info->l3_header;
210
+ assert( ptr != NULL );
211
+
212
+ // Check the length of remained buffer for an ipv6 header without nexthdr.
213
+ size_t length = REMAINED_BUFFER_LENGTH( buf, ptr );
214
+ if ( length < sizeof( ipv6_header_t ) ) {
215
+ return;
216
+ }
217
+
218
+ // Parses IPv6 header
219
+ ipv6_header_t *ipv6_header = ptr;
220
+ uint32_t hdrctl = ntohl( ipv6_header->hdrctl );
221
+ packet_info->ipv6_version = ( uint8_t )( hdrctl >> 28 );
222
+ packet_info->ipv6_tc = ( uint8_t )( hdrctl >> 20 & 0xFF );
223
+ packet_info->ipv6_flowlabel = hdrctl & 0xFFFFF;
224
+ packet_info->ipv6_plen = ntohs( ipv6_header->plen );
225
+ packet_info->ipv6_nexthdr = ipv6_header->nexthdr;
226
+ packet_info->ipv6_hoplimit = ipv6_header->hoplimit;
227
+ memcpy( packet_info->ipv6_saddr, ipv6_header->saddr, IPV6_ADDRLEN );
228
+ memcpy( packet_info->ipv6_daddr, ipv6_header->daddr, IPV6_ADDRLEN );
229
+
230
+ packet_info->format |= NW_IPV6;
231
+
232
+ return;
233
+ }
234
+
235
+
205
236
  static void
206
237
  parse_lldp( buffer *buf ) {
207
238
  assert( buf != NULL );
@@ -439,6 +470,11 @@ parse_packet( buffer *buf ) {
439
470
  parse_ipv4( buf );
440
471
  break;
441
472
 
473
+ case ETH_ETHTYPE_IPV6:
474
+ packet_info->l3_header = packet_info->l2_payload;
475
+ parse_ipv6( buf );
476
+ break;
477
+
442
478
  case ETH_ETHTYPE_LLDP:
443
479
  packet_info->l3_header = packet_info->l2_payload;
444
480
  parse_lldp( buf );
@@ -0,0 +1,498 @@
1
+ /*
2
+ * Author: Kazushi SUGYO, 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 <arpa/inet.h>
22
+ #include <assert.h>
23
+ #include <errno.h>
24
+ #include <fcntl.h>
25
+ #include <netinet/in.h>
26
+ #include <netinet/tcp.h>
27
+ #include <stdio.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <sys/socket.h>
31
+ #include <sys/types.h>
32
+ #include <unistd.h>
33
+ #include "buffer.h"
34
+ #include "checks.h"
35
+ #include "event_handler.h"
36
+ #include "log.h"
37
+ #include "message_queue.h"
38
+ #include "openflow.h"
39
+ #include "openflow_switch_interface.h"
40
+ #include "secure_channel.h"
41
+ #include "timer.h"
42
+ #include "wrapper.h"
43
+
44
+
45
+ enum connection_state {
46
+ INIT,
47
+ CONNECTING,
48
+ CONNECTED,
49
+ DISCONNECTED,
50
+ };
51
+
52
+ static char connection_state_string[][ 13 ] = { "INIT", "CONNECTING", "CONNECTED", "DISCONNECTED" };
53
+
54
+
55
+ typedef struct {
56
+ uint32_t ip;
57
+ uint16_t port;
58
+ int fd;
59
+ int state;
60
+ connected_handler connected_callback;
61
+ disconnected_handler disconnected_callback;
62
+ } secure_channel_connection;
63
+
64
+
65
+ static secure_channel_connection connection = { 0, 0, -1, INIT, NULL, NULL };
66
+ static bool secure_channel_initialized = false;
67
+
68
+ static message_queue *send_queue = NULL;
69
+ static message_queue *recv_queue = NULL;
70
+
71
+ static const size_t RECEIVE_BUFFFER_SIZE = UINT16_MAX + sizeof( struct ofp_packet_in ) - 2;
72
+ static buffer *fragment_buf = NULL;
73
+
74
+
75
+ static void
76
+ transit_state( int state ) {
77
+ switch ( connection.state ) {
78
+ case INIT:
79
+ {
80
+ if ( state != CONNECTING ) {
81
+ goto invalid_transition;
82
+ }
83
+ connection.state = state;
84
+ }
85
+ break;
86
+
87
+ case CONNECTING:
88
+ {
89
+ if ( state != CONNECTED && state != CONNECTING ) {
90
+ goto invalid_transition;
91
+ }
92
+ }
93
+ break;
94
+
95
+ case CONNECTED:
96
+ {
97
+ if ( state != DISCONNECTED && state != INIT ) {
98
+ goto invalid_transition;
99
+ }
100
+ }
101
+ break;
102
+
103
+ case DISCONNECTED:
104
+ {
105
+ if ( state != CONNECTED ) {
106
+ goto invalid_transition;
107
+ }
108
+ }
109
+ break;
110
+
111
+ default:
112
+ {
113
+ error( "Invalid state ( %d ).", connection.state );
114
+ return;
115
+ }
116
+ break;
117
+ }
118
+
119
+ debug( "State transition: %s -> %s.",
120
+ connection_state_string[ connection.state ],
121
+ connection_state_string[ state ] );
122
+
123
+ connection.state = state;
124
+
125
+ return;
126
+
127
+ invalid_transition:
128
+ error( "Invalid state transition ( %d -> %d ).", connection.state, state );
129
+ }
130
+
131
+
132
+ static void
133
+ clear_connection() {
134
+ if ( connection.fd >= 0 ) {
135
+ close( connection.fd );
136
+ set_readable( connection.fd, false );
137
+ set_writable( connection.fd, false );
138
+ delete_fd_handler( connection.fd );
139
+ }
140
+
141
+ connection.fd = -1;
142
+ connection.state = INIT;
143
+ }
144
+
145
+
146
+ static void reconnect( void *user_data );
147
+
148
+
149
+ static void
150
+ disconnected() {
151
+ transit_state( DISCONNECTED );
152
+
153
+ if ( connection.disconnected_callback != NULL ) {
154
+ connection.disconnected_callback();
155
+ }
156
+
157
+ clear_connection();
158
+ }
159
+
160
+
161
+ static bool
162
+ recv_message_from_secure_channel() {
163
+ assert( recv_queue != NULL );
164
+
165
+ if ( recv_queue->length == 0 ) {
166
+ return false;
167
+ }
168
+
169
+ buffer *message = dequeue_message( recv_queue );
170
+ handle_secure_channel_message( message ); // FIXME: handle error properly
171
+ free_buffer( message );
172
+
173
+ return true;
174
+ }
175
+
176
+
177
+ static void
178
+ recv_from_secure_channel( int fd, void *user_data ) {
179
+ UNUSED( fd );
180
+ UNUSED( user_data );
181
+
182
+ // all queued messages should be processed before receiving new messages from remote
183
+ if ( recv_queue->length > 0 ) {
184
+ return;
185
+ }
186
+
187
+ if ( fragment_buf == NULL ) {
188
+ fragment_buf = alloc_buffer_with_length( RECEIVE_BUFFFER_SIZE );
189
+ }
190
+
191
+ size_t remaining_length = RECEIVE_BUFFFER_SIZE - fragment_buf->length;
192
+ char *recv_buf = ( char * ) fragment_buf->data + fragment_buf->length;
193
+ ssize_t recv_length = read( connection.fd, recv_buf, remaining_length );
194
+ if ( recv_length < 0 ) {
195
+ if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
196
+ return;
197
+ }
198
+ error( "Receive error ( errno = %s [%d] ).", strerror( errno ), errno );
199
+ return;
200
+ }
201
+ if ( recv_length == 0 ) {
202
+ debug( "Connection closed by peer." );
203
+ disconnected();
204
+ reconnect( NULL );
205
+ return;
206
+ }
207
+ fragment_buf->length += ( size_t ) recv_length;
208
+
209
+ size_t read_total = 0;
210
+ while ( fragment_buf->length >= sizeof( struct ofp_header ) ) {
211
+ struct ofp_header *header = fragment_buf->data;
212
+ uint16_t message_length = ntohs( header->length );
213
+ if ( message_length > fragment_buf->length ) {
214
+ break;
215
+ }
216
+ buffer *message = alloc_buffer_with_length( message_length );
217
+ char *p = append_back_buffer( message, message_length );
218
+ memcpy( p, fragment_buf->data, message_length );
219
+ remove_front_buffer( fragment_buf, message_length );
220
+ enqueue_message( recv_queue, message );
221
+ read_total += message_length;
222
+ }
223
+
224
+ // remove headroom manually for next call
225
+ if ( read_total > 0 ) {
226
+ memmove( ( char * ) fragment_buf->data - read_total, fragment_buf->data, fragment_buf->length );
227
+ fragment_buf->data = ( char * ) fragment_buf->data - read_total;
228
+ }
229
+
230
+ while ( recv_message_from_secure_channel() == true );
231
+ }
232
+
233
+
234
+ static void
235
+ flush_send_queue( int fd, void *user_data ) {
236
+ UNUSED( fd );
237
+ UNUSED( user_data );
238
+
239
+ assert( send_queue != NULL );
240
+ assert( connection.fd >= 0 );
241
+
242
+ debug( "Flushing send queue ( length = %d ).", send_queue->length );
243
+
244
+ set_writable( connection.fd, false );
245
+
246
+ buffer *buf = NULL;
247
+ while ( ( buf = peek_message( send_queue ) ) != NULL ) {
248
+ ssize_t write_length = write( connection.fd, buf->data, buf->length );
249
+ if ( write_length < 0 ) {
250
+ if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
251
+ set_writable( connection.fd, true );
252
+ return;
253
+ }
254
+ error( "Failed to send a message to secure channel ( errno = %s [%d] ).",
255
+ strerror( errno ), errno );
256
+ return;
257
+ }
258
+ if ( ( size_t ) write_length < buf->length ) {
259
+ remove_front_buffer( buf, ( size_t ) write_length );
260
+ set_writable( connection.fd, true );
261
+ return;
262
+ }
263
+
264
+ buf = dequeue_message( send_queue );
265
+ free_buffer( buf );
266
+ }
267
+ }
268
+
269
+
270
+ static void
271
+ connected() {
272
+ transit_state( CONNECTED );
273
+
274
+ set_fd_handler( connection.fd, recv_from_secure_channel, NULL, flush_send_queue, NULL );
275
+ set_readable( connection.fd, true );
276
+ set_writable( connection.fd, false );
277
+
278
+ if ( connection.connected_callback != NULL ) {
279
+ connection.connected_callback();
280
+ }
281
+ }
282
+
283
+
284
+ static bool try_connect( void );
285
+
286
+ static void
287
+ reconnect( void *user_data ) {
288
+ UNUSED( user_data );
289
+ bool ret = try_connect();
290
+ if ( ret == false ) {
291
+ error( "Failed to reconnect." );
292
+ clear_connection();
293
+ }
294
+ }
295
+
296
+
297
+ static void
298
+ backoff() {
299
+ if ( connection.fd >= 0 ) {
300
+ close( connection.fd );
301
+ }
302
+
303
+ struct itimerspec spec = { { 0, 0 }, { 5, 0 } };
304
+ add_timer_event_callback( &spec, reconnect, NULL );
305
+ }
306
+
307
+
308
+ static void
309
+ check_connected( void *user_data ) {
310
+ UNUSED( user_data );
311
+
312
+ debug( "Checking a connection ( fd = %d ip = %#x, port = %u ).", connection.fd, connection.ip, connection.port );
313
+
314
+ assert( secure_channel_initialized );
315
+ assert( connection.fd >= 0 );
316
+
317
+ set_writable( connection.fd, false );
318
+ delete_fd_handler( connection.fd );
319
+
320
+ int err = 0;
321
+ socklen_t length = sizeof( error );
322
+ int ret = getsockopt( connection.fd, SOL_SOCKET, SO_ERROR, &err, &length );
323
+ if ( ret < 0 ) {
324
+ error( "Failed to retrieve error code ( fd = %d, ret = %d, errno = %s [%d] ).",
325
+ connection.fd, ret, strerror( errno ), errno );
326
+ return;
327
+ }
328
+
329
+ switch( err ) {
330
+ case 0:
331
+ connected();
332
+ break;
333
+
334
+ case EINTR:
335
+ case EAGAIN:
336
+ case ECONNREFUSED:
337
+ case ENETUNREACH:
338
+ case ETIMEDOUT:
339
+ warn( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err );
340
+ backoff();
341
+ return;
342
+
343
+ case EINPROGRESS:
344
+ set_fd_handler( connection.fd, NULL ,NULL, ( event_fd_callback ) check_connected, NULL );
345
+ set_writable( connection.fd, true );
346
+ break;
347
+
348
+ default:
349
+ error( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err );
350
+ clear_connection();
351
+ return;
352
+ }
353
+ }
354
+
355
+
356
+ static bool
357
+ try_connect() {
358
+ assert( connection.state != CONNECTED );
359
+
360
+ int fd = socket( PF_INET, SOCK_STREAM, 0 );
361
+ if ( fd < 0 ) {
362
+ error( "Failed to create a socket ( ret = %d, errno = %s [%d] ).",
363
+ fd, strerror( errno ), errno );
364
+ return false;
365
+ }
366
+
367
+ int flag = 1;
368
+ int ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof( flag ) );
369
+ if ( ret < 0 ) {
370
+ error( "Failed to set socket options ( fd = %d, ret = %d, errno = %s [%d] ).",
371
+ fd, ret, strerror( errno ), errno );
372
+ return false;
373
+ }
374
+
375
+ ret = fcntl( fd, F_SETFL, O_NONBLOCK );
376
+ if ( ret < 0 ) {
377
+ error( "Failed to enable non-blocking mode ( fd = %d, ret = %d, errno = %s [%d] ).",
378
+ fd, ret, strerror( errno ), errno );
379
+
380
+ close( fd );
381
+ return false;
382
+ }
383
+
384
+ connection.fd = fd;
385
+
386
+ struct sockaddr_in addr;
387
+ memset( &addr, 0, sizeof( struct sockaddr_in ) );
388
+ addr.sin_family = AF_INET;
389
+ addr.sin_port = htons( connection.port );
390
+ addr.sin_addr.s_addr = htonl( connection.ip );
391
+
392
+ transit_state( CONNECTING );
393
+
394
+ ret = connect( connection.fd, ( struct sockaddr * ) &addr, sizeof( struct sockaddr_in ) );
395
+ if ( ret < 0 ) {
396
+ switch( errno ) {
397
+ case EINTR:
398
+ case EAGAIN:
399
+ case ECONNREFUSED:
400
+ case ENETUNREACH:
401
+ case ETIMEDOUT:
402
+ warn( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).",
403
+ connection.fd, ret, strerror( errno ), errno );
404
+ backoff();
405
+ return true;
406
+
407
+ case EINPROGRESS:
408
+ break;
409
+
410
+ default:
411
+ error( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).",
412
+ connection.fd, ret, strerror( errno ), errno );
413
+ clear_connection();
414
+ return false;
415
+ }
416
+ }
417
+
418
+ set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL );
419
+ set_writable( connection.fd, true );
420
+
421
+ return true;
422
+ }
423
+
424
+
425
+ bool
426
+ init_secure_channel( uint32_t ip, uint16_t port, connected_handler connected_callback, disconnected_handler disconnected_callback ) {
427
+ assert( !secure_channel_initialized );
428
+
429
+ connection.ip = ip;
430
+ connection.port = port;
431
+ connection.fd = -1;
432
+ connection.connected_callback = connected_callback;
433
+ connection.disconnected_callback = disconnected_callback;
434
+
435
+ bool ret = try_connect();
436
+ if ( ret == false ) {
437
+ clear_connection();
438
+ return false;
439
+ }
440
+
441
+ send_queue = create_message_queue();
442
+ recv_queue = create_message_queue();
443
+
444
+ secure_channel_initialized = true;
445
+
446
+ return true;
447
+ }
448
+
449
+
450
+ bool
451
+ finalize_secure_channel() {
452
+ assert( secure_channel_initialized );
453
+
454
+ clear_connection();
455
+
456
+ if ( send_queue != NULL ) {
457
+ delete_message_queue( send_queue );
458
+ send_queue = NULL;
459
+ }
460
+ if ( recv_queue != NULL ) {
461
+ delete_message_queue( recv_queue );
462
+ recv_queue = NULL;
463
+ }
464
+
465
+ secure_channel_initialized = false;
466
+
467
+ return true;
468
+ }
469
+
470
+
471
+ bool
472
+ send_message_to_secure_channel( buffer *message ) {
473
+ assert( send_queue != NULL );
474
+ assert( message != NULL );
475
+ assert( message->length > 0 );
476
+ assert( connection.state == CONNECTED );
477
+ assert( connection.fd >= 0 );
478
+
479
+ debug( "Enqueuing a message to send queue ( queue length = %d, message length = %d ).",
480
+ send_queue->length, message->length );
481
+
482
+ if ( send_queue->length == 0 ) {
483
+ set_writable( connection.fd, true );
484
+ }
485
+
486
+ buffer *duplicated = duplicate_buffer( message );
487
+ enqueue_message( send_queue, duplicated );
488
+
489
+ return true;
490
+ }
491
+
492
+
493
+ /*
494
+ * Local variables:
495
+ * c-basic-offset: 2
496
+ * indent-tabs-mode: nil
497
+ * End:
498
+ */