1a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* 2a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Copyright (C) 2012 The Android Open Source Project 3a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * 4a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License"); 5a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * you may not use this file except in compliance with the License. 6a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * You may obtain a copy of the License at 7a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * 8a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * http://www.apache.org/licenses/LICENSE-2.0 9a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * 10a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software 11a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS, 12a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * See the License for the specific language governing permissions and 14a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * limitations under the License. 15a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 16a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 17a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* 18a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Encapsulates exchange protocol between the emulator, and an Android device 19a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * that is connected to the host via USB. The communication is established over 20a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * a TCP port forwarding, enabled by ADB. 21a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 22a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 23a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#include "android/async-socket-connector.h" 24a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#include "android/async-socket.h" 25af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/debug.h" 26af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/eintr_wrapper.h" 27af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/panic.h" 28d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "android/iolooper.h" 29a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 30a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define E(...) derror(__VA_ARGS__) 31a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define W(...) dwarning(__VA_ARGS__) 32a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define D(...) VERBOSE_PRINT(asyncsocket,__VA_ARGS__) 33a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define D_ACTIVE VERBOSE_CHECK(asyncsocket) 34a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 35c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define TRACE_ON 0 36c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 37c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#if TRACE_ON 38c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define T(...) VERBOSE_PRINT(asyncsocket,__VA_ARGS__) 39c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else 40c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define T(...) 41c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif 42c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 43a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/******************************************************************************** 44a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Asynchronous Socket internal API declarations 45a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/ 46a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 47a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Gets socket's address string. */ 48a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const char* _async_socket_string(AsyncSocket* as); 49a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 50a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Gets socket's looper. */ 51a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic Looper* _async_socket_get_looper(AsyncSocket* as); 52a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 53a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Handler for the I/O time out. 54a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * as - Asynchronous socket for the I/O. 56a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - Desciptor for the timed out I/O. 57a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction _async_socket_io_timed_out(AsyncSocket* as, 596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncSocketIO* asio); 60a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 61a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/******************************************************************************** 62a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Asynchronous Socket Reader / Writer 63a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/ 64a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 65a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestruct AsyncSocketIO { 66a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Next I/O in the reader, or writer list. */ 67a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* next; 68a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Asynchronous socket for this I/O. */ 69a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocket* as; 70a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Timer used for time outs on this I/O. */ 71a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine LoopTimer timer[1]; 72a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* An opaque pointer associated with this I/O. */ 73a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* io_opaque; 74a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Buffer where to read / write data. */ 75a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint8_t* buffer; 76a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Bytes to transfer through the socket for this I/O. */ 77a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint32_t to_transfer; 78a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Bytes thransferred through the socket in this I/O. */ 79a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint32_t transferred; 806dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* I/O callback for this I/O. */ 816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb on_io; 82a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* I/O type selector: 1 - read, 0 - write. */ 83a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int is_io_read; 846dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* State of the I/O. */ 856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOState state; 86ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Number of outstanding references to the I/O. */ 87ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine int ref_count; 88ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Deadline for this I/O */ 89ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine Duration deadline; 90a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}; 91a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 92a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* 93a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Recycling I/O instances. 94a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Since AsyncSocketIO instances are not that large, it makes sence to recycle 95a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * them for faster allocation, rather than allocating and freeing them for each 96a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O on the socket. 97a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 98a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 99a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* List of recycled I/O descriptors. */ 100a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* _asio_recycled = NULL; 101a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Number of I/O descriptors that are recycled in the _asio_recycled list. */ 102a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int _recycled_asio_count = 0; 103a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Maximum number of I/O descriptors that can be recycled. */ 104a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const int _max_recycled_asio_num = 32; 105a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 106a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Handler for an I/O time-out timer event. 107a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * When this routine is invoked, it indicates that a time out has occurred on an 108a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O. 109a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 110a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * opaque - AsyncSocketIO instance representing the timed out I/O. 111a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 112a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void _on_async_socket_io_timed_out(void* opaque); 113a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 114a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new I/O descriptor. 115a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 116a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Asynchronous socket for the I/O. 117a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * is_io_read - I/O type selector: 1 - read, 0 - write. 118a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * buffer, len - Reader / writer buffer address. 1196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * io_cb - Callback for this reader / writer. 120a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * io_opaque - An opaque pointer associated with the I/O. 121a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * deadline - Deadline to complete the I/O. 122a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 123a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Initialized AsyncSocketIO instance. 124a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 125a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 126a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_rw_new(AsyncSocket* as, 127a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int is_io_read, 128a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* buffer, 129a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint32_t len, 1306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb io_cb, 131a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* io_opaque, 132a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Duration deadline) 133a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 134a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Lookup in the recycler first. */ 135a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* asio = _asio_recycled; 136a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (asio != NULL) { 137a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Pull the descriptor from recycler. */ 138a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _asio_recycled = asio->next; 139a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _recycled_asio_count--; 140a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 141a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* No recycled descriptors. Allocate new one. */ 142a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine ANEW0(asio); 143a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 144a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 145a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->next = NULL; 146a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->as = as; 147a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->is_io_read = is_io_read; 148a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->buffer = (uint8_t*)buffer; 149a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->to_transfer = len; 150a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->transferred = 0; 1516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asio->on_io = io_cb; 152a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->io_opaque = io_opaque; 1536dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asio->state = ASIO_STATE_QUEUED; 154ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine asio->ref_count = 1; 155ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine asio->deadline = deadline; 156a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_init(asio->timer, _async_socket_get_looper(as), 157a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _on_async_socket_io_timed_out, asio); 158a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_startAbsolute(asio->timer, deadline); 159a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 160ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference socket that is holding this I/O. */ 161ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_reference(as); 162ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 163c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O descriptor %p is created for %d bytes of data", 164c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), is_io_read ? "READ" : "WRITE", asio, len); 165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 166a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return asio; 167a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 168a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 169a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Destroys and frees I/O descriptor. */ 170a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 171ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine_async_socket_io_free(AsyncSocketIO* asio) 172a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 173ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine AsyncSocket* const as = asio->as; 174ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O descriptor %p is destroyed.", 176c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio); 177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 178a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_done(asio->timer); 179a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 180a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Try to recycle it first, and free the memory if recycler is full. */ 181a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (_recycled_asio_count < _max_recycled_asio_num) { 182a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asio->next = _asio_recycled; 183a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _asio_recycled = asio; 184a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _recycled_asio_count++; 185a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 186a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AFREE(asio); 187a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 188ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 189ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Release socket that is holding this I/O. */ 190ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 191ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine} 192ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O has been finished and its descriptor is about to be discarded. */ 194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void 195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_async_socket_io_finished(AsyncSocketIO* asio) 196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{ 197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine /* Notify the client of the I/O that I/O is finished. */ 198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine asio->on_io(asio->io_opaque, asio, ASIO_STATE_FINISHED); 199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} 200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 201ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint 202ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_io_reference(AsyncSocketIO* asio) 203ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{ 204ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine assert(asio->ref_count > 0); 205ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine asio->ref_count++; 206ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return asio->ref_count; 207ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine} 208ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 209ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint 210ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_io_release(AsyncSocketIO* asio) 211ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{ 212ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine assert(asio->ref_count > 0); 213ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine asio->ref_count--; 214ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine if (asio->ref_count == 0) { 215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_io_finished(asio); 216ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Last reference has been dropped. Destroy this object. */ 217ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_io_free(asio); 218ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return 0; 219ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine } 220ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return asio->ref_count; 221a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 222a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 223a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new asynchronous socket reader. 224a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 225a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Asynchronous socket for the reader. 226a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * buffer, len - Reader's buffer. 2276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * io_cb - Reader's callback. 228a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * reader_opaque - An opaque pointer associated with the reader. 229a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * deadline - Deadline to complete the operation. 230a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 231a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * An initialized AsyncSocketIO intance. 232a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 233a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 234a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_reader_new(AsyncSocket* as, 235a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* buffer, 236a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint32_t len, 2376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb io_cb, 238a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* reader_opaque, 239a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Duration deadline) 240a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 241a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asio = _async_socket_rw_new(as, 1, buffer, len, io_cb, 242a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine reader_opaque, deadline); 243a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return asio; 244a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 245a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 246a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new asynchronous socket writer. 247a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 248a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Asynchronous socket for the writer. 249a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * buffer, len - Writer's buffer. 2506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * io_cb - Writer's callback. 251a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * writer_opaque - An opaque pointer associated with the writer. 252a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * deadline - Deadline to complete the operation. 253a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 254a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * An initialized AsyncSocketIO intance. 255a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 256a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 257a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_writer_new(AsyncSocket* as, 258a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine const void* buffer, 259a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine uint32_t len, 2606dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb io_cb, 261a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* writer_opaque, 262a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Duration deadline) 263a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 264a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asio = _async_socket_rw_new(as, 0, (void*)buffer, len, 265a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine io_cb, writer_opaque, 266a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine deadline); 267a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return asio; 268a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 269a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 270a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* I/O timed out. */ 271a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 272a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_io_timed_out(void* opaque) 273a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 274a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asio = (AsyncSocketIO*)opaque; 275ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine AsyncSocket* const as = asio->as; 276ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 277c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: %s I/O with deadline %lld has timed out at %lld", 278ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", 279ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine asio->deadline, async_socket_deadline(as, 0)); 280ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 281ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference while in callback. */ 282ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_reference(asio); 283ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_io_timed_out(asio->as, asio); 284ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asio); 2856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 2866dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 2876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine/******************************************************************************** 2886dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Public Asynchronous Socket I/O API 2896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *******************************************************************************/ 2906dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 2916dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir ChtchetkineAsyncSocket* 2926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_socket(const AsyncSocketIO* asio) 2936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 294ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_reference(asio->as); 2956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->as; 2966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 2976dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 2986dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 2996dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_cancel_time_out(AsyncSocketIO* asio) 3006dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3016dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopTimer_stop(asio->timer); 3026dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid* 3056dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_io_opaque(const AsyncSocketIO* asio) 3066dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3076dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->io_opaque; 3086dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3096dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3106dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid* 3116dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_client_opaque(const AsyncSocketIO* asio) 3126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return async_socket_get_client_opaque(asio->as); 3146dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3166dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid* 3176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_buffer_info(const AsyncSocketIO* asio, 3186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine uint32_t* transferred, 3196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine uint32_t* to_transfer) 3206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (transferred != NULL) { 3226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *transferred = asio->transferred; 3236dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 3246dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (to_transfer != NULL) { 3256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *to_transfer = asio->to_transfer; 3266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 3276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->buffer; 3286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid* 3316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_buffer(const AsyncSocketIO* asio) 3326dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3336dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->buffer; 3346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3356dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3366dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineuint32_t 3376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_transferred(const AsyncSocketIO* asio) 3386dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->transferred; 3406dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3416dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3426dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineuint32_t 3436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_to_transfer(const AsyncSocketIO* asio) 3446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3456dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->to_transfer; 3466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 3476dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 3486dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineint 3496dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_is_read(const AsyncSocketIO* asio) 3506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 3516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->is_io_read; 352a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 353a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 354a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/******************************************************************************** 355a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Asynchronous Socket internals 356a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/ 357a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 358a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestruct AsyncSocket { 359a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* TCP address for the socket. */ 360a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine SockAddress address; 3616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Connection callback for this socket. */ 3626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_connection_cb on_connection; 363a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* An opaque pointer associated with this socket by the client. */ 364a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* client_opaque; 365a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* I/O looper for asynchronous I/O on the socket. */ 366a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Looper* looper; 367a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* I/O descriptor for asynchronous I/O on the socket. */ 368a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine LoopIo io[1]; 369a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Timer to use for reconnection attempts. */ 370a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine LoopTimer reconnect_timer[1]; 371a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Head of the list of the active readers. */ 372a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* readers_head; 373a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Tail of the list of the active readers. */ 374a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* readers_tail; 375a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Head of the list of the active writers. */ 376a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* writers_head; 377a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Tail of the list of the active writers. */ 378a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* writers_tail; 379a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Socket's file descriptor. */ 380a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int fd; 381a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Timeout to use for reconnection attempts. */ 382a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int reconnect_to; 383ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Number of outstanding references to the socket. */ 384ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine int ref_count; 385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine /* Flags whether (1) or not (0) socket owns the looper. */ 386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine int owns_looper; 387a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}; 388a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 389a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const char* 390a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_string(AsyncSocket* as) 391a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 392a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return sock_address_to_string(&as->address); 393a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 394a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 395a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic Looper* 396a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_get_looper(AsyncSocket* as) 397a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 398a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return as->looper; 399a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 400a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 401a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first reader out of the list. 402a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 403a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 404a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 405a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * First I/O pulled out of the list, or NULL if there are no I/O in the list. 406ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * Note that the caller is responsible for releasing the I/O object returned 407ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * from this routine. 408a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 409a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 410a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_io(AsyncSocket* as, 411a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_head, 412a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_tail) 413a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 414a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const ret = *list_head; 415a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (ret != NULL) { 416a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_head = ret->next; 417a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine ret->next = NULL; 418a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (*list_head == NULL) { 419a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_tail = NULL; 420a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 421a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 422a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return ret; 423a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 424a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 425a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first reader out of the list. 426a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 427a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 428a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 429a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * First reader pulled out of the list, or NULL if there are no readers in the 430a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * list. 431ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * Note that the caller is responsible for releasing the I/O object returned 432ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * from this routine. 433a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 434a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 435a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_reader(AsyncSocket* as) 436a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 437a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return _async_socket_pull_first_io(as, &as->readers_head, &as->readers_tail); 438a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 439a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 440a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first writer out of the list. 441a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 442a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 443a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 444a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * First writer pulled out of the list, or NULL if there are no writers in the 445a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * list. 446ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * Note that the caller is responsible for releasing the I/O object returned 447ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine * from this routine. 448a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 449a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* 450a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_writer(AsyncSocket* as) 451a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 452a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return _async_socket_pull_first_io(as, &as->writers_head, &as->writers_tail); 453a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 454a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 455a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Removes an I/O descriptor from a list of active I/O. 456a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 457a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 458a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * list_head, list_tail - Pointers to the list head and tail. 459a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * io - I/O to remove. 460a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 461a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Boolean: 1 if I/O has been removed, or 0 if I/O has not been found in the list. 462a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 463a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int 464a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_remove_io(AsyncSocket* as, 465a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_head, 466a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_tail, 467a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* io) 468a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 469a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* prev = NULL; 470a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 471a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine while (*list_head != NULL && io != *list_head) { 472a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine prev = *list_head; 473a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine list_head = &((*list_head)->next); 474a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 475a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (*list_head == NULL) { 476a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine D("%s: I/O %p is not found in the list for socket '%s'", 477a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine __FUNCTION__, io, _async_socket_string(as)); 478a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 479a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 480a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 481a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_head = io->next; 482a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (prev != NULL) { 483a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine prev->next = io->next; 484a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 485a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (*list_tail == io) { 486a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_tail = prev; 487a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 488a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 489ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Release I/O adjusting reference added when I/O has been saved in the list. */ 490ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(io); 491ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 492a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 1; 493a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 494a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 495a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next I/O in the list. 496a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 497a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 498a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * list_head, list_tail - Pointers to the list head and tail. 499a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 500ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void 501a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_io(AsyncSocket* as, 502a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_head, 503a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO** list_tail) 504a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 505a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* first_io = *list_head; 506a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (first_io != NULL) { 507a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_head = first_io->next; 508a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine first_io->next = NULL; 509a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 510a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (*list_head == NULL) { 511a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *list_tail = NULL; 512a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 513ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine if (first_io != NULL) { 514ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Release I/O removed from the head of the list. */ 515ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(first_io); 516ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine } 517a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 518a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 519a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next reader in the list. 520a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 521a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 522a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 523ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void 524a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_reader(AsyncSocket* as) 525a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 526ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_advance_io(as, &as->readers_head, &as->readers_tail); 527a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 528a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 529a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next writer in the list. 530a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 531a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 532a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 533ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void 534a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_writer(AsyncSocket* as) 535a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 536ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_advance_io(as, &as->writers_head, &as->writers_tail); 537a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 538a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 539a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Completes an I/O. 540a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 541a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 542a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - I/O to complete. 5436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return: 5446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * One of AsyncIOAction values. 545a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 5466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 547a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_complete_io(AsyncSocket* as, AsyncSocketIO* asio) 548a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O %p is completed.", 550c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio); 551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 552a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Stop the timer. */ 553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine async_socket_io_cancel_time_out(asio); 554a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 5556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->on_io(asio->io_opaque, asio, ASIO_STATE_SUCCEEDED); 556a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 557a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 558a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Timeouts an I/O. 559a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 560a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 561a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - An I/O that has timed out. 5626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return: 5636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * One of AsyncIOAction values. 564a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 5656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 566a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio) 567a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 568c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O %p with deadline %lld has timed out at %lld", 569c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio, 570c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine asio->deadline, async_socket_deadline(as, 0)); 571c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 5726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Report to the client. */ 5736dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine const AsyncIOAction action = asio->on_io(asio->io_opaque, asio, 5746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine ASIO_STATE_TIMED_OUT); 5756dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 5766dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Remove the I/O from a list of active I/O for actions other than retry. */ 5776dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (action != ASIO_ACTION_RETRY) { 5786dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (asio->is_io_read) { 5796dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio); 5806dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 5816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio); 5826dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 583a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 584a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 5856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return action; 586a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 587a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 588a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels an I/O. 589a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 590a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 591a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - An I/O to cancel. 5926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return: 5936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * One of AsyncIOAction values. 594a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 5956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 596a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio) 597a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O %p is cancelled.", 599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio); 600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 601a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Stop the timer. */ 602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine async_socket_io_cancel_time_out(asio); 603a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 6046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->on_io(asio->io_opaque, asio, ASIO_STATE_CANCELLED); 605a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 606a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 607a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Reports an I/O failure. 608a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 609a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 610a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - An I/O that has failed. Can be NULL for general failures. 611a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * failure - Failure (errno) that has occurred. 6126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return: 6136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * One of AsyncIOAction values. 614a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 6156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 616a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_io_failure(AsyncSocket* as, AsyncSocketIO* asio, int failure) 617a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: %s I/O %p has failed: %d -> %s", 619c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio, 620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine failure, strerror(failure)); 621c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 622a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Stop the timer. */ 623c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine async_socket_io_cancel_time_out(asio); 624a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 6256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine errno = failure; 6266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return asio->on_io(asio->io_opaque, asio, ASIO_STATE_FAILED); 627a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 628a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 629a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the active socket readers. 630a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 631a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 632a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 633a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 634a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_readers(AsyncSocket* as) 635a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 636a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine while (as->readers_head != NULL) { 637a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const to_cancel = _async_socket_pull_first_reader(as); 6386dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* We ignore action returned from the cancellation callback, since we're 6396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * in a disconnected state here. */ 640a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_io(as, to_cancel); 641ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(to_cancel); 642a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 643a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 644a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 645a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the active socket writers. 646a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 647a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 648a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 649a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 650a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_writers(AsyncSocket* as) 651a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 652a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine while (as->writers_head != NULL) { 653a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const to_cancel = _async_socket_pull_first_writer(as); 6546dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* We ignore action returned from the cancellation callback, since we're 6556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * in a disconnected state here. */ 656a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_io(as, to_cancel); 657ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(to_cancel); 658a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 659a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 660a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 661a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the I/O on the socket. */ 662a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 663a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_all_io(AsyncSocket* as) 664a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 665a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Stop the reconnection timer. */ 666a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_stop(as->reconnect_timer); 667a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 668a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Stop read / write on the socket. */ 669a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantWrite(as->io); 670a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantRead(as->io); 671a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 672a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Cancel active readers and writers. */ 673a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_readers(as); 674a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_writers(as); 675a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 676a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 677a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Closes socket handle used by the async socket. 678a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 679a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 680a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 681a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 682a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_close_socket(AsyncSocket* as) 683a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 684a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as->fd >= 0) { 685c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Socket handle %d is closed.", 686c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), as->fd); 6877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine loopIo_done(as->io); 6887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine socket_close(as->fd); 689a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine as->fd = -1; 690a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 691a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 692a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 693a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Destroys AsyncSocket instance. 694a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 695a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 696a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 697a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 698ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine_async_socket_free(AsyncSocket* as) 699a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 700a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as != NULL) { 701c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Socket descriptor is destroyed.", _async_socket_string(as)); 702a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 703a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Close socket. */ 704a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_close_socket(as); 705a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 706a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Free allocated resources. */ 707a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as->looper != NULL) { 708a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_done(as->reconnect_timer); 709c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine if (as->owns_looper) { 710c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine looper_free(as->looper); 711c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine } 712a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 713a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine sock_address_done(&as->address); 714a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AFREE(as); 715a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 716a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 717a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 718a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Starts reconnection attempts after connection has been lost. 719a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 720a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 721a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * to - Milliseconds to wait before reconnection attempt. 722a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 723a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 724a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_reconnect(AsyncSocket* as, int to) 725a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 726c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: reconnecting in %dms...", _async_socket_string(as), to); 727c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 728a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Make sure that no I/O is active, and socket is closed before we 729a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * reconnect. */ 730a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_all_io(as); 731a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 732a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Set the timer for reconnection attempt. */ 733a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_startRelative(as->reconnect_timer, to); 734a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 735a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 736a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/******************************************************************************** 737a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Asynchronous Socket callbacks 738a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/ 739a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 740a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when socket gets disconnected. 741a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 742a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 743a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 744a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 745a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_disconnected(AsyncSocket* as) 746a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 747a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Save error to restore it for the client's callback. */ 748a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine const int save_errno = errno; 7496dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOAction action = ASIO_ACTION_ABORT; 750a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 751c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Disconnected.", _async_socket_string(as)); 752a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 753a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Cancel all the I/O on this socket. */ 754a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_all_io(as); 755a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 756a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Close the socket. */ 757a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_close_socket(as); 758a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 759a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Restore errno, and invoke client's callback. */ 760a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine errno = save_errno; 7616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED); 762a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 7636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (action == ASIO_ACTION_RETRY) { 764a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Client requested reconnection. */ 7656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine _async_socket_reconnect(as, as->reconnect_to); 766a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 767a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 768a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 769a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked on socket's I/O failure. 770a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 771a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 772a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * asio - Descriptor for the failed I/O. Can be NULL for general failures. 773a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 7746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 775a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio) 776a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 777c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: %s I/O failure: %d -> %s", 778ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", 779ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine errno, strerror(errno)); 780a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 781a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Report the failure. */ 7826dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return _async_socket_io_failure(as, asio, errno); 783a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 784a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 785a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when there is data available to read. 786a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 787a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 788a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 789a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * 0 on success, or -1 on failure. Failure returned from this routine will 790a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * skip writes (if awailable) behind this read. 791a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 792a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int 793a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_recv(AsyncSocket* as) 794a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 7956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOAction action; 7966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 797a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Get current reader. */ 798a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asr = as->readers_head; 799a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (asr == NULL) { 800c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: No reader is available.", _async_socket_string(as)); 801a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantRead(as->io); 802a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 803a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 804a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 805ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference the reader while we're working with it in this callback. */ 806ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_reference(asr); 807ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 8086dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Bump I/O state, and inform the client that I/O is in progress. */ 8096dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (asr->state == ASIO_STATE_QUEUED) { 8106dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asr->state = ASIO_STATE_STARTED; 8116dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 8126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asr->state = ASIO_STATE_CONTINUES; 8136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 8146dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = asr->on_io(asr->io_opaque, asr, asr->state); 8156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (action == ASIO_ACTION_ABORT) { 816c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Read is aborted by the client.", _async_socket_string(as)); 8176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Move on to the next reader. */ 8186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine _async_socket_advance_reader(as); 8196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Lets see if there are still active readers, and enable, or disable 8206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * read I/O callback accordingly. */ 8216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (as->readers_head != NULL) { 8226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_wantRead(as->io); 8236dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 8246dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_dontWantRead(as->io); 8256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 826ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asr); 8276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return 0; 8286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 8296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 830a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Read next chunk of data. */ 831af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner int res = HANDLE_EINTR( 832af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner socket_recv(as->fd, 833af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner asr->buffer + asr->transferred, 834af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner asr->to_transfer - asr->transferred)); 835a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (res == 0) { 836a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Socket has been disconnected. */ 837a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine errno = ECONNRESET; 838a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _on_async_socket_disconnected(as); 839ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asr); 840a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return -1; 841a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 842a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 843a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (res < 0) { 844a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (errno == EWOULDBLOCK || errno == EAGAIN) { 845a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Yield to writes behind this read. */ 846a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_wantRead(as->io); 847ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asr); 848a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 849a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 850a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 851a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* An I/O error. */ 8526dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = _on_async_socket_failure(as, asr); 853c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine if (action != ASIO_ACTION_RETRY) { 854c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Read is aborted on failure.", _async_socket_string(as)); 8556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Move on to the next reader. */ 8566dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine _async_socket_advance_reader(as); 8576dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Lets see if there are still active readers, and enable, or disable 8586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * read I/O callback accordingly. */ 8596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (as->readers_head != NULL) { 8606dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_wantRead(as->io); 8616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 8626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_dontWantRead(as->io); 8636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 8646dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 865ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asr); 866a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return -1; 867a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 868a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 869a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Update the reader's descriptor. */ 870a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asr->transferred += res; 871a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (asr->transferred == asr->to_transfer) { 872a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* This read is completed. Move on to the next reader. */ 873a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_advance_reader(as); 874a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 875a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Notify reader completion. */ 876a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_complete_io(as, asr); 877a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 878a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 879a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Lets see if there are still active readers, and enable, or disable read 880a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O callback accordingly. */ 881a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as->readers_head != NULL) { 882a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_wantRead(as->io); 883a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 884a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantRead(as->io); 885a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 886a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 887ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asr); 888ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 889a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 890a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 891a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 892a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when there is data available to write. 893a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 894a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 895a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 896a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * 0 on success, or -1 on failure. Failure returned from this routine will 897a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * skip reads (if awailable) behind this write. 898a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 899a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int 900a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_send(AsyncSocket* as) 901a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 9026dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOAction action; 9036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 904a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Get current writer. */ 905a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asw = as->writers_head; 906a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (asw == NULL) { 907c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: No writer is available.", _async_socket_string(as)); 908a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantWrite(as->io); 909a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 910a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 911a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 912ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference the writer while we're working with it in this callback. */ 913ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_reference(asw); 914ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 9156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Bump I/O state, and inform the client that I/O is in progress. */ 9166dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (asw->state == ASIO_STATE_QUEUED) { 9176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asw->state = ASIO_STATE_STARTED; 9186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 9196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine asw->state = ASIO_STATE_CONTINUES; 9206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 9216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = asw->on_io(asw->io_opaque, asw, asw->state); 9226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (action == ASIO_ACTION_ABORT) { 923c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Write is aborted by the client.", _async_socket_string(as)); 924ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Move on to the next writer. */ 925ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_advance_writer(as); 9266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Lets see if there are still active writers, and enable, or disable 9276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * write I/O callback accordingly. */ 9286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (as->writers_head != NULL) { 9296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_wantWrite(as->io); 9306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 9316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_dontWantWrite(as->io); 9326dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 933ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asw); 9346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return 0; 9356dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 9366dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 937a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Write next chunk of data. */ 938af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner int res = HANDLE_EINTR( 939af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner socket_send(as->fd, 940af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner asw->buffer + asw->transferred, 941af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner asw->to_transfer - asw->transferred)); 942a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (res == 0) { 943a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Socket has been disconnected. */ 944a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine errno = ECONNRESET; 945a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _on_async_socket_disconnected(as); 946ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asw); 947a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return -1; 948a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 949a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 950a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (res < 0) { 951a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (errno == EWOULDBLOCK || errno == EAGAIN) { 952a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Yield to reads behind this write. */ 953a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_wantWrite(as->io); 954ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asw); 955a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 956a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 957a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 958a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* An I/O error. */ 9596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = _on_async_socket_failure(as, asw); 960c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine if (action != ASIO_ACTION_RETRY) { 961c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Write is aborted on failure.", _async_socket_string(as)); 962ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Move on to the next writer. */ 963ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_advance_writer(as); 9646dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Lets see if there are still active writers, and enable, or disable 9656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * write I/O callback accordingly. */ 9666dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (as->writers_head != NULL) { 9676dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_wantWrite(as->io); 9686dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 9696dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_dontWantWrite(as->io); 9706dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 9716dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } 972ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asw); 973a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return -1; 974a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 975a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 976ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Update the writer descriptor. */ 977a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine asw->transferred += res; 978a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (asw->transferred == asw->to_transfer) { 979a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* This write is completed. Move on to the next writer. */ 980a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_advance_writer(as); 981a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 982a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Notify writer completion. */ 983a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_complete_io(as, asw); 984a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 985a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 986a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Lets see if there are still active writers, and enable, or disable write 987a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O callback accordingly. */ 988a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as->writers_head != NULL) { 989a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_wantWrite(as->io); 990a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 991a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopIo_dontWantWrite(as->io); 992a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 993a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 994ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_io_release(asw); 995ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 996a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return 0; 997a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 998a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 999a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when an I/O is available on socket. 1000a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 1001a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 1002a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * fd - Socket's file descriptor. 1003a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * events - LOOP_IO_READ | LOOP_IO_WRITE bitmask. 1004a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 1005a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void 1006a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_io(void* opaque, int fd, unsigned events) 1007a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1008a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocket* const as = (AsyncSocket*)opaque; 1009a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1010ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference the socket while we're working with it in this callback. */ 1011ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_reference(as); 1012ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1013a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if ((events & LOOP_IO_READ) != 0) { 1014a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (_on_async_socket_recv(as) != 0) { 1015ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 1016a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return; 1017a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1018a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1019a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1020a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if ((events & LOOP_IO_WRITE) != 0) { 1021a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (_on_async_socket_send(as) != 0) { 1022ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 1023a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return; 1024a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1025a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1026ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1027ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 1028a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1029a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1030a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked by asynchronous socket connector on connection 1031a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * events. 1032a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 1033a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * opaque - Initialized AsyncSocket instance. 1034a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * connector - Connector that is used to connect this socket. 1035a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * event - Connection event. 1036a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return: 10376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * One of AsyncIOAction values. 1038a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 10396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction 1040a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_connector_events(void* opaque, 1041a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketConnector* connector, 10426dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOState event) 1043a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 10446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine AsyncIOAction action; 1045a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocket* const as = (AsyncSocket*)opaque; 1046a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1047ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference the socket while we're working with it in this callback. */ 1048ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_reference(as); 1049ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 10506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (event == ASIO_STATE_SUCCEEDED) { 10516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine /* Accept the connection. */ 10526dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine as->fd = async_socket_connector_pull_fd(connector); 10536dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as); 1054a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1055a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1056a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* Invoke client's callback. */ 10576dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine action = as->on_connection(as->client_opaque, as, event); 10586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (event == ASIO_STATE_SUCCEEDED && action != ASIO_ACTION_DONE) { 1059a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine /* For whatever reason the client didn't want to keep this connection. 1060a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Close it. */ 1061c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine D("ASocket %s: Connection is discarded by the client.", 1062c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as)); 1063a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_close_socket(as); 1064a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1065a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1066ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine if (action != ASIO_ACTION_RETRY) { 1067ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_connector_release(connector); 1068ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine } 1069ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1070ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 1071ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 10726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return action; 1073a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1074a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1075a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Timer callback invoked to reconnect the lost connection. 1076a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param: 1077a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * as - Initialized AsyncSocket instance. 1078a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */ 1079a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinevoid 1080a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_reconnect(void* opaque) 1081a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1082a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocket* as = (AsyncSocket*)opaque; 1083ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1084ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Reference the socket while we're working with it in this callback. */ 1085ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_reference(as); 1086a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine async_socket_connect(as, as->reconnect_to); 1087ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine async_socket_release(as); 1088a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1089a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1090a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1091a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/******************************************************************************** 1092a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Android Device Socket public API 1093a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/ 1094a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1095a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir ChtchetkineAsyncSocket* 1096a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_new(int port, 1097a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int reconnect_to, 10986dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_connection_cb client_cb, 1099c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine void* client_opaque, 1100c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine Looper* looper) 1101a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1102a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocket* as; 1103a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 11046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (client_cb == NULL) { 1105a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine E("Invalid client_cb parameter"); 1106a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return NULL; 1107a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1108a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1109a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine ANEW0(as); 1110a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1111a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine as->fd = -1; 1112a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine as->client_opaque = client_opaque; 11136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine as->on_connection = client_cb; 1114a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine as->readers_head = as->readers_tail = NULL; 1115a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine as->reconnect_to = reconnect_to; 1116ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine as->ref_count = 1; 1117a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine sock_address_init_inet(&as->address, SOCK_ADDRESS_INET_LOOPBACK, port); 1118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine if (looper == NULL) { 1119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine as->looper = looper_newCore(); 1120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine if (as->looper == NULL) { 1121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine E("Unable to create I/O looper for async socket '%s'", 1122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as)); 1123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine client_cb(client_opaque, as, ASIO_STATE_FAILED); 1124c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_free(as); 1125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine return NULL; 1126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine } 1127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine as->owns_looper = 1; 1128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine } else { 1129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine as->looper = looper; 1130c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine as->owns_looper = 0; 1131a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1133a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine loopTimer_init(as->reconnect_timer, as->looper, _on_async_socket_reconnect, as); 1134a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Descriptor is created.", _async_socket_string(as)); 1136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1137a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine return as; 1138a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1139a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1140ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint 1141ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_reference(AsyncSocket* as) 1142ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{ 1143ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine assert(as->ref_count > 0); 1144ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine as->ref_count++; 1145ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return as->ref_count; 1146ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine} 1147ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1148ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint 1149ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_release(AsyncSocket* as) 1150ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{ 1151ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine assert(as->ref_count > 0); 1152ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine as->ref_count--; 1153ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine if (as->ref_count == 0) { 1154ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine /* Last reference has been dropped. Destroy this object. */ 1155ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_cancel_all_io(as); 1156ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine _async_socket_free(as); 1157ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return 0; 1158ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine } 1159ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return as->ref_count; 1160ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine} 1161ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 11626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 1163a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_connect(AsyncSocket* as, int retry_to) 1164a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Handling connection request for %dms...", 1166c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), retry_to); 1167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1168a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketConnector* const connector = 1169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine async_socket_connector_new(&as->address, retry_to, _on_connector_events, 1170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine as, as->looper); 11716dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine if (connector != NULL) { 11726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine async_socket_connector_connect(connector); 11736dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine } else { 11746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED); 1175a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1176a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1177a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 1178a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinevoid 1179a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_disconnect(AsyncSocket* as) 1180a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Handling disconnection request...", _async_socket_string(as)); 1182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1183a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine if (as != NULL) { 1184a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_all_io(as); 1185a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_close_socket(as); 1186a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1187a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1188a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 11896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 1190a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_reconnect(AsyncSocket* as, int retry_to) 1191a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Handling reconnection request for %dms...", 1193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), retry_to); 1194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1195a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_cancel_all_io(as); 1196a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_close_socket(as); 1197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_reconnect(as, retry_to); 1198a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1199a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 12006dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 1201a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_read_abs(AsyncSocket* as, 1202a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* buffer, uint32_t len, 12036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb reader_cb, 1204a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* reader_opaque, 1205a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Duration deadline) 1206a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Handling read for %d bytes with deadline %lld...", 1208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), len, deadline); 1209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1210a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asr = 1211a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_reader_new(as, buffer, len, reader_cb, reader_opaque, 1212a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine deadline); 12137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine if (async_socket_is_connected(as)) { 12147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine /* Add new reader to the list. Note that we use initial reference from I/O 12157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * 'new' routine as "in the list" reference counter. */ 12167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine if (as->readers_head == NULL) { 12177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->readers_head = as->readers_tail = asr; 12187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine } else { 12197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->readers_tail->next = asr; 12207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->readers_tail = asr; 12217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine } 12227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine loopIo_wantRead(as->io); 1223a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 12247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine D("ASocket %s: Read on a disconnected socket.", _async_socket_string(as)); 12257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine errno = ECONNRESET; 12267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine reader_cb(reader_opaque, asr, ASIO_STATE_FAILED); 12277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine async_socket_io_release(asr); 1228a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1229a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1230a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 12316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 1232a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_read_rel(AsyncSocket* as, 1233a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* buffer, uint32_t len, 12346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb reader_cb, 1235a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* reader_opaque, 1236a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine int to) 1237a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1238a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to : 1239a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine DURATION_INFINITE; 12406dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl); 1241a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1242a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 12436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 1244a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_write_abs(AsyncSocket* as, 1245a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine const void* buffer, uint32_t len, 12466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb writer_cb, 1247a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine void* writer_opaque, 1248a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine Duration deadline) 1249a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine T("ASocket %s: Handling write for %d bytes with deadline %lld...", 1251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine _async_socket_string(as), len, deadline); 1252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine 1253a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine AsyncSocketIO* const asw = 1254a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine _async_socket_writer_new(as, buffer, len, writer_cb, writer_opaque, 1255a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine deadline); 12567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine if (async_socket_is_connected(as)) { 12577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine /* Add new writer to the list. Note that we use initial reference from I/O 12587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * 'new' routine as "in the list" reference counter. */ 12597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine if (as->writers_head == NULL) { 12607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->writers_head = as->writers_tail = asw; 12617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine } else { 12627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->writers_tail->next = asw; 12637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine as->writers_tail = asw; 12647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine } 12657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine loopIo_wantWrite(as->io); 1266a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } else { 12677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine D("ASocket %s: Write on a disconnected socket.", _async_socket_string(as)); 12687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine errno = ECONNRESET; 12697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine writer_cb(writer_opaque, asw, ASIO_STATE_FAILED); 12707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine async_socket_io_release(asw); 1271a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine } 1272a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1273a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine 12746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid 12756dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_write_rel(AsyncSocket* as, 12766dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine const void* buffer, uint32_t len, 12776dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine on_as_io_cb writer_cb, 12786dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine void* writer_opaque, 12796dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine int to) 1280a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{ 1281a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to : 1282a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine DURATION_INFINITE; 12836dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl); 12846dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 12856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 12866dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid* 12876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_get_client_opaque(const AsyncSocket* as) 12886dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 12896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return as->client_opaque; 12906dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine} 12916dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine 12926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir ChtchetkineDuration 12936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_deadline(AsyncSocket* as, int rel) 12946dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{ 12956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine return (rel >= 0) ? looper_now(_async_socket_get_looper(as)) + rel : 12966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine DURATION_INFINITE; 1297a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine} 1298ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine 1299ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint 1300ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_get_port(const AsyncSocket* as) 1301ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{ 1302ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine return sock_address_get_port(&as->address); 1303ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine} 13047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine 13057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint 13067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineasync_socket_is_connected(const AsyncSocket* as) 13077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{ 13087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine return as->fd >= 0; 13097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine} 1310