blob: 6d460c204dad96e68f50458904f7e83d4f923d97 [file] [log] [blame]
/*
* Copyright (C) 2010 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_UTILS_H
#define ANDROID_ASYNC_UTILS_H
#include "android/looper.h"
#include "sockets.h"
/* A set of useful data types to perform asynchronous operations.
*
* IMPORTANT NOTE:
* In case of network disconnection, read() and write() just return 0
* the first time they are called. As a convenience, these functions
* will return ASYNC_ERROR and set 'errno' to ECONNRESET instead.
*/
typedef enum {
ASYNC_COMPLETE = 0, /* asynchronous operation completed */
ASYNC_ERROR, /* an error occurred, look at errno */
ASYNC_NEED_MORE /* more data is needed, try again later */
} AsyncStatus;
/**************************************************************************
**************************************************************************
*****
***** A S Y N C R E A D E R
*****
*****/
/* An AsyncReader makes it easier to read a given number of bytes into
* a target buffer asynchronously. Usage is the following:
*
* 1/ setup the reader with asyncReader_init(ar, buffer, buffsize,io);
* 2/ call asyncReader_read(ar, io), where 'io' is a LoopIo whenever
* you can receive data, i.e. just after the init() or in your
* own callback.
*/
typedef struct {
uint8_t* buffer;
size_t buffsize;
size_t pos;
LoopIo* io;
} AsyncReader;
/* Setup an ASyncReader, by giving the address of the read buffer,
* and the number of bytes we want to read.
*
* This also calls loopIo_wantRead(io) for you.
*/
void asyncReader_init(AsyncReader* ar,
void* buffer,
size_t buffsize,
LoopIo* io);
/* Try to read data from 'io' and return the state of the read operation.
*
* Returns:
* ASYNC_COMPLETE: If the read operation was complete. This will also
* call loopIo_dontWantRead(io) for you.
*
* ASYNC_ERROR: If an error occured (see errno). The error will be
* ECONNRESET in case of disconnection.
*
* ASYNC_NEED_MORE: If there was not enough incoming data to complete
* the read (or if 'events' doesn't contain LOOP_IO_READ).
*/
AsyncStatus asyncReader_read(AsyncReader* ar);
/**************************************************************************
**************************************************************************
*****
***** A S Y N C W R I T E R
*****
*****/
/* An AsyncWriter is the counterpart of an AsyncReader, but for writing
* data to a file descriptor asynchronously.
*/
typedef struct {
const uint8_t* buffer;
size_t buffsize;
size_t pos;
LoopIo* io;
} AsyncWriter;
/* Setup an ASyncWriter, by giving the address of the write buffer,
* and the number of bytes we want to write.
*
* This also calls loopIo_wantWrite(io) for you.
*/
void asyncWriter_init(AsyncWriter* aw,
const void* buffer,
size_t buffsize,
LoopIo* io);
/* Try to write data to 'io' and return the state of the write operation.
*
* Returns:
* ASYNC_COMPLETE: If the write operation was complete. This will also
* call loopIo_dontWantWrite(io) for you.
*
* ASYNC_ERROR: If an error occured (see errno). The error will be
* ECONNRESET in case of disconnection.
*
* ASYNC_NEED_MORE: If not all bytes could be sent yet (or if 'events'
* doesn't contain LOOP_IO_WRITE).
*/
AsyncStatus asyncWriter_write(AsyncWriter* aw);
/**************************************************************************
**************************************************************************
*****
***** A S Y N C L I N E R E A D E R
*****
*****/
/* An AsyncLineReader allows you to read one line of text asynchronously.
* The biggest difference with AsyncReader is that you don't know the line
* size in advance, so the object will read data byte-by-byte until it
* encounters a '\n'.
*/
typedef struct {
uint8_t* buffer;
size_t buffsize;
size_t pos;
LoopIo* io;
char eol;
} AsyncLineReader;
/* Setup an AsyncLineReader to read at most 'buffsize' characters (bytes)
* into 'buffer'. The reader will stop when it finds a '\n' which will be
* part of the buffer by default.
*
* NOTE: buffsize must be > 0. If not, asyncLineReader_getLine will return
* ASYNC_ERROR with errno == ENOMEM.
*
* buffsize must also sufficiently big to hold the final '\n'.
*
* Also calls loopIo_wantRead(io) for you.
*/
void asyncLineReader_init(AsyncLineReader* alr,
void* buffer,
size_t buffsize,
LoopIo* io);
/* Sets line terminator character for the reader.
* By default, asyncLineReader_init will set EOL to be '\n'. Sometimes it's more
* convenient to have '\0' as line terminator, so "line" reader easily becomes
* a "string" reader.
*/
AINLINED void
asyncLineReader_setEOL(AsyncLineReader* alr, char eol)
{
alr->eol = eol;
}
/* Try to read line characters from 'io'.
* Returns:
* ASYNC_COMPLETE: An end-of-line was detected, call asyncLineReader_getLine
* to extract the line content.
*
* ASYNC_ERROR: An error occured. Note that in case of disconnection,
* errno will be set to ECONNRESET, but you should be able
* to call asyncLineReader_getLine to read the partial line
* that was read.
*
* In case of overflow, errno will be set to ENOMEM.
*
* ASYNC_NEED_MORE: If there was not enough incoming data (or events
* does not contain LOOP_IO_READ).
*/
AsyncStatus asyncLineReader_read(AsyncLineReader* alr);
/* Return a pointer to the NON-ZERO-TERMINATED line characters, if any.
* If 'pLength" is not NULL, the function sets '*pLength' to the length
* in bytes of the line.
*
* Returns:
* NULL if 'buffsize' was initially 0, otherwise, a pointer to 'buffer'
* as passed in asyncLineReader_setup().
*
* NOTE: The data is *not* zero terminated, but its last character
* should be '\n' unless an error occured.
*/
const char* asyncLineReader_getLineRaw(AsyncLineReader* alr, int *pLength);
/* Return a pointer to the ZERO-TERMINATED line, with final '\n' or '\r\n'
* stripped. This will be NULL in case of error though.
*/
const char* asyncLineReader_getLine(AsyncLineReader* alr);
/**************************************************************************
**************************************************************************
*****
***** A S Y N C C O N N E C T O R
*****
*****/
/* Asynchronous connection to a socket
*/
typedef struct {
int error;
int state;
LoopIo* io;
} AsyncConnector;
AsyncStatus
asyncConnector_init(AsyncConnector* ac,
const SockAddress* address,
LoopIo* io);
AsyncStatus
asyncConnector_run(AsyncConnector* ac);
#endif /* ANDROID_ASYNC_UTILS_H */