|
9 | 9 | #include <aws/common/device_random.h> |
10 | 10 | #include <aws/common/encoding.h> |
11 | 11 | #include <aws/common/mutex.h> |
| 12 | +#include <aws/common/ref_count.h> |
12 | 13 | #include <aws/http/private/websocket_decoder.h> |
13 | 14 | #include <aws/http/private/websocket_encoder.h> |
14 | 15 | #include <aws/http/request_response.h> |
@@ -41,6 +42,7 @@ struct outgoing_frame { |
41 | 42 |
|
42 | 43 | struct aws_websocket { |
43 | 44 | struct aws_allocator *alloc; |
| 45 | + struct aws_ref_count ref_count; |
44 | 46 | struct aws_channel_handler channel_handler; |
45 | 47 | struct aws_channel_slot *channel_slot; |
46 | 48 | size_t initial_window_size; |
@@ -137,9 +139,6 @@ struct aws_websocket { |
137 | 139 |
|
138 | 140 | /* Mirrors variable from thread_data */ |
139 | 141 | bool is_midchannel_handler; |
140 | | - |
141 | | - /* Whether aws_websocket_release() has been called */ |
142 | | - bool is_released; |
143 | 142 | } synced_data; |
144 | 143 | }; |
145 | 144 |
|
@@ -168,6 +167,7 @@ static int s_handler_shutdown( |
168 | 167 | static size_t s_handler_initial_window_size(struct aws_channel_handler *handler); |
169 | 168 | static size_t s_handler_message_overhead(struct aws_channel_handler *handler); |
170 | 169 | static void s_handler_destroy(struct aws_channel_handler *handler); |
| 170 | +static void s_websocket_on_refcount_zero(void *user_data); |
171 | 171 |
|
172 | 172 | static int s_encoder_stream_outgoing_payload(struct aws_byte_buf *out_buf, void *user_data); |
173 | 173 |
|
@@ -271,6 +271,7 @@ struct aws_websocket *aws_websocket_handler_new(const struct aws_websocket_handl |
271 | 271 | } |
272 | 272 |
|
273 | 273 | websocket->alloc = options->allocator; |
| 274 | + aws_ref_count_init(&websocket->ref_count, websocket, s_websocket_on_refcount_zero); |
274 | 275 | websocket->channel_handler.vtable = &s_channel_handler_vtable; |
275 | 276 | websocket->channel_handler.alloc = options->allocator; |
276 | 277 | websocket->channel_handler.impl = websocket; |
@@ -357,30 +358,28 @@ static void s_handler_destroy(struct aws_channel_handler *handler) { |
357 | 358 | aws_mem_release(websocket->alloc, websocket); |
358 | 359 | } |
359 | 360 |
|
360 | | -void aws_websocket_release(struct aws_websocket *websocket) { |
361 | | - AWS_ASSERT(websocket); |
362 | | - AWS_ASSERT(websocket->channel_slot); |
363 | | - |
364 | | - bool was_already_released; |
365 | | - |
366 | | - /* BEGIN CRITICAL SECTION */ |
367 | | - s_lock_synced_data(websocket); |
368 | | - if (websocket->synced_data.is_released) { |
369 | | - was_already_released = true; |
370 | | - } else { |
371 | | - was_already_released = false; |
372 | | - websocket->synced_data.is_released = true; |
373 | | - } |
374 | | - s_unlock_synced_data(websocket); |
375 | | - /* END CRITICAL SECTION */ |
| 361 | +struct aws_websocket *aws_websocket_acquire(struct aws_websocket *websocket) { |
| 362 | + AWS_PRECONDITION(websocket); |
| 363 | + AWS_LOGF_TRACE(AWS_LS_HTTP_WEBSOCKET, "id=%p: Acquiring websocket ref-count.", (void *)websocket); |
| 364 | + aws_ref_count_acquire(&websocket->ref_count); |
| 365 | + return websocket; |
| 366 | +} |
376 | 367 |
|
377 | | - if (was_already_released) { |
378 | | - AWS_LOGF_TRACE( |
379 | | - AWS_LS_HTTP_WEBSOCKET, "id=%p: Ignoring multiple calls to websocket release.", (void *)websocket); |
| 368 | +void aws_websocket_release(struct aws_websocket *websocket) { |
| 369 | + if (!websocket) { |
380 | 370 | return; |
381 | 371 | } |
382 | 372 |
|
383 | | - AWS_LOGF_TRACE(AWS_LS_HTTP_WEBSOCKET, "id=%p: Websocket released, shut down if necessary.", (void *)websocket); |
| 373 | + AWS_LOGF_TRACE(AWS_LS_HTTP_WEBSOCKET, "id=%p: Releasing websocket ref-count.", (void *)websocket); |
| 374 | + aws_ref_count_release(&websocket->ref_count); |
| 375 | +} |
| 376 | + |
| 377 | +static void s_websocket_on_refcount_zero(void *user_data) { |
| 378 | + struct aws_websocket *websocket = user_data; |
| 379 | + AWS_ASSERT(websocket->channel_slot); |
| 380 | + |
| 381 | + AWS_LOGF_TRACE( |
| 382 | + AWS_LS_HTTP_WEBSOCKET, "id=%p: Websocket ref-count is zero, shut down if necessary.", (void *)websocket); |
384 | 383 |
|
385 | 384 | /* Channel might already be shut down, but make sure */ |
386 | 385 | s_schedule_channel_shutdown(websocket, AWS_ERROR_SUCCESS); |
@@ -422,26 +421,6 @@ int aws_websocket_convert_to_midchannel_handler(struct aws_websocket *websocket) |
422 | 421 | return aws_raise_error(AWS_ERROR_INVALID_STATE); |
423 | 422 | } |
424 | 423 |
|
425 | | - bool was_released = false; |
426 | | - |
427 | | - /* BEGIN CRITICAL SECTION */ |
428 | | - s_lock_synced_data(websocket); |
429 | | - if (websocket->synced_data.is_released) { |
430 | | - was_released = true; |
431 | | - } else { |
432 | | - websocket->synced_data.is_midchannel_handler = true; |
433 | | - } |
434 | | - s_unlock_synced_data(websocket); |
435 | | - /* END CRITICAL SECTION */ |
436 | | - |
437 | | - if (was_released) { |
438 | | - AWS_LOGF_ERROR( |
439 | | - AWS_LS_HTTP_WEBSOCKET, |
440 | | - "id=%p: Cannot convert websocket to midchannel handler because it was already released.", |
441 | | - (void *)websocket); |
442 | | - return aws_raise_error(AWS_ERROR_HTTP_CONNECTION_CLOSED); |
443 | | - } |
444 | | - |
445 | 424 | websocket->thread_data.is_midchannel_handler = true; |
446 | 425 |
|
447 | 426 | return AWS_OP_SUCCESS; |
|
0 commit comments