trema 0.4.5 → 0.4.6

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 (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 );