trema 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -4
  3. data/Guardfile +8 -0
  4. data/Rakefile +2 -1
  5. data/bin/trema +4 -0
  6. data/cruise.rb +1 -1
  7. data/features/core/switch_manager.feature +2 -2
  8. data/features/examples/message.vendor-action.feature +2 -2
  9. data/features/examples/message.vendor-stats-request.feature +20 -0
  10. data/features/trema_commands/kill.feature +4 -0
  11. data/features/trema_commands/killall.feature +1 -0
  12. data/features/trema_commands/run.feature +20 -1
  13. data/ruby/trema/command/run.rb +4 -0
  14. data/ruby/trema/default_openflow_channel_port.rb +26 -0
  15. data/ruby/trema/dsl/configuration.rb +2 -1
  16. data/ruby/trema/open-vswitch.rb +2 -4
  17. data/ruby/trema/stats-reply.c +10 -1
  18. data/ruby/trema/stats-request.c +34 -1
  19. data/ruby/trema/vendor-stats-reply.rb +6 -2
  20. data/ruby/trema/version.rb +1 -1
  21. data/spec/trema/dsl/runner_spec.rb +1 -1
  22. data/spec/trema/dsl/syntax_spec.rb +1 -1
  23. data/spec/trema/shell/vswitch_spec.rb +1 -1
  24. data/spec/trema/stats-reply_spec.rb +2 -1
  25. data/spec/trema/stats-request_spec.rb +11 -0
  26. data/src/examples/cbench_switch/cbench-switch.rb +1 -0
  27. data/src/examples/cbench_switch/cbench_switch.c +1 -1
  28. data/src/examples/openflow_message/vendor-action.rb +4 -4
  29. data/src/examples/openflow_message/vendor-stats-request.rb +66 -0
  30. data/src/examples/simple_router/arp-table.rb +6 -17
  31. data/src/examples/simple_router/interface.rb +20 -29
  32. data/src/examples/simple_router/routing-table.rb +15 -22
  33. data/src/examples/simple_router/simple-router.rb +75 -64
  34. data/src/lib/chibach.c +3 -2
  35. data/src/lib/event_handler.c +55 -23
  36. data/src/lib/event_handler.h +0 -5
  37. data/src/lib/external_callback.c +126 -0
  38. data/src/lib/external_callback.h +46 -0
  39. data/src/lib/messenger.c +58 -35
  40. data/src/lib/openflow_message.c +32 -11
  41. data/src/lib/trema.c +13 -7
  42. data/src/lib/trema.h +1 -0
  43. data/src/lib/utility.c +13 -2
  44. data/src/switch_manager/secure_channel_receiver.c +6 -1
  45. data/src/switch_manager/switch.c +27 -26
  46. data/src/switch_manager/switch_manager.c +31 -10
  47. data/src/tremashark/packet_capture.c +3 -2
  48. data/src/tremashark/tremashark.c +2 -2
  49. data/trema.gemspec +1 -1
  50. data/unittests/lib/external_callback_test.c +282 -0
  51. data/unittests/lib/messenger_test.c +22 -0
  52. data/unittests/lib/openflow_message_test.c +1 -1
  53. data/unittests/lib/trema_test.c +1 -1
  54. data/unittests/switch_manager/switch_manager_test.c +3 -3
  55. metadata +12 -6
  56. data/src/examples/simple_router/router-utils.rb +0 -211
data/src/lib/chibach.c CHANGED
@@ -33,6 +33,7 @@
33
33
  #include <unistd.h>
34
34
  #include "chibach.h"
35
35
  #include "chibach_private.h"
36
+ #include "external_callback.h"
36
37
  #include "daemon.h"
37
38
  #include "doubly_linked_list.h"
38
39
  #include "log.h"
@@ -191,7 +192,7 @@ parse_argv( int *argc, char ***argv ) {
191
192
 
192
193
  run_as_daemon = false;
193
194
  controller.ip = 0x7f000001;
194
- controller.port = 6633;
195
+ controller.port = 6653;
195
196
 
196
197
  for ( int i = 0; i < *argc; ++i ) {
197
198
  new_argv[ i ] = ( *argv )[ i ];
@@ -286,7 +287,7 @@ set_exit_handler() {
286
287
 
287
288
  static void
288
289
  set_dump_stats_as_external_callback() {
289
- set_external_callback( dump_stats );
290
+ push_external_callback( dump_stats );
290
291
  }
291
292
 
292
293
 
@@ -23,6 +23,7 @@
23
23
  #include <unistd.h>
24
24
  #include "checks.h"
25
25
  #include "event_handler.h"
26
+ #include "external_callback.h"
26
27
  #include "log.h"
27
28
  #include "timer.h"
28
29
 
@@ -61,6 +62,30 @@ extern bool mock_add_periodic_event_callback( const time_t seconds, void ( *call
61
62
  #define execute_timer_events mock_execute_timer_events
62
63
  extern void mock_execute_timer_events( int *next_timeout_usec );
63
64
 
65
+ #ifdef init_external_callback
66
+ #undef init_external_callback
67
+ #endif
68
+ #define init_external_callback mock_init_external_callback
69
+ extern void mock_init_external_callback( void );
70
+
71
+ #ifdef finalize_external_callback
72
+ #undef finalize_external_callback
73
+ #endif
74
+ #define finalize_external_callback mock_finalize_external_callback
75
+ extern void mock_finalize_external_callback( void );
76
+
77
+ #ifdef push_external_callback
78
+ #undef push_external_callback
79
+ #endif
80
+ #define push_external_callback mock_push_external_callback
81
+ extern void mock_push_external_callback( external_callback_t callback );
82
+
83
+ #ifdef run_external_callback
84
+ #undef run_external_callback
85
+ #endif
86
+ #define run_external_callback mock_run_external_callback
87
+ extern void mock_run_external_callback( void );
88
+
64
89
  #endif // UNIT_TESTING
65
90
 
66
91
 
@@ -94,19 +119,19 @@ fd_set current_write_set;
94
119
 
95
120
  int fd_set_size = 0;
96
121
 
97
- external_callback_t external_callback = ( external_callback_t ) NULL;
98
-
99
-
100
122
  static void
101
123
  _init_event_handler() {
102
124
  event_last = event_list;
103
- event_handler_state = EVENT_HANDLER_INITIALIZED;
104
125
 
105
126
  memset( event_list, 0, sizeof( event_fd ) * FD_SETSIZE );
106
127
  memset( event_fd_set, 0, sizeof( event_fd * ) * FD_SETSIZE );
107
128
 
108
129
  FD_ZERO( &event_read_set );
109
130
  FD_ZERO( &event_write_set );
131
+
132
+ init_external_callback();
133
+
134
+ event_handler_state = EVENT_HANDLER_INITIALIZED;
110
135
  }
111
136
  void ( *init_event_handler )() = _init_event_handler;
112
137
 
@@ -120,18 +145,15 @@ _finalize_event_handler() {
120
145
  }
121
146
 
122
147
  event_handler_state = EVENT_HANDLER_FINALIZED;
148
+
149
+ finalize_external_callback();
123
150
  }
124
151
  void ( *finalize_event_handler )() = _finalize_event_handler;
125
152
 
126
153
 
127
154
  static bool
128
155
  _run_event_handler_once( int timeout_usec ) {
129
- if ( external_callback != NULL ) {
130
- external_callback_t callback = external_callback;
131
- external_callback = NULL;
132
-
133
- callback();
134
- }
156
+ run_external_callback();
135
157
 
136
158
  memcpy( &current_read_set, &event_read_set, sizeof( fd_set ) );
137
159
  memcpy( &current_write_set, &event_write_set, sizeof( fd_set ) );
@@ -143,6 +165,7 @@ _run_event_handler_once( int timeout_usec ) {
143
165
 
144
166
  if ( set_count == -1 ) {
145
167
  if ( errno == EINTR ) {
168
+ run_external_callback();
146
169
  return true;
147
170
  }
148
171
  error( "Failed to select ( errno = %s [%d] ).", strerror( errno ), errno );
@@ -151,11 +174,13 @@ _run_event_handler_once( int timeout_usec ) {
151
174
  }
152
175
  else if ( set_count == 0 ) {
153
176
  // timed out
177
+ run_external_callback();
154
178
  return true;
155
179
  }
156
180
 
157
- event_fd *event_itr = event_list;
181
+ run_external_callback();
158
182
 
183
+ event_fd *event_itr = event_list;
159
184
  while ( event_itr < event_last ) {
160
185
  event_fd current_event = *event_itr;
161
186
 
@@ -163,6 +188,23 @@ _run_event_handler_once( int timeout_usec ) {
163
188
  current_event.write_callback( current_event.fd, current_event.write_data );
164
189
  }
165
190
 
191
+ // In the rare cases the current fd is closed, a new one is opened
192
+ // with the same fd and is put in the same location we can just
193
+ // wait for the next select call.
194
+ if ( current_event.fd == event_itr->fd ) {
195
+ event_itr = event_itr + 1;
196
+ }
197
+ else {
198
+ debug( "run_event_handler_once: event fd is changed ( current = %d, new = %d )", current_event.fd, event_itr->fd );
199
+ }
200
+ }
201
+
202
+ run_external_callback();
203
+
204
+ event_itr = event_list;
205
+ while ( event_itr < event_last ) {
206
+ event_fd current_event = *event_itr;
207
+
166
208
  if ( FD_ISSET( current_event.fd, &current_read_set ) ) {
167
209
  current_event.read_callback( current_event.fd, current_event.read_data );
168
210
  }
@@ -178,6 +220,8 @@ _run_event_handler_once( int timeout_usec ) {
178
220
  }
179
221
  }
180
222
 
223
+ run_external_callback();
224
+
181
225
  return true;
182
226
  }
183
227
  bool ( *run_event_handler_once )( int ) = _run_event_handler_once;
@@ -367,18 +411,6 @@ _writable( int fd ) {
367
411
  bool ( *writable )( int fd ) = _writable;
368
412
 
369
413
 
370
- static bool
371
- _set_external_callback( external_callback_t callback ) {
372
- if ( external_callback != NULL ) {
373
- return false;
374
- }
375
-
376
- external_callback = callback;
377
- return true;
378
- }
379
- bool ( *set_external_callback )( external_callback_t callback ) = _set_external_callback;
380
-
381
-
382
414
  /*
383
415
  * Local variables:
384
416
  * c-basic-offset: 2
@@ -27,7 +27,6 @@
27
27
 
28
28
 
29
29
  typedef void ( *event_fd_callback )( int, void *data );
30
- typedef void ( *external_callback_t )( void );
31
30
 
32
31
  extern void ( *init_event_handler )();
33
32
  extern void ( *finalize_event_handler )();
@@ -46,10 +45,6 @@ extern void ( *set_writable )( int fd, bool state );
46
45
  extern bool ( *readable )( int fd );
47
46
  extern bool ( *writable )( int fd );
48
47
 
49
- // Optional functions for event handlers to implement, must be signal
50
- // safe. Leave as NULL if not supported.
51
- extern bool ( *set_external_callback )( external_callback_t callback );
52
-
53
48
 
54
49
  #endif // EVENT_HANDLER_H
55
50
 
@@ -0,0 +1,126 @@
1
+ /*
2
+ * Copyright (C) 2013 NEC Corporation
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License, version 2, as
6
+ * published by the Free Software Foundation.
7
+ *
8
+ * This program is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ * GNU General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU General Public License along
14
+ * with this program; if not, write to the Free Software Foundation, Inc.,
15
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ */
17
+
18
+
19
+ #include <assert.h>
20
+ #include "external_callback.h"
21
+ #include "log.h"
22
+ #include "wrapper.h"
23
+
24
+ #ifdef UNIT_TESTING
25
+
26
+ #ifdef xcalloc
27
+ #undef xcalloc
28
+ #endif
29
+ #define xcalloc mock_xcalloc
30
+ extern void *mock_xcalloc( size_t nmemb, size_t size );
31
+
32
+ #ifdef xfree
33
+ #undef xfree
34
+ #endif
35
+ #define xfree mock_xfree
36
+ extern void mock_xfree( void *ptr );
37
+
38
+ #ifdef debug
39
+ #undef debug
40
+ #endif
41
+ #define debug mock_debug
42
+ extern void mock_debug( const char *format, ... );
43
+
44
+ #define static
45
+
46
+ #endif // UNIT_TESTING
47
+
48
+
49
+ typedef struct {
50
+ external_callback_t *buffer;
51
+ unsigned int size;
52
+ unsigned int write_position;
53
+ unsigned int read_position;
54
+ } ring_buffer;
55
+
56
+ static const unsigned int MAX_EXTERNAL_CALLBACK = 16;
57
+ static ring_buffer *external_callbacks = NULL;
58
+
59
+
60
+ static void
61
+ _init_external_callback() {
62
+ assert( external_callbacks == NULL );
63
+
64
+ external_callbacks = xcalloc( 1, sizeof( ring_buffer ) );
65
+ external_callbacks->buffer = xcalloc( MAX_EXTERNAL_CALLBACK, sizeof( external_callback_t * ) );
66
+ external_callbacks->size = MAX_EXTERNAL_CALLBACK;
67
+ }
68
+ void ( *init_external_callback )() = _init_external_callback;
69
+
70
+
71
+ static void
72
+ _finalize_external_callback() {
73
+ assert( external_callbacks != NULL );
74
+ assert( external_callbacks->buffer != NULL );
75
+
76
+ xfree( external_callbacks->buffer );
77
+ xfree( external_callbacks );
78
+ external_callbacks = NULL;
79
+ }
80
+ void ( *finalize_external_callback )() = _finalize_external_callback;
81
+
82
+
83
+ static bool
84
+ _push_external_callback( external_callback_t callback ) {
85
+ if ( callback == NULL ) {
86
+ return false;
87
+ }
88
+ if ( external_callbacks == NULL ) {
89
+ return false;
90
+ }
91
+ assert( external_callbacks->buffer != NULL );
92
+
93
+ debug( "push_external_callback: %p", callback );
94
+ unsigned int write_pos = __sync_fetch_and_add( &external_callbacks->write_position, 1 ) % external_callbacks->size;
95
+ assert( __sync_bool_compare_and_swap( &( external_callbacks->buffer[ write_pos ] ), NULL, callback ) );
96
+
97
+ return true;
98
+ }
99
+ bool ( *push_external_callback )( external_callback_t callback ) = _push_external_callback;
100
+
101
+
102
+ static void
103
+ _run_external_callback() {
104
+ assert( external_callbacks != NULL );
105
+ assert( external_callbacks->buffer != NULL );
106
+
107
+ while ( external_callbacks->write_position != external_callbacks->read_position ) {
108
+ unsigned int read_pos = external_callbacks->read_position % external_callbacks->size;
109
+ external_callback_t callback = external_callbacks->buffer[ read_pos ];
110
+ assert( callback != NULL );
111
+ external_callbacks->buffer[ read_pos ] = NULL;
112
+ external_callbacks->read_position++;
113
+ debug( "run_external_callback: %p ( write_position = %u, read_position = %u )", callback,
114
+ external_callbacks->write_position, external_callbacks->read_position );
115
+ callback();
116
+ }
117
+ }
118
+ void ( *run_external_callback )() = _run_external_callback;
119
+
120
+
121
+ /*
122
+ * Local variables:
123
+ * c-basic-offset: 2
124
+ * indent-tabs-mode: nil
125
+ * End:
126
+ */
@@ -0,0 +1,46 @@
1
+ /*
2
+ * External callback implementation
3
+ *
4
+ * Copyright (C) 2013 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
+ #ifndef EXTERNAL_CALLBACK_H
22
+ #define EXTERNAL_CALLBACK_H
23
+
24
+
25
+ #include <sys/types.h>
26
+ #include "bool.h"
27
+
28
+ typedef void ( *external_callback_t )( void );
29
+
30
+ extern void ( *init_external_callback )( void );
31
+ extern void ( *finalize_external_callback )( void );
32
+ extern bool ( *push_external_callback )( external_callback_t callback );
33
+ extern void ( *run_external_callback )( void );
34
+
35
+ #define set_external_callback( callback ) push_external_callback( callback )
36
+
37
+
38
+ #endif // EXTERNAL_CALLBACK_H
39
+
40
+
41
+ /*
42
+ * Local variables:
43
+ * c-basic-offset: 2
44
+ * indent-tabs-mode: nil
45
+ * End:
46
+ */
data/src/lib/messenger.c CHANGED
@@ -141,6 +141,7 @@ enum {
141
141
  MESSAGE_TYPE_NOTIFY,
142
142
  MESSAGE_TYPE_REQUEST,
143
143
  MESSAGE_TYPE_REPLY,
144
+ MESSAGE_TYPE_INVALID = 255,
144
145
  };
145
146
 
146
147
  typedef struct message_buffer {
@@ -172,6 +173,7 @@ typedef struct receive_queue {
172
173
  struct sockaddr_un listen_addr;
173
174
  dlist_element *client_sockets;
174
175
  message_buffer *buffer;
176
+ bool in_progress;
175
177
  } receive_queue;
176
178
 
177
179
  typedef struct send_queue {
@@ -425,12 +427,14 @@ delete_receive_queue( void *service_name, void *_rq, void *user_data ) {
425
427
  receive_queue_callback *cb;
426
428
 
427
429
  assert( rq != NULL );
430
+ assert( rq->in_progress == false );
428
431
  for ( element = rq->message_callbacks->next; element; element = element->next ) {
429
432
  cb = element->data;
430
433
  debug( "Deleting a callback ( function = %p, message_type = %#x ).", cb->function, cb->message_type );
431
434
  xfree( cb );
432
435
  }
433
436
  delete_dlist( rq->message_callbacks );
437
+ rq->message_callbacks = NULL;
434
438
 
435
439
  for ( element = rq->client_sockets->next; element; element = element->next ) {
436
440
  client_socket = element->data;
@@ -591,6 +595,7 @@ create_receive_queue( const char *service_name ) {
591
595
  rq->message_callbacks = create_dlist();
592
596
  rq->client_sockets = create_dlist();
593
597
  rq->buffer = create_message_buffer( messenger_recv_queue_length );
598
+ rq->in_progress = false;
594
599
 
595
600
  insert_hash_entry( receive_queues, rq->service_name, rq );
596
601
 
@@ -699,11 +704,17 @@ delete_message_callback( const char *service_name, uint8_t message_type, void (
699
704
  cb = e->data;
700
705
  if ( ( cb->function == callback ) && ( cb->message_type == message_type ) ) {
701
706
  debug( "Deleting a callback ( message_type = %#x, callback = %p ).", message_type, callback );
702
- xfree( cb );
703
- delete_dlist_element( e );
704
- if ( rq->message_callbacks->next == NULL ) {
705
- debug( "No more callback for message_type = %#x.", message_type );
706
- delete_receive_queue( rq->service_name, rq, NULL );
707
+ if ( rq->in_progress ) {
708
+ cb->function = NULL;
709
+ cb->message_type = MESSAGE_TYPE_INVALID;
710
+ }
711
+ else {
712
+ xfree( cb );
713
+ delete_dlist_element( e );
714
+ if ( rq->message_callbacks->next == NULL ) {
715
+ debug( "No more callback for message_type = %#x.", message_type );
716
+ delete_receive_queue( rq->service_name, rq, NULL );
717
+ }
707
718
  }
708
719
  return true;
709
720
  }
@@ -844,17 +855,15 @@ send_queue_connect( send_queue *sq ) {
844
855
  return -1;
845
856
  }
846
857
 
847
- if ( geteuid() == 0 ) {
848
- int wmem_size = 1048576;
849
- int ret = setsockopt( sq->server_socket, SOL_SOCKET, SO_SNDBUFFORCE, ( const void * ) &wmem_size, ( socklen_t ) sizeof( wmem_size ) );
850
- if ( ret < 0 ) {
851
- error( "Failed to set SO_SNDBUFFORCE to %d ( %s [%d] ).", wmem_size, strerror( errno ), errno );
852
- close( sq->server_socket );
853
- sq->server_socket = -1;
854
- return -1;
855
- }
858
+ sq->socket_buffer_size = 1048576;
859
+ int ret = setsockopt( sq->server_socket, SOL_SOCKET, SO_SNDBUF, ( const void * ) &sq->socket_buffer_size, ( socklen_t ) sizeof( sq->socket_buffer_size ) );
860
+ if ( ret < 0 ) {
861
+ error( "Failed to set SO_SNDBUF to %d ( %s [%d] ).", sq->socket_buffer_size, strerror( errno ), errno );
862
+ close( sq->server_socket );
863
+ sq->server_socket = -1;
864
+ return -1;
856
865
  }
857
- int ret = fcntl( sq->server_socket, F_SETFL, O_NONBLOCK );
866
+ ret = fcntl( sq->server_socket, F_SETFL, O_NONBLOCK );
858
867
  if ( ret < 0 ) {
859
868
  error( "Failed to set O_NONBLOCK ( %s [%d] ).", strerror( errno ), errno );
860
869
  close( sq->server_socket );
@@ -873,7 +882,7 @@ send_queue_connect( send_queue *sq ) {
873
882
  return 0;
874
883
  }
875
884
 
876
- set_fd_handler( sq->server_socket, on_send_read, sq, &on_send_write, sq );
885
+ set_fd_handler( sq->server_socket, on_send_read, sq, on_send_write, sq );
877
886
  set_readable( sq->server_socket, true );
878
887
 
879
888
  if ( sq->buffer != NULL && sq->buffer->data_length >= sizeof( message_header ) ) {
@@ -1092,9 +1101,7 @@ push_message_to_send_queue( const char *service_name, const uint8_t message_type
1092
1101
  }
1093
1102
 
1094
1103
  set_writable( sq->server_socket, true );
1095
- if ( sq->buffer->data_length > messenger_send_length_for_flush ) {
1096
- on_send_write( sq->server_socket, sq );
1097
- }
1104
+
1098
1105
  return true;
1099
1106
  }
1100
1107
 
@@ -1215,7 +1222,7 @@ _clear_send_queue( const char *service_name ) {
1215
1222
  return false;
1216
1223
  }
1217
1224
 
1218
- if ( sq->buffer->data_length > 0 ) {
1225
+ if ( sq->server_socket > -1 ) {
1219
1226
  set_writable( sq->server_socket, false );
1220
1227
  }
1221
1228
 
@@ -1369,14 +1376,13 @@ truncate_message_buffer( message_buffer *buf, size_t len ) {
1369
1376
  len = buf->data_length;
1370
1377
  }
1371
1378
 
1372
- if ( ( buf->head_offset + len ) <= buf->size ) {
1373
- buf->head_offset += len;
1379
+ buf->data_length -= len;
1380
+ if ( buf->data_length == 0 ) {
1381
+ buf->head_offset = 0;
1374
1382
  }
1375
1383
  else {
1376
- memmove( buf->buffer, ( char * ) buf->buffer + buf->head_offset + len, buf->data_length - len );
1377
- buf->head_offset = 0;
1384
+ buf->head_offset += len;
1378
1385
  }
1379
- buf->data_length -= len;
1380
1386
  }
1381
1387
 
1382
1388
 
@@ -1437,15 +1443,18 @@ static void
1437
1443
  call_message_callbacks( receive_queue *rq, const uint8_t message_type, const uint16_t tag, void *data, size_t len ) {
1438
1444
  assert( rq != NULL );
1439
1445
 
1440
- dlist_element *element;
1446
+ dlist_element *element, *next;
1441
1447
  receive_queue_callback *cb;
1442
1448
 
1443
1449
  debug( "Calling message callbacks ( service_name = %s, message_type = %#x, tag = %#x, data = %p, len = %zu ).",
1444
1450
  rq->service_name, message_type, tag, data, len );
1445
1451
 
1446
- for ( element = rq->message_callbacks->next; element; element = element->next ) {
1452
+ assert( rq->in_progress != true );
1453
+ rq->in_progress = true;
1454
+ for ( element = rq->message_callbacks->next; element; element = next ) {
1455
+ next = element->next;
1447
1456
  cb = element->data;
1448
- if ( cb->message_type != message_type ) {
1457
+ if ( cb == NULL || cb->function == NULL || cb->message_type != message_type ) {
1449
1458
  continue;
1450
1459
  }
1451
1460
  switch ( message_type ) {
@@ -1511,6 +1520,19 @@ call_message_callbacks( receive_queue *rq, const uint8_t message_type, const uin
1511
1520
  assert( 0 );
1512
1521
  }
1513
1522
  }
1523
+ for ( element = rq->message_callbacks->next; element; element = next ) {
1524
+ next = element->next;
1525
+ cb = element->data;
1526
+ if ( cb->function == NULL ) {
1527
+ xfree( cb );
1528
+ delete_dlist_element( element );
1529
+ }
1530
+ }
1531
+ rq->in_progress = false;
1532
+ if ( rq->message_callbacks->next == NULL ) {
1533
+ debug( "No more callback for message_type = %#x.", message_type );
1534
+ delete_receive_queue( rq->service_name, rq, NULL );
1535
+ }
1514
1536
  }
1515
1537
 
1516
1538
 
@@ -1648,11 +1670,6 @@ on_send_write( int fd, void *data ) {
1648
1670
  debug( "Sending data to remote ( fd = %d, service_name = %s, buffer = %p, data_length = %zu ).",
1649
1671
  fd, sq->service_name, get_message_buffer_head( sq->buffer ), sq->buffer->data_length );
1650
1672
 
1651
- if ( sq->buffer->data_length < sizeof( message_header ) ) {
1652
- set_writable( sq->server_socket, false );
1653
- return;
1654
- }
1655
-
1656
1673
  void *send_data;
1657
1674
  size_t send_len;
1658
1675
  ssize_t sent_len;
@@ -1664,8 +1681,14 @@ on_send_write( int fd, void *data ) {
1664
1681
  if ( sent_len == -1 ) {
1665
1682
  int err = errno;
1666
1683
  if ( err != EAGAIN && err != EWOULDBLOCK ) {
1667
- error( "Failed to send ( service_name = %s, fd = %d, errno = %s [%d] ).",
1668
- sq->service_name, fd, strerror( err ), err );
1684
+ if ( err == EPIPE ) {
1685
+ debug( "Failed to send ( service_name = %s, fd = %d, errno = %s [%d] ).",
1686
+ sq->service_name, fd, strerror( err ), err );
1687
+ }
1688
+ else {
1689
+ error( "Failed to send ( service_name = %s, fd = %d, errno = %s [%d] ).",
1690
+ sq->service_name, fd, strerror( err ), err );
1691
+ }
1669
1692
  send_dump_message( MESSENGER_DUMP_SEND_CLOSED, sq->service_name, NULL, 0 );
1670
1693
 
1671
1694
  set_readable( sq->server_socket, false );