aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2012-04-02 07:48:19 -0700
committerVladimir Chtchetkine <vchtchetkine@google.com>2012-04-02 07:48:19 -0700
commit6dc5c2cef91004488f04fc6e9c0946f6d3a29705 (patch)
tree41fdf1c93fef544aea1a08a5066dbb3f26df6351
parenta7383ef4eb8d3863c8d582ea0d6b2ddb42125cba (diff)
downloadexternal_qemu-6dc5c2cef91004488f04fc6e9c0946f6d3a29705.zip
external_qemu-6dc5c2cef91004488f04fc6e9c0946f6d3a29705.tar.gz
external_qemu-6dc5c2cef91004488f04fc6e9c0946f6d3a29705.tar.bz2
Refactor asynchronous socket APIs
The initial implementation was a bit too complex in two ways: 1. Each component (the connector, and async socket) had its own set of state and action enums, which was confusing, required value translation, and was not really needed. So, all these enums have been combined into two common enums that are now declared in android/async-io-common.h 2. Too many callbacks, which really complicated implementation of the clients. It is much more efficient to have just two callbacks (one to monitor connection, and another to monitor I/O), letting the client to dispatch on particular event (success/timeout/etc.) This CL fixes these two issues. Change-Id: I545c93dee2e9e9c72c1d25e6cd218c8680933ee3
-rw-r--r--android/async-io-common.h61
-rw-r--r--android/async-socket-connector.c121
-rw-r--r--android/async-socket-connector.h107
-rw-r--r--android/async-socket.c402
-rw-r--r--android/async-socket.h273
5 files changed, 527 insertions, 437 deletions
diff --git a/android/async-io-common.h b/android/async-io-common.h
new file mode 100644
index 0000000..02714a7
--- /dev/null
+++ b/android/async-io-common.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ASYNC_IO_COMMON_H_
+#define ANDROID_ASYNC_IO_COMMON_H_
+
+/*
+ * Contains declarations common for asynchronous socket I/O
+ */
+
+/* Enumerates asynchronous I/O states.
+ * Values from this enum are passed to callbacks associated with an I/O,
+ * indicating at what state the I/O is. */
+typedef enum AsyncIOState {
+ /* Asynchronous I/O has been queued. (0) */
+ ASIO_STATE_QUEUED,
+ /* Asynchronous I/O has started. This state indicates that I/O has been
+ * performed for the first time. (1) */
+ ASIO_STATE_STARTED,
+ /* Asynchronous I/O is continuing. This state indicates that I/O has been
+ * invoked for the second (or more) time. (2) */
+ ASIO_STATE_CONTINUES,
+ /* Asynchronous I/O is about to be retried. (3) */
+ ASIO_STATE_RETRYING,
+ /* Asynchronous I/O has been successfuly completed. (4) */
+ ASIO_STATE_SUCCEEDED,
+ /* Asynchronous I/O has failed. (5) */
+ ASIO_STATE_FAILED,
+ /* Asynchronous I/O has timed out. (6) */
+ ASIO_STATE_TIMED_OUT,
+ /* Asynchronous I/O has been cancelled (due to disconnect, for
+ * instance). (7) */
+ ASIO_STATE_CANCELLED,
+} AsyncIOState;
+
+/* Enumerates actions to perform with an I/O on state transition.
+ * Values from this enum are returned from async I/O callbacks, indicating what
+ * action should be performed with the I/O by I/O handler. */
+typedef enum AsyncIOAction {
+ /* I/O is done. Perform default action depending on I/O type. */
+ ASIO_ACTION_DONE,
+ /* Abort the I/O. */
+ ASIO_ACTION_ABORT,
+ /* Retry the I/O. */
+ ASIO_ACTION_RETRY,
+} AsyncIOAction;
+
+#endif /* ANDROID_ASYNC_IO_COMMON_H_ */
diff --git a/android/async-socket-connector.c b/android/async-socket-connector.c
index daf6a37..41a13e0 100644
--- a/android/async-socket-connector.c
+++ b/android/async-socket-connector.c
@@ -47,7 +47,7 @@ struct AsyncSocketConnector {
LoopTimer connector_timer[1];
/* Asynchronous connector to the socket. */
AsyncConnector connector[1];
- /* Callback to invoke on connection / connection error. */
+ /* Callback to invoke on connection events. */
asc_event_cb on_connected_cb;
/* An opaque parameter to pass to the connection callback. */
void* on_connected_cb_opaque;
@@ -106,8 +106,8 @@ _async_socket_connector_open_socket(AsyncSocketConnector* connector)
/* Open socket. */
connector->fd = socket_create_inet(SOCKET_STREAM);
if (connector->fd < 0) {
- D("Unable to create connector socket for %s. Error: %s",
- _asc_socket_string(connector), strerror(errno));
+ D("Unable to create AsyncSocketConnector socket for '%s'. Error: %d -> %s",
+ _asc_socket_string(connector), errno, strerror(errno));
return -1;
}
@@ -148,45 +148,38 @@ static void
_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
AsyncStatus status)
{
- ASCCbRes action;
- int do_retry = 0;
+ AsyncIOAction action = ASIO_ACTION_DONE;
switch (status) {
case ASYNC_COMPLETE:
loopIo_done(connector->connector_io);
- D("Socket %s is connected", _asc_socket_string(connector));
+ D("Socket '%s' is connected", _asc_socket_string(connector));
/* Invoke "on connected" callback */
action = connector->on_connected_cb(connector->on_connected_cb_opaque,
- connector, ASC_CONNECTION_SUCCEEDED);
- if (action == ASC_CB_RETRY) {
- do_retry = 1;
- } else if (action == ASC_CB_ABORT) {
- _async_socket_connector_close_socket(connector);
- }
+ connector, ASIO_STATE_SUCCEEDED);
break;
case ASYNC_ERROR:
loopIo_done(connector->connector_io);
- D("Error %d while connecting to socket %s: %s",
- errno, _asc_socket_string(connector), strerror(errno));
+ D("Error while connecting to socket '%s': %d -> %s",
+ _asc_socket_string(connector), errno, strerror(errno));
/* Invoke "on connected" callback */
action = connector->on_connected_cb(connector->on_connected_cb_opaque,
- connector, ASC_CONNECTION_FAILED);
- if (action == ASC_CB_RETRY) {
- do_retry = 1;
- } else if (action == ASC_CB_ABORT) {
- _async_socket_connector_close_socket(connector);
- }
+ connector, ASIO_STATE_FAILED);
break;
case ASYNC_NEED_MORE:
return;
}
- if (do_retry) {
- D("Retrying connection to socket %s", _asc_socket_string(connector));
+ if (action == ASIO_ACTION_RETRY) {
+ D("Retrying connection to socket '%s'", _asc_socket_string(connector));
loopTimer_startRelative(connector->connector_timer, connector->retry_to);
} else {
+ if (action == ASIO_ACTION_ABORT) {
+ D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
+ __FUNCTION__, _asc_socket_string(connector));
+ }
_async_socket_connector_free(connector);
}
}
@@ -196,9 +189,19 @@ _on_async_socket_connector_io(void* opaque, int fd, unsigned events)
{
AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
- /* Complete socket connection. */
- const AsyncStatus status = asyncConnector_run(connector->connector);
- _on_async_socket_connector_connecting(connector, status);
+ /* Notify the client that another connection attempt is about to start. */
+ const AsyncIOAction action =
+ connector->on_connected_cb(connector->on_connected_cb_opaque,
+ connector, ASIO_STATE_CONTINUES);
+ if (action != ASIO_ACTION_ABORT) {
+ /* Complete socket connection. */
+ const AsyncStatus status = asyncConnector_run(connector->connector);
+ _on_async_socket_connector_connecting(connector, status);
+ } else {
+ D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
+ __FUNCTION__, _asc_socket_string(connector));
+ _async_socket_connector_free(connector);
+ }
}
/* Retry connection timer callback.
@@ -208,31 +211,33 @@ _on_async_socket_connector_io(void* opaque, int fd, unsigned events)
static void
_on_async_socket_connector_retry(void* opaque)
{
+ AsyncStatus status;
AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
/* Invoke the callback to notify about a connection retry attempt. */
- const ASCCbRes action =
+ AsyncIOAction action =
connector->on_connected_cb(connector->on_connected_cb_opaque,
- connector, ASC_CONNECTION_RETRY);
-
- if (action == ASC_CB_RETRY) {
- AsyncStatus status;
+ connector, ASIO_STATE_RETRYING);
- /* Close handle opened for the previous (failed) attempt. */
- _async_socket_connector_close_socket(connector);
+ if (action == ASIO_ACTION_ABORT) {
+ D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
+ __FUNCTION__, _asc_socket_string(connector));
+ _async_socket_connector_free(connector);
+ return;
+ }
- /* Retry connection attempt. */
- if (_async_socket_connector_open_socket(connector) == 0) {
- status = asyncConnector_init(connector->connector, &connector->address,
- connector->connector_io);
- } else {
- status = ASYNC_ERROR;
- }
+ /* Close handle opened for the previous (failed) attempt. */
+ _async_socket_connector_close_socket(connector);
- _on_async_socket_connector_connecting(connector, status);
+ /* Retry connection attempt. */
+ if (_async_socket_connector_open_socket(connector) == 0) {
+ status = asyncConnector_init(connector->connector, &connector->address,
+ connector->connector_io);
} else {
- _async_socket_connector_free(connector);
+ status = ASYNC_ERROR;
}
+
+ _on_async_socket_connector_connecting(connector, status);
}
/********************************************************************************
@@ -248,7 +253,7 @@ async_socket_connector_new(const SockAddress* address,
AsyncSocketConnector* connector;
if (cb == NULL) {
- W("No callback for AsyncSocketConnector for %s",
+ W("No callback for AsyncSocketConnector for socket '%s'",
sock_address_to_string(address));
errno = EINVAL;
return NULL;
@@ -275,8 +280,9 @@ async_socket_connector_new(const SockAddress* address,
loopTimer_init(connector->connector_timer, connector->looper,
_on_async_socket_connector_retry, connector);
} else {
- E("Unable to create I/O looper for asynchronous connector to socket %s",
+ E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'",
_asc_socket_string(connector));
+ cb(cb_opaque, connector, ASIO_STATE_FAILED);
_async_socket_connector_free(connector);
return NULL;
}
@@ -284,31 +290,30 @@ async_socket_connector_new(const SockAddress* address,
return connector;
}
-ASCConnectRes
+void
async_socket_connector_connect(AsyncSocketConnector* connector)
{
AsyncStatus status;
if (_async_socket_connector_open_socket(connector) == 0) {
- status = asyncConnector_init(connector->connector, &connector->address,
- connector->connector_io);
+ const AsyncIOAction action =
+ connector->on_connected_cb(connector->on_connected_cb_opaque,
+ connector, ASIO_STATE_STARTED);
+ if (action == ASIO_ACTION_ABORT) {
+ D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
+ __FUNCTION__, _asc_socket_string(connector));
+ _async_socket_connector_free(connector);
+ return;
+ } else {
+ status = asyncConnector_init(connector->connector,
+ &connector->address,
+ connector->connector_io);
+ }
} else {
status = ASYNC_ERROR;
}
_on_async_socket_connector_connecting(connector, status);
-
- switch (status) {
- case ASYNC_COMPLETE:
- return ASC_CONNECT_SUCCEEDED;
-
- case ASYNC_ERROR:
- return ASC_CONNECT_FAILED;
-
- case ASYNC_NEED_MORE:
- default:
- return ASC_CONNECT_IN_PROGRESS;
- }
}
int
diff --git a/android/async-socket-connector.h b/android/async-socket-connector.h
index 998d0c8..4c05059 100644
--- a/android/async-socket-connector.h
+++ b/android/async-socket-connector.h
@@ -17,15 +17,17 @@
#ifndef ANDROID_ASYNC_SOCKET_CONNECTOR_H_
#define ANDROID_ASYNC_SOCKET_CONNECTOR_H_
+#include "android/async-io-common.h"
+
/*
* Contains declaration of an API that allows asynchronous connection to a
* socket with retries.
*
* The typical usage of this API is as such:
*
- * 1. The client creates an async connector instance by calling async_socket_connector_new
- * routine, supplying there address of the socket to connect, and a callback
- * to invoke on connection events.
+ * 1. The client creates an asynchronous connector instance by calling
+ * async_socket_connector_new routine, supplying there address of the socket
+ * to connect, and a callback to invoke on connection events.
* 2. The client then proceeds with calling async_socket_connector_connect that
* would initiate connection attempts.
*
@@ -38,94 +40,58 @@
* 2. Failure.
* 3. Retry.
*
- * Typically, when client's callback is called for successful connection, the
+ * Typically, when client's callback is called for a successful connection, the
* client will pull connected socket's FD from the connector, and then this FD
- * will be used by the client for I/O on the connected socket. If socket's FD
- * is pulled by the client, it must return ASC_CB_KEEP from the callback.
+ * will be used by the client for I/O on the connected socket.
*
- * When client's callback is invoked with an error (ASC_CONNECTION_FAILED event),
- * the client has an opportunity to review the error (available in 'errno'), and
- * either abort the connection by returning ASC_CB_ABORT, or schedule a retry
- * by returning ASC_CB_RETRY from the callback. If client returns ASC_CB_ABORT
+ * When client's callback is invoked with an error (ASIO_STATE_FAILED event), the
+ * client has an opportunity to review the error (available in 'errno'), and
+ * either abort the connection by returning ASIO_ACTION_ABORT, or schedule a retry
+ * by returning ASIO_ACTION_RETRY from the callback. If client returns ASIO_ACTION_ABORT
* from the callback, the connector will stop connection attempts, and will
- * self-destruct. If ASC_CB_RETRY is returned from the callback, the connector
+ * self-destruct. If ASIO_ACTION_RETRY is returned from the callback, the connector
* will retry connection attempt after timeout that was set by the caller in the
* call to async_socket_connector_new routine.
*
- * When client's callback is invoked with ASC_CONNECTION_RETRY, the client has an
- * opportunity to cancel further connection attempts by returning ASC_CB_ABORT,
- * or it can allow another connection attempt by returning ASC_CB_RETRY.
+ * When client's callback is invoked with ASIO_STATE_RETRYING (indicating that
+ * connector is about to retry a connection attempt), the client has an opportunity
+ * to cancel further connection attempts by returning ASIO_ACTION_ABORT, or it
+ * can allow another connection attempt by returning ASIO_ACTION_RETRY.
*
* The client has no control over the lifespan of initialized connector instance.
* It always self-destructs after client's cllback returns with a status other
- * than ASC_CB_RETRY.
+ * than ASIO_ACTION_RETRY.
*/
/* Declares async socket connector descriptor. */
typedef struct AsyncSocketConnector AsyncSocketConnector;
-/* Enumerates connection events.
- * Values from this enum are passed to the callback that connector's client uses
- * to monitor connection status / progress.
- */
-typedef enum ASCEvent {
- /* Connection with the socket has been successfuly established. */
- ASC_CONNECTION_SUCCEEDED,
- /* A failure has occured while establising connection, with errno containing
- * the actual error. */
- ASC_CONNECTION_FAILED,
- /* Async socket connector is about to retry the connection. */
- ASC_CONNECTION_RETRY,
-} ASCEvent;
-
-/* Enumerates return values from the callback to the connector's client.
- */
-typedef enum ASCCbRes {
- /* Keep established connection. */
- ASC_CB_KEEP,
- /* Abort connection attempts. */
- ASC_CB_ABORT,
- /* Retry connection attempt. */
- ASC_CB_RETRY,
-} ASCCbRes;
-
-/* Enumerates values returned from the connector routine.
- */
-typedef enum ASCConnectRes {
- /* Connection has succeeded in the connector routine. */
- ASC_CONNECT_SUCCEEDED,
- /* Connection has failed in the connector routine. */
- ASC_CONNECT_FAILED,
- /* Connection is in progress, and will be completed asynchronously. */
- ASC_CONNECT_IN_PROGRESS,
-} ASCConnectRes;
-
/* Declares callback that connector's client uses to monitor connection
* status / progress.
* Param:
* opaque - An opaque pointer associated with the client.
- * connector - Connector instance for thecallback.
- * event - Event that has occured. If event is set to ASC_CONNECTION_FAILED,
+ * connector - AsyncSocketConnector instance.
+ * event - Event that has occurred. If event is set to ASIO_STATE_FAILED,
* errno contains connection error.
* Return:
- * One of ASCCbRes values.
+ * One of AsyncIOAction values.
*/
-typedef ASCCbRes (*asc_event_cb)(void* opaque,
- AsyncSocketConnector* connector,
- ASCEvent event);
+typedef AsyncIOAction (*asc_event_cb)(void* opaque,
+ AsyncSocketConnector* connector,
+ AsyncIOState event);
/* Creates and initializes AsyncSocketConnector instance.
* Param:
* address - Initialized socket address to connect to.
- * retry_to - Retry timeout in milliseconds.
+ * retry_to - Timeout to retry a failed connection attempt in milliseconds.
* cb, cb_opaque - Callback to invoke on connection events. This callback is
* required, and must not be NULL.
* Return:
* Initialized AsyncSocketConnector instance. Note that AsyncSocketConnector
* instance returned from this routine will be destroyed by the connector itself,
- * when its work on connecting to the socket is completed. Typically, the
- * connector wil destroy the descriptor after client's callback routine returns
- * with the status other than ASC_CB_RETRY.
+ * when its work on connecting to the socket is completed. Typically, connector
+ * will destroy its descriptor after client's callback routine returns with a
+ * status other than ASIO_ACTION_RETRY.
*/
extern AsyncSocketConnector* async_socket_connector_new(const SockAddress* address,
int retry_to,
@@ -133,21 +99,20 @@ extern AsyncSocketConnector* async_socket_connector_new(const SockAddress* addre
void* cb_opaque);
/* Initiates asynchronous connection.
+ * Note that connection result will be reported via callback set with the call to
+ * async_socket_connector_new routine.
* Param:
- * connector - Initialized AsyncSocketConnector instance.
- * Return:
- * Status indicating state of the connection: completed, failed, or in progress.
- * Note that the connector will always invoke a callback passed to the
- * async_socket_connector_new routine prior to exiting from this routine with
- * statuses other ASC_CONNECT_IN_PROGRESS.
+ * connector - Initialized AsyncSocketConnector instance. Note that this
+ * connector descriptor might be destroyed asynchronously, before this
+ * routine returns.
*/
-extern ASCConnectRes async_socket_connector_connect(AsyncSocketConnector* connector);
+extern void async_socket_connector_connect(AsyncSocketConnector* connector);
/* Pulls socket's file descriptor from the connector.
* This routine should be called from the connection callback on successful
- * connection status. This will provide the connector's client with operational
- * socket FD, and at the same time this will tell the connector not to close
- * the FD when connector descriptor gets destroyed.
+ * connection status. This will provide the connector's client with an operational
+ * socket FD, and at the same time this will tell the connector not to close the
+ * FD when connector descriptor gets destroyed.
* Param:
* connector - Initialized AsyncSocketConnector instance.
* Return:
diff --git a/android/async-socket.c b/android/async-socket.c
index 13e15ca..4be69f6 100644
--- a/android/async-socket.c
+++ b/android/async-socket.c
@@ -37,9 +37,6 @@
* Asynchronous Socket internal API declarations
*******************************************************************************/
-/* Asynchronous socket I/O (reader, or writer) descriptor. */
-typedef struct AsyncSocketIO AsyncSocketIO;
-
/* Gets socket's address string. */
static const char* _async_socket_string(AsyncSocket* as);
@@ -48,10 +45,11 @@ static Looper* _async_socket_get_looper(AsyncSocket* as);
/* Handler for the I/O time out.
* Param:
- * as - Asynchronous socket for the reader.
+ * as - Asynchronous socket for the I/O.
* asio - Desciptor for the timed out I/O.
*/
-static void _async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio);
+static AsyncIOAction _async_socket_io_timed_out(AsyncSocket* as,
+ AsyncSocketIO* asio);
/********************************************************************************
* Asynchronous Socket Reader / Writer
@@ -72,10 +70,12 @@ struct AsyncSocketIO {
uint32_t to_transfer;
/* Bytes thransferred through the socket in this I/O. */
uint32_t transferred;
- /* I/O callbacks for this I/O. */
- const ASIOCb* io_cb;
+ /* I/O callback for this I/O. */
+ on_as_io_cb on_io;
/* I/O type selector: 1 - read, 0 - write. */
int is_io_read;
+ /* State of the I/O. */
+ AsyncIOState state;
};
/*
@@ -105,7 +105,7 @@ static void _on_async_socket_io_timed_out(void* opaque);
* as - Asynchronous socket for the I/O.
* is_io_read - I/O type selector: 1 - read, 0 - write.
* buffer, len - Reader / writer buffer address.
- * io_cb - Callbacks for this reader / writer.
+ * io_cb - Callback for this reader / writer.
* io_opaque - An opaque pointer associated with the I/O.
* deadline - Deadline to complete the I/O.
* Return:
@@ -116,7 +116,7 @@ _async_socket_rw_new(AsyncSocket* as,
int is_io_read,
void* buffer,
uint32_t len,
- const ASIOCb* io_cb,
+ on_as_io_cb io_cb,
void* io_opaque,
Duration deadline)
{
@@ -137,8 +137,9 @@ _async_socket_rw_new(AsyncSocket* as,
asio->buffer = (uint8_t*)buffer;
asio->to_transfer = len;
asio->transferred = 0;
- asio->io_cb = io_cb;
+ asio->on_io = io_cb;
asio->io_opaque = io_opaque;
+ asio->state = ASIO_STATE_QUEUED;
loopTimer_init(asio->timer, _async_socket_get_looper(as),
_on_async_socket_io_timed_out, asio);
@@ -168,7 +169,7 @@ _async_socket_io_destroy(AsyncSocketIO* asio)
* Param:
* as - Asynchronous socket for the reader.
* buffer, len - Reader's buffer.
- * io_cb - Lists reader's callbacks.
+ * io_cb - Reader's callback.
* reader_opaque - An opaque pointer associated with the reader.
* deadline - Deadline to complete the operation.
* Return:
@@ -178,7 +179,7 @@ static AsyncSocketIO*
_async_socket_reader_new(AsyncSocket* as,
void* buffer,
uint32_t len,
- const ASIOCb* io_cb,
+ on_as_io_cb io_cb,
void* reader_opaque,
Duration deadline)
{
@@ -191,7 +192,7 @@ _async_socket_reader_new(AsyncSocket* as,
* Param:
* as - Asynchronous socket for the writer.
* buffer, len - Writer's buffer.
- * io_cb - Lists writer's callbacks.
+ * io_cb - Writer's callback.
* writer_opaque - An opaque pointer associated with the writer.
* deadline - Deadline to complete the operation.
* Return:
@@ -201,7 +202,7 @@ static AsyncSocketIO*
_async_socket_writer_new(AsyncSocket* as,
const void* buffer,
uint32_t len,
- const ASIOCb* io_cb,
+ on_as_io_cb io_cb,
void* writer_opaque,
Duration deadline)
{
@@ -216,8 +217,76 @@ static void
_on_async_socket_io_timed_out(void* opaque)
{
AsyncSocketIO* const asio = (AsyncSocketIO*)opaque;
- _async_socket_io_timed_out(asio->as, asio);
- _async_socket_io_destroy(asio);
+ const AsyncIOAction action = _async_socket_io_timed_out(asio->as, asio);
+ if (action != ASIO_ACTION_RETRY) {
+ _async_socket_io_destroy(asio);
+ }
+}
+
+/********************************************************************************
+ * Public Asynchronous Socket I/O API
+ *******************************************************************************/
+
+AsyncSocket*
+async_socket_io_get_socket(const AsyncSocketIO* asio)
+{
+ return asio->as;
+}
+
+void
+async_socket_io_cancel_time_out(AsyncSocketIO* asio)
+{
+ loopTimer_stop(asio->timer);
+}
+
+void*
+async_socket_io_get_io_opaque(const AsyncSocketIO* asio)
+{
+ return asio->io_opaque;
+}
+
+void*
+async_socket_io_get_client_opaque(const AsyncSocketIO* asio)
+{
+ return async_socket_get_client_opaque(asio->as);
+}
+
+void*
+async_socket_io_get_buffer_info(const AsyncSocketIO* asio,
+ uint32_t* transferred,
+ uint32_t* to_transfer)
+{
+ if (transferred != NULL) {
+ *transferred = asio->transferred;
+ }
+ if (to_transfer != NULL) {
+ *to_transfer = asio->to_transfer;
+ }
+ return asio->buffer;
+}
+
+void*
+async_socket_io_get_buffer(const AsyncSocketIO* asio)
+{
+ return asio->buffer;
+}
+
+uint32_t
+async_socket_io_get_transferred(const AsyncSocketIO* asio)
+{
+ return asio->transferred;
+}
+
+uint32_t
+async_socket_io_get_to_transfer(const AsyncSocketIO* asio)
+{
+ return asio->to_transfer;
+}
+
+int
+async_socket_io_is_read(const AsyncSocketIO* asio)
+{
+ return asio->is_io_read;
}
/********************************************************************************
@@ -227,8 +296,8 @@ _on_async_socket_io_timed_out(void* opaque)
struct AsyncSocket {
/* TCP address for the socket. */
SockAddress address;
- /* Client callbacks for this socket. */
- const ASClientCb* client_cb;
+ /* Connection callback for this socket. */
+ on_as_connection_cb on_connection;
/* An opaque pointer associated with this socket by the client. */
void* client_opaque;
/* I/O looper for asynchronous I/O on the socket. */
@@ -353,7 +422,7 @@ _async_socket_remove_io(AsyncSocket* as,
* as - Initialized AsyncSocket instance.
* list_head, list_tail - Pointers to the list head and tail.
* Return:
- * Next I/O at the head of the list, or NULL if I/O list become empty.
+ * Next I/O at the head of the list, or NULL if I/O list became empty.
*/
static AsyncSocketIO*
_async_socket_advance_io(AsyncSocket* as,
@@ -375,7 +444,7 @@ _async_socket_advance_io(AsyncSocket* as,
* Param:
* as - Initialized AsyncSocket instance.
* Return:
- * Next reader at the head of the list, or NULL if reader list become empty.
+ * Next reader at the head of the list, or NULL if reader list became empty.
*/
static AsyncSocketIO*
_async_socket_advance_reader(AsyncSocket* as)
@@ -387,7 +456,7 @@ _async_socket_advance_reader(AsyncSocket* as)
* Param:
* as - Initialized AsyncSocket instance.
* Return:
- * Next writer at the head of the list, or NULL if writer list become empty.
+ * Next writer at the head of the list, or NULL if writer list became empty.
*/
static AsyncSocketIO*
_async_socket_advance_writer(AsyncSocket* as)
@@ -399,75 +468,58 @@ _async_socket_advance_writer(AsyncSocket* as)
* Param:
* as - Initialized AsyncSocket instance.
* asio - I/O to complete.
+ * Return:
+ * One of AsyncIOAction values.
*/
-static void
+static AsyncIOAction
_async_socket_complete_io(AsyncSocket* as, AsyncSocketIO* asio)
{
/* Stop the timer. */
loopTimer_stop(asio->timer);
- /* Report I/O completion. First report via I/O callback, and only if it is
- * not set, report via client callback. */
- if (asio->io_cb && asio->io_cb->on_completed) {
- asio->io_cb->on_completed(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer, asio->transferred);
- } else if (as->client_cb->io_cb && as->client_cb->io_cb->on_completed) {
- as->client_cb->io_cb->on_completed(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred);
- }
+ return asio->on_io(asio->io_opaque, asio, ASIO_STATE_SUCCEEDED);
}
/* Timeouts an I/O.
* Param:
* as - Initialized AsyncSocket instance.
* asio - An I/O that has timed out.
+ * Return:
+ * One of AsyncIOAction values.
*/
-static void
+static AsyncIOAction
_async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio)
{
- /* Remove the I/O from a list of active I/O. */
- if (asio->is_io_read) {
- _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio);
- } else {
- _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio);
+ /* Report to the client. */
+ const AsyncIOAction action = asio->on_io(asio->io_opaque, asio,
+ ASIO_STATE_TIMED_OUT);
+
+ /* Remove the I/O from a list of active I/O for actions other than retry. */
+ if (action != ASIO_ACTION_RETRY) {
+ if (asio->is_io_read) {
+ _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio);
+ } else {
+ _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio);
+ }
}
- /* Report I/O time out. First report it via I/O callbacks, and only if it is
- * not set, report it via client callbacks. */
- if (asio->io_cb && asio->io_cb->on_timed_out) {
- asio->io_cb->on_timed_out(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred, asio->to_transfer);
- } else if (as->client_cb->io_cb && as->client_cb->io_cb->on_timed_out) {
- as->client_cb->io_cb->on_timed_out(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred, asio->to_transfer);
- }
+ return action;
}
/* Cancels an I/O.
* Param:
* as - Initialized AsyncSocket instance.
* asio - An I/O to cancel.
+ * Return:
+ * One of AsyncIOAction values.
*/
-static void
+static AsyncIOAction
_async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio)
{
/* Stop the timer. */
loopTimer_stop(asio->timer);
- /* Report I/O cancellation. First report it via I/O callbacks, and only if it
- * is not set, report it via client callbacks. */
- if (asio->io_cb && asio->io_cb->on_cancelled) {
- asio->io_cb->on_cancelled(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred, asio->to_transfer);
- } else if (as->client_cb->io_cb && as->client_cb->io_cb->on_cancelled) {
- as->client_cb->io_cb->on_cancelled(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred, asio->to_transfer);
- }
+ return asio->on_io(asio->io_opaque, asio, ASIO_STATE_CANCELLED);
}
/* Reports an I/O failure.
@@ -475,25 +527,17 @@ _async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio)
* as - Initialized AsyncSocket instance.
* asio - An I/O that has failed. Can be NULL for general failures.
* failure - Failure (errno) that has occurred.
+ * Return:
+ * One of AsyncIOAction values.
*/
-static void
+static AsyncIOAction
_async_socket_io_failure(AsyncSocket* as, AsyncSocketIO* asio, int failure)
{
/* Stop the timer. */
loopTimer_stop(asio->timer);
- /* Report I/O failure. First report it via I/O callbacks, and only if it
- * is not set, report it via client callbacks. */
- if (asio && asio->io_cb && asio->io_cb->on_io_failure) {
- asio->io_cb->on_io_failure(as->client_opaque, as, asio->is_io_read,
- asio->io_opaque, asio->buffer,
- asio->transferred, asio->to_transfer, failure);
- } else if (as->client_cb->io_cb && as->client_cb->io_cb->on_io_failure) {
- as->client_cb->io_cb->on_io_failure(as->client_opaque, as,
- asio->is_io_read, asio->io_opaque,
- asio->buffer, asio->transferred,
- asio->to_transfer, failure);
- }
+ errno = failure;
+ return asio->on_io(asio->io_opaque, asio, ASIO_STATE_FAILED);
}
/* Cancels all the active socket readers.
@@ -505,6 +549,8 @@ _async_socket_cancel_readers(AsyncSocket* as)
{
while (as->readers_head != NULL) {
AsyncSocketIO* const to_cancel = _async_socket_pull_first_reader(as);
+ /* We ignore action returned from the cancellation callback, since we're
+ * in a disconnected state here. */
_async_socket_cancel_io(as, to_cancel);
_async_socket_io_destroy(to_cancel);
}
@@ -519,6 +565,8 @@ _async_socket_cancel_writers(AsyncSocket* as)
{
while (as->writers_head != NULL) {
AsyncSocketIO* const to_cancel = _async_socket_pull_first_writer(as);
+ /* We ignore action returned from the cancellation callback, since we're
+ * in a disconnected state here. */
_async_socket_cancel_io(as, to_cancel);
_async_socket_io_destroy(to_cancel);
}
@@ -607,7 +655,7 @@ _on_async_socket_disconnected(AsyncSocket* as)
{
/* Save error to restore it for the client's callback. */
const int save_errno = errno;
- ASConnectAction action = ASCA_ABORT;
+ AsyncIOAction action = ASIO_ACTION_ABORT;
D("Async socket '%s' is disconnected. Error %d -> %s",
_async_socket_string(as), errno, strerror(errno));
@@ -620,14 +668,11 @@ _on_async_socket_disconnected(AsyncSocket* as)
/* Restore errno, and invoke client's callback. */
errno = save_errno;
- action = as->client_cb->on_connection(as->client_opaque, as,
- ASCS_DISCONNECTED);
+ action = as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
- if (action == ASCA_RETRY) {
+ if (action == ASIO_ACTION_RETRY) {
/* Client requested reconnection. */
- if (as->reconnect_to) {
- _async_socket_reconnect(as, as->reconnect_to);
- }
+ _async_socket_reconnect(as, as->reconnect_to);
}
}
@@ -636,14 +681,14 @@ _on_async_socket_disconnected(AsyncSocket* as)
* as - Initialized AsyncSocket instance.
* asio - Descriptor for the failed I/O. Can be NULL for general failures.
*/
-static void
+static AsyncIOAction
_on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio)
{
- D("Async socket '%s' I/O failure %d: %s",
+ D("Async socket '%s' I/O failure: %d -> %s",
_async_socket_string(as), errno, strerror(errno));
/* Report the failure. */
- _async_socket_io_failure(as, asio, errno);
+ return _async_socket_io_failure(as, asio, errno);
}
/* A callback that is invoked when there is data available to read.
@@ -656,6 +701,8 @@ _on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio)
static int
_on_async_socket_recv(AsyncSocket* as)
{
+ AsyncIOAction action;
+
/* Get current reader. */
AsyncSocketIO* const asr = as->readers_head;
if (asr == NULL) {
@@ -665,6 +712,29 @@ _on_async_socket_recv(AsyncSocket* as)
return 0;
}
+ /* Bump I/O state, and inform the client that I/O is in progress. */
+ if (asr->state == ASIO_STATE_QUEUED) {
+ asr->state = ASIO_STATE_STARTED;
+ } else {
+ asr->state = ASIO_STATE_CONTINUES;
+ }
+ action = asr->on_io(asr->io_opaque, asr, asr->state);
+ if (action == ASIO_ACTION_ABORT) {
+ D("Read is aborted by the client of async socket '%s'",
+ _async_socket_string(as));
+ /* Move on to the next reader. */
+ _async_socket_advance_reader(as);
+ _async_socket_io_destroy(asr);
+ /* Lets see if there are still active readers, and enable, or disable
+ * read I/O callback accordingly. */
+ if (as->readers_head != NULL) {
+ loopIo_wantRead(as->io);
+ } else {
+ loopIo_dontWantRead(as->io);
+ }
+ return 0;
+ }
+
/* Read next chunk of data. */
int res = socket_recv(as->fd, asr->buffer + asr->transferred,
asr->to_transfer - asr->transferred);
@@ -688,7 +758,21 @@ _on_async_socket_recv(AsyncSocket* as)
}
/* An I/O error. */
- _on_async_socket_failure(as, asr);
+ action = _on_async_socket_failure(as, asr);
+ if (action == ASIO_ACTION_ABORT) {
+ D("Read is aborted on failure by the client of async socket '%s'",
+ _async_socket_string(as));
+ /* Move on to the next reader. */
+ _async_socket_advance_reader(as);
+ _async_socket_io_destroy(asr);
+ /* Lets see if there are still active readers, and enable, or disable
+ * read I/O callback accordingly. */
+ if (as->readers_head != NULL) {
+ loopIo_wantRead(as->io);
+ } else {
+ loopIo_dontWantRead(as->io);
+ }
+ }
return -1;
}
@@ -724,6 +808,8 @@ _on_async_socket_recv(AsyncSocket* as)
static int
_on_async_socket_send(AsyncSocket* as)
{
+ AsyncIOAction action;
+
/* Get current writer. */
AsyncSocketIO* const asw = as->writers_head;
if (asw == NULL) {
@@ -733,6 +819,29 @@ _on_async_socket_send(AsyncSocket* as)
return 0;
}
+ /* Bump I/O state, and inform the client that I/O is in progress. */
+ if (asw->state == ASIO_STATE_QUEUED) {
+ asw->state = ASIO_STATE_STARTED;
+ } else {
+ asw->state = ASIO_STATE_CONTINUES;
+ }
+ action = asw->on_io(asw->io_opaque, asw, asw->state);
+ if (action == ASIO_ACTION_ABORT) {
+ D("Write is aborted by the client of async socket '%s'",
+ _async_socket_string(as));
+ /* Move on to the next reader. */
+ _async_socket_advance_reader(as);
+ _async_socket_io_destroy(asw);
+ /* Lets see if there are still active writers, and enable, or disable
+ * write I/O callback accordingly. */
+ if (as->writers_head != NULL) {
+ loopIo_wantWrite(as->io);
+ } else {
+ loopIo_dontWantWrite(as->io);
+ }
+ return 0;
+ }
+
/* Write next chunk of data. */
int res = socket_send(as->fd, asw->buffer + asw->transferred,
asw->to_transfer - asw->transferred);
@@ -756,7 +865,22 @@ _on_async_socket_send(AsyncSocket* as)
}
/* An I/O error. */
- _on_async_socket_failure(as, asw);
+ /* An I/O error. */
+ action = _on_async_socket_failure(as, asw);
+ if (action == ASIO_ACTION_ABORT) {
+ D("Write is aborted on failure by the client of async socket '%s'",
+ _async_socket_string(as));
+ /* Move on to the next reader. */
+ _async_socket_advance_reader(as);
+ _async_socket_io_destroy(asw);
+ /* Lets see if there are still active writers, and enable, or disable
+ * write I/O callback accordingly. */
+ if (as->writers_head != NULL) {
+ loopIo_wantWrite(as->io);
+ } else {
+ loopIo_dontWantWrite(as->io);
+ }
+ }
return -1;
}
@@ -813,51 +937,33 @@ _on_async_socket_io(void* opaque, int fd, unsigned events)
* connector - Connector that is used to connect this socket.
* event - Connection event.
* Return:
- * One of ASCCbRes values.
+ * One of AsyncIOAction values.
*/
-static ASCCbRes
+static AsyncIOAction
_on_connector_events(void* opaque,
AsyncSocketConnector* connector,
- ASCEvent event)
+ AsyncIOState event)
{
- ASConnectAction action;
- ASConnectStatus adsc_status;
+ AsyncIOAction action;
AsyncSocket* const as = (AsyncSocket*)opaque;
- /* Convert connector event into async socket connection event. */
- switch (event) {
- case ASC_CONNECTION_SUCCEEDED:
- /* Accept the connection. */
- adsc_status = ASCS_CONNECTED;
- as->fd = async_socket_connector_pull_fd(connector);
- loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as);
- break;
-
- case ASC_CONNECTION_RETRY:
- adsc_status = ASCS_RETRY;
- break;
-
- case ASC_CONNECTION_FAILED:
- default:
- adsc_status = ASCS_FAILURE;
- break;
+ if (event == ASIO_STATE_SUCCEEDED) {
+ /* Accept the connection. */
+ as->fd = async_socket_connector_pull_fd(connector);
+ loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as);
}
/* Invoke client's callback. */
- action = as->client_cb->on_connection(as->client_opaque, as, adsc_status);
- if (event == ASC_CONNECTION_SUCCEEDED && action != ASCA_KEEP) {
+ action = as->on_connection(as->client_opaque, as, event);
+ if (event == ASIO_STATE_SUCCEEDED && action != ASIO_ACTION_DONE) {
/* For whatever reason the client didn't want to keep this connection.
* Close it. */
+ D("Connection is discarded by a client of async socket '%s'",
+ _async_socket_string(as));
_async_socket_close_socket(as);
}
- if (action == ASCA_RETRY) {
- return ASC_CB_RETRY;
- } else if (action == ASCA_ABORT) {
- return ASC_CB_ABORT;
- } else {
- return ASC_CB_KEEP;
- }
+ return action;
}
/* Timer callback invoked to reconnect the lost connection.
@@ -879,12 +985,12 @@ _on_async_socket_reconnect(void* opaque)
AsyncSocket*
async_socket_new(int port,
int reconnect_to,
- const ASClientCb* client_cb,
+ on_as_connection_cb client_cb,
void* client_opaque)
{
AsyncSocket* as;
- if (client_cb == NULL || client_cb->on_connection == NULL) {
+ if (client_cb == NULL) {
E("Invalid client_cb parameter");
return NULL;
}
@@ -893,7 +999,7 @@ async_socket_new(int port,
as->fd = -1;
as->client_opaque = client_opaque;
- as->client_cb = client_cb;
+ as->on_connection = client_cb;
as->readers_head = as->readers_tail = NULL;
as->reconnect_to = reconnect_to;
sock_address_init_inet(&as->address, SOCK_ADDRESS_INET_LOOPBACK, port);
@@ -901,6 +1007,7 @@ async_socket_new(int port,
if (as->looper == NULL) {
E("Unable to create I/O looper for async socket '%s'",
_async_socket_string(as));
+ client_cb(client_opaque, as, ASIO_STATE_FAILED);
_async_socket_destroy(as);
return NULL;
}
@@ -909,15 +1016,16 @@ async_socket_new(int port,
return as;
}
-int
+void
async_socket_connect(AsyncSocket* as, int retry_to)
{
AsyncSocketConnector* const connector =
async_socket_connector_new(&as->address, retry_to, _on_connector_events, as);
- if (connector == NULL) {
- return -1;
+ if (connector != NULL) {
+ async_socket_connector_connect(connector);
+ } else {
+ as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
}
- return (async_socket_connector_connect(connector) == ASC_CONNECT_FAILED) ? -1 : 0;
}
void
@@ -930,18 +1038,18 @@ async_socket_disconnect(AsyncSocket* as)
}
}
-int
+void
async_socket_reconnect(AsyncSocket* as, int retry_to)
{
_async_socket_cancel_all_io(as);
_async_socket_close_socket(as);
- return async_socket_connect(as, retry_to);
+ async_socket_connect(as, retry_to);
}
-int
+void
async_socket_read_abs(AsyncSocket* as,
void* buffer, uint32_t len,
- const ASIOCb* reader_cb,
+ on_as_io_cb reader_cb,
void* reader_opaque,
Duration deadline)
{
@@ -955,25 +1063,24 @@ async_socket_read_abs(AsyncSocket* as,
as->readers_tail = asr;
}
loopIo_wantRead(as->io);
- return 0;
}
-int
+void
async_socket_read_rel(AsyncSocket* as,
void* buffer, uint32_t len,
- const ASIOCb* reader_cb,
+ on_as_io_cb reader_cb,
void* reader_opaque,
int to)
{
const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
DURATION_INFINITE;
- return async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl);
+ async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl);
}
-int
+void
async_socket_write_abs(AsyncSocket* as,
const void* buffer, uint32_t len,
- const ASIOCb* writer_cb,
+ on_as_io_cb writer_cb,
void* writer_opaque,
Duration deadline)
{
@@ -987,16 +1094,29 @@ async_socket_write_abs(AsyncSocket* as,
as->writers_tail = asw;
}
loopIo_wantWrite(as->io);
- return 0;
}
-int async_socket_write_rel(AsyncSocket* as,
- const void* buffer, uint32_t len,
- const ASIOCb* writer_cb,
- void* writer_opaque,
- int to)
+void
+async_socket_write_rel(AsyncSocket* as,
+ const void* buffer, uint32_t len,
+ on_as_io_cb writer_cb,
+ void* writer_opaque,
+ int to)
{
const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
DURATION_INFINITE;
- return async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl);
+ async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl);
+}
+
+void*
+async_socket_get_client_opaque(const AsyncSocket* as)
+{
+ return as->client_opaque;
+}
+
+Duration
+async_socket_deadline(AsyncSocket* as, int rel)
+{
+ return (rel >= 0) ? looper_now(_async_socket_get_looper(as)) + rel :
+ DURATION_INFINITE;
}
diff --git a/android/async-socket.h b/android/async-socket.h
index 5b5d125..1402126 100644
--- a/android/async-socket.h
+++ b/android/async-socket.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_ASYNC_SOCKET_H_
#define ANDROID_ASYNC_SOCKET_H_
+#include "android/async-io-common.h"
+
/*
- * Contains declaration of an API that encapsulates communication via
+ * Contains declaration of an API that encapsulates communication via an
* asynchronous socket.
*
- * This is pretty basic API that allows to asynchronously connect to a socket,
- * and perform asynchronous read from / write to the connected socket.
+ * This is pretty basic API that allows asynchronous connection to a socket,
+ * and asynchronous read from / write to the connected socket.
*
* Since all the operations (including connection) are asynchronous, all the
* operation results are reported back to the client of this API via set of
@@ -32,32 +34,8 @@
/* Declares asynchronous socket descriptor. */
typedef struct AsyncSocket AsyncSocket;
-/* Enumerates asynchronous socket connection statuses.
- * Values enumerated here are passed to the client's callback that was set to
- * monitor socket connection.
- */
-typedef enum ASConnectStatus {
- /* Socket has been connected. */
- ASCS_CONNECTED,
- /* Socket has been disconnected. */
- ASCS_DISCONNECTED,
- /* An error has occured while connecting to the socket. */
- ASCS_FAILURE,
- /* An attempt to retry connection is about to begin. */
- ASCS_RETRY,
-} ASConnectStatus;
-
-/* Enumerates values returned from the client's callback that was set to
- * monitor socket connection.
- */
-typedef enum ASConnectAction {
- /* Keep the connection. */
- ASCA_KEEP,
- /* Retry connection attempt. */
- ASCA_RETRY,
- /* Abort the connection. */
- ASCA_ABORT,
-} ASConnectAction;
+/* Asynchronous socket I/O (reader, or writer) descriptor. */
+typedef struct AsyncSocketIO AsyncSocketIO;
/* Defines client's callback set to monitor socket connection.
* Param:
@@ -65,216 +43,177 @@ typedef enum ASConnectAction {
* as - Initialized AsyncSocket instance.
* status - Socket connection status.
* Return:
- * One of the ASConnectAction values.
+ * One of the AsyncIOAction values.
*/
-typedef ASConnectAction (*on_as_connection_cb)(void* client_opaque,
- AsyncSocket* as,
- ASConnectStatus status);
+typedef AsyncIOAction (*on_as_connection_cb)(void* client_opaque,
+ AsyncSocket* as,
+ AsyncIOState status);
-/* Defines client's callback set to monitor socket I/O failures.
+/* Defines client's callback set to monitor I/O progress.
* Param:
- * client_opaque - An opaque pointer associated with the client.
- * as - Initialized AsyncSocket instance.
- * is_io_read - I/O type selector: 1 - read, 0 - write.
- * io_opaque - An opaque pointer associated with the I/O that has failed.
- * buffer - Address of the I/O buffer.
- * transferred - Number of bytes that were transferred before I/O has failed.
- * to_transfer - Number of bytes initially requested to transfer with the
- * failed I/O.
- * failure - Error that occured (errno value)
+ * io_opaque - An opaque pointer associated with the I/O.
+ * asio - Async I/O in progress.
+ * status - Status of the I/O.
+ * Return:
+ * One of the AsyncIOAction values.
*/
-typedef void (*on_as_io_failure_cb)(void* client_opaque,
- AsyncSocket* as,
- int is_io_read,
- void* io_opaque,
- void* buffer,
- uint32_t transferred,
- uint32_t to_transfer,
- int failure);
+typedef AsyncIOAction (*on_as_io_cb)(void* io_opaque,
+ AsyncSocketIO* asio,
+ AsyncIOState status);
-/* Defines client's callback invoked when I/O has been completed.
- * Param:
- * client_opaque - An opaque pointer associated with the client.
- * as - Initialized AsyncSocket instance.
- * is_io_read - I/O type selector: 1 - read, 0 - write.
- * io_opaque - An opaque pointer associated with the I/O that has been
- * completed.
- * buffer - Address of the I/O buffer.
- * transferred - Number of bytes that were transferred.
- */
-typedef void (*on_as_io_completed_cb)(void* client_opaque,
- AsyncSocket* as,
- int is_io_read,
- void* io_opaque,
- void* buffer,
- uint32_t transferred);
+/********************************************************************************
+ * AsyncSocketIO API
+ *******************************************************************************/
-/* Defines client's callback invoked when an I/O gets cancelled (due to a
- * disconnection, for instance).
- * Param:
- * client_opaque - An opaque pointer associated with the client.
- * as - Initialized AsyncSocket instance.
- * is_io_read - I/O type selector: 1 - read, 0 - write.
- * io_opaque - An opaque pointer associated with the I/O that has been
- * cancelled.
- * buffer - Address of the I/O buffer.
- * transferred - Number of bytes that were transferred before I/O has been
- * cancelled.
- * to_transfer - Number of bytes initially requested to transfer with the
- * cancelled I/O.
- */
-typedef void (*on_as_io_cancelled_cb)(void* client_opaque,
- AsyncSocket* as,
- int is_io_read,
- void* io_opaque,
- void* buffer,
- uint32_t transferred,
- uint32_t to_transfer);
+/* Gets AsyncSocket instance for an I/O */
+extern AsyncSocket* async_socket_io_get_socket(const AsyncSocketIO* asio);
+
+/* Cancels time out set for an I/O */
+extern void async_socket_io_cancel_time_out(AsyncSocketIO* asio);
+
+/* Gets an opaque pointer associated with an I/O */
+extern void* async_socket_io_get_io_opaque(const AsyncSocketIO* asio);
-/* Defines client's callback invoked when an I/O gets timed out.
+/* Gets an opaque pointer associated with the client that has requested I/O */
+extern void* async_socket_io_get_client_opaque(const AsyncSocketIO* asio);
+
+/* Gets I/O buffer information.
* Param:
- * client_opaque - An opaque pointer associated with the client.
- * as - Initialized AsyncSocket instance.
- * is_io_read - I/O type selector: 1 - read, 0 - write.
- * io_opaque - An opaque pointer associated with the I/O that has timed out.
- * buffer - Address of the I/O buffer.
- * transferred - Number of bytes that were transferred before I/O has timed out.
- * to_transfer - Number of bytes initially requested to transfer with the timed
- * out I/O.
+ * asio - I/O descriptor.
+ * transferred - Optional pointer to receive number of bytes transferred with
+ * this I/O. Can be NULL.
+ * to_transfer - Optional pointer to receive number of bytes requested to
+ * transfer with this I/O. Can be NULL.
+ * Return:
+ * I/O buffer.
*/
-typedef void (*on_as_io_timed_out_cb)(void* client_opaque,
- AsyncSocket* as,
- int is_io_read,
- void* io_opaque,
- void* buffer,
- uint32_t transferred,
- uint32_t to_transfer);
+extern void* async_socket_io_get_buffer_info(const AsyncSocketIO* asio,
+ uint32_t* transferred,
+ uint32_t* to_transfer);
-/* Lists asynchronous socket I/O callbacks. */
-typedef struct ASIOCb {
- on_as_io_completed_cb on_completed;
- on_as_io_cancelled_cb on_cancelled;
- on_as_io_timed_out_cb on_timed_out;
- on_as_io_failure_cb on_io_failure;
-} ASIOCb;
+/* Gets I/O buffer. */
+extern void* async_socket_io_get_buffer(const AsyncSocketIO* asio);
+/* Gets number of bytes transferred with this I/O. */
+extern uint32_t async_socket_io_get_transferred(const AsyncSocketIO* asio);
-/* Lists asynchronous socket client callbacks. */
-typedef struct ASClientCb {
- /* Connection callback (client must have one) */
- on_as_connection_cb on_connection;
- /* Optional client-level I/O callbacks. */
- const ASIOCb* io_cb;
-} ASClientCb;
+/* Gets number of bytes requested to transfer with this I/O. */
+extern uint32_t async_socket_io_get_to_transfer(const AsyncSocketIO* asio);
+
+/* Gets I/O type: read (returns 1), or write (returns 0). */
+extern int async_socket_io_is_read(const AsyncSocketIO* asio);
+
+/********************************************************************************
+ * AsyncSocket API
+ *******************************************************************************/
/* Creates an asynchronous socket descriptor.
* Param:
* port - TCP port to connect the socket to.
- * reconnect_to - Timeout before retrying to reconnect after disconnection.
- * 0 means "don't try to reconnect".
- * client_callbacks - Lists socket client callbacks.
+ * reconnect_to - Timeout before trying to reconnect after disconnection.
+ * connect_cb - Client callback to monitor connection state (must not be NULL).
* client_opaque - An opaque pointer to associate with the socket client.
* Return:
* Initialized AsyncSocket instance on success, or NULL on failure.
*/
extern AsyncSocket* async_socket_new(int port,
int reconnect_to,
- const ASClientCb* client_callbacks,
+ on_as_connection_cb connect_cb,
void* client_opaque);
/* Asynchronously connects to an asynchronous socket.
+ * Note that connection result will be reported via callback passed to the
+ * async_socket_new routine.
* Param:
* as - Initialized AsyncSocket instance.
* retry_to - Number of milliseconds to wait before retrying a failed
- * connection.
- * Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
+ * connection attempt.
*/
-extern int async_socket_connect(AsyncSocket* as, int retry_to);
+extern void async_socket_connect(AsyncSocket* as, int retry_to);
/* Disconnects from an asynchronous socket.
+ * NOTE: AsyncSocket instance referenced in this call will be destroyed in this
+ * routine.
* Param:
* as - Initialized and connected AsyncSocket instance.
*/
extern void async_socket_disconnect(AsyncSocket* as);
/* Asynchronously reconnects to an asynchronous socket.
+ * Note that connection result will be reported via callback passed to the
+ * async_socket_new routine.
* Param:
* as - Initialized AsyncSocket instance.
- * retry_to - Number of milliseconds to wait before retrying to reconnect.
- * Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
+ * retry_to - Number of milliseconds to wait before trying to reconnect.
*/
-extern int async_socket_reconnect(AsyncSocket* as, int retry_to);
+extern void async_socket_reconnect(AsyncSocket* as, int retry_to);
/* Asynchronously reads data from an asynchronous socket with a deadline.
* Param:
* as - Initialized and connected AsyncSocket instance.
* buffer, len - Buffer where to read data.
- * reader_cb - Lists reader's callbacks.
+ * reader_cb - Callback to monitor I/O progress (must not be NULL).
* reader_opaque - An opaque pointer associated with the reader.
* deadline - Deadline to complete the read.
- * Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
*/
-extern int async_socket_read_abs(AsyncSocket* as,
- void* buffer, uint32_t len,
- const ASIOCb* reader_cb,
- void* reader_opaque,
- Duration deadline);
+extern void async_socket_read_abs(AsyncSocket* as,
+ void* buffer, uint32_t len,
+ on_as_io_cb reader_cb,
+ void* reader_opaque,
+ Duration deadline);
/* Asynchronously reads data from an asynchronous socket with a relative timeout.
* Param:
* as - Initialized and connected AsyncSocket instance.
* buffer, len - Buffer where to read data.
- * reader_cb - Lists reader's callbacks.
+ * reader_cb - Callback to monitor I/O progress (must not be NULL).
* reader_opaque - An opaque pointer associated with the reader.
* to - Milliseconds to complete the read. to < 0 indicates "no timeout"
- * Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
*/
-extern int async_socket_read_rel(AsyncSocket* as,
- void* buffer, uint32_t len,
- const ASIOCb* reader_cb,
- void* reader_opaque,
- int to);
+extern void async_socket_read_rel(AsyncSocket* as,
+ void* buffer, uint32_t len,
+ on_as_io_cb reader_cb,
+ void* reader_opaque,
+ int to);
/* Asynchronously writes data to an asynchronous socket with a deadline.
* Param:
* as - Initialized and connected AsyncSocket instance.
* buffer, len - Buffer with writing data.
- * writer_cb - Lists writer's callbacks.
+ * writer_cb - Callback to monitor I/O progress (must not be NULL).
* writer_opaque - An opaque pointer associated with the writer.
* deadline - Deadline to complete the write.
- * Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
*/
-extern int async_socket_write_abs(AsyncSocket* as,
- const void* buffer, uint32_t len,
- const ASIOCb* writer_cb,
- void* writer_opaque,
- Duration deadline);
+extern void async_socket_write_abs(AsyncSocket* as,
+ const void* buffer, uint32_t len,
+ on_as_io_cb writer_cb,
+ void* writer_opaque,
+ Duration deadline);
/* Asynchronously writes data to an asynchronous socket with a relative timeout.
* Param:
* as - Initialized and connected AsyncSocket instance.
* buffer, len - Buffer with writing data.
- * writer_cb - Lists writer's callbacks.
+ * writer_cb - Callback to monitor I/O progress (must not be NULL)
* writer_opaque - An opaque pointer associated with the writer.
* to - Milliseconds to complete the write. to < 0 indicates "no timeout"
+ */
+extern void async_socket_write_rel(AsyncSocket* as,
+ const void* buffer, uint32_t len,
+ on_as_io_cb writer_cb,
+ void* writer_opaque,
+ int to);
+
+/* Get a deadline for the given time interval relative to "now".
+ * Param:
+ * as - Initialized AsyncSocket instance.
+ * rel - Time interval. If < 0 an infinite duration will be returned.
* Return:
- * 0 on success, or -1 on failure. If this routine returns a failure, I/O
- * failure callback has not been invoked.
+ * A deadline for the given time interval relative to "now".
*/
-extern int async_socket_write_rel(AsyncSocket* as,
- const void* buffer, uint32_t len,
- const ASIOCb* writer_cb,
- void* writer_opaque,
- int to);
+extern Duration async_socket_deadline(AsyncSocket* as, int rel);
+
+/* Gets an opaque pointer associated with the socket's client */
+extern void* async_socket_get_client_opaque(const AsyncSocket* as);
#endif /* ANDROID_ASYNC_SOCKET_H_ */