mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-09-17 22:59:57 +08:00
feat(nopoll): Move nopoll to components
This commit is contained in:
269
components/nopoll/library/nopoll_loop.c
Normal file
269
components/nopoll/library/nopoll_loop.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_loop.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_loop noPoll Loop: basic support to create a watching loop for WebSocket listeners
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_loop
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal Function used by nopoll_loop_wait to register all
|
||||
* connections into the io waiting object.
|
||||
*/
|
||||
nopoll_bool nopoll_loop_register (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data)
|
||||
{
|
||||
/* do not add connections that aren't working */
|
||||
if (! nopoll_conn_is_ok (conn)) {
|
||||
/* remove this connection from registry */
|
||||
nopoll_ctx_unregister_conn (ctx, conn);
|
||||
return nopoll_false; /* keep foreach, don't stop */
|
||||
}
|
||||
|
||||
/* register the connection socket */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding socket id: %d", conn->session);*/
|
||||
if (! ctx->io_engine->addto (conn->session, ctx, conn, ctx->io_engine->io_object)) {
|
||||
/* remove this connection from registry */
|
||||
nopoll_ctx_unregister_conn (ctx, conn);
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Failed to add socket %d to the watching set", conn->session);
|
||||
}
|
||||
|
||||
return nopoll_false; /* keep foreach, don't stop */
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to handle incoming data from from the
|
||||
* connection and to notify this data on the connection.
|
||||
*/
|
||||
void nopoll_loop_process_data (noPollCtx * ctx, noPollConn * conn)
|
||||
{
|
||||
noPollMsg * msg;
|
||||
|
||||
/* call to get messages from the connection */
|
||||
msg = nopoll_conn_get_msg (conn);
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
/* found message, notify it */
|
||||
if (conn->on_msg)
|
||||
conn->on_msg (ctx, conn, msg, conn->on_msg_data);
|
||||
else if (ctx->on_msg)
|
||||
ctx->on_msg (ctx, conn, msg, ctx->on_msg_data);
|
||||
|
||||
/* release message */
|
||||
nopoll_msg_unref (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to detected which connections has something
|
||||
* interesting to be notified.
|
||||
*
|
||||
*/
|
||||
nopoll_bool nopoll_loop_process (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data)
|
||||
{
|
||||
int * conn_changed = (int *) user_data;
|
||||
|
||||
/* check if the connection have something to notify */
|
||||
if (ctx->io_engine->isset (ctx, conn->session, ctx->io_engine->io_object)) {
|
||||
|
||||
/* call to notify action according to role */
|
||||
switch (conn->role) {
|
||||
case NOPOLL_ROLE_CLIENT:
|
||||
case NOPOLL_ROLE_LISTENER:
|
||||
/* received data, notify */
|
||||
nopoll_loop_process_data (ctx, conn);
|
||||
break;
|
||||
case NOPOLL_ROLE_MAIN_LISTENER:
|
||||
/* call to handle */
|
||||
nopoll_conn_accept (ctx, conn);
|
||||
break;
|
||||
default:
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found connection with unknown role, closing and dropping");
|
||||
nopoll_conn_shutdown (conn);
|
||||
break;
|
||||
}
|
||||
|
||||
/* reduce connection changed */
|
||||
(*conn_changed)--;
|
||||
} /* end if */
|
||||
|
||||
return (*conn_changed) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to init internal io wait mechanism...
|
||||
*
|
||||
* @param ctx The noPoll context to be initialized if it wasn't
|
||||
*/
|
||||
void nopoll_loop_init (noPollCtx * ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* grab the mutex for the following check */
|
||||
if (ctx->io_engine == NULL) {
|
||||
ctx->io_engine = nopoll_io_get_engine (ctx, NOPOLL_IO_ENGINE_DEFAULT);
|
||||
if (ctx->io_engine == NULL) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to create IO wait engine, unable to implement wait call");
|
||||
return;
|
||||
}
|
||||
} /* end if */
|
||||
/* release the mutex */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flag to stop the current loop implemented (if any) on the provided context.
|
||||
*
|
||||
* @param ctx The context where the loop is being done, and wanted to
|
||||
* be stopped.
|
||||
*
|
||||
*/
|
||||
void nopoll_loop_stop (noPollCtx * ctx)
|
||||
{
|
||||
if (! ctx)
|
||||
return;
|
||||
ctx->keep_looping = nopoll_false;
|
||||
return;
|
||||
} /* end if */
|
||||
|
||||
/**
|
||||
* @brief Allows to implement a wait over all connections registered
|
||||
* under the provided context during the provided timeout until
|
||||
* something is detected meaningful to the user, calling to the action
|
||||
* handler defined, optionally receving the user data pointer.
|
||||
*
|
||||
* @param ctx The context object where the wait will be implemented.
|
||||
*
|
||||
* @param timeout The timeout to wait for changes. If no changes
|
||||
* happens, the function returns. The function will block the caller
|
||||
* until a call to \ref nopoll_loop_stop is done in the case timeout
|
||||
* passed is 0.
|
||||
*
|
||||
* @return The function returns 0 when finished or -2 in the case ctx
|
||||
* is NULL or timeout is negative.
|
||||
*/
|
||||
int nopoll_loop_wait (noPollCtx * ctx, long timeout)
|
||||
{
|
||||
struct timeval start;
|
||||
struct timeval stop;
|
||||
struct timeval diff;
|
||||
long ellapsed;
|
||||
int wait_status;
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx, -2);
|
||||
nopoll_return_val_if_fail (ctx, timeout >= 0, -2);
|
||||
|
||||
/* call to init io engine */
|
||||
nopoll_loop_init (ctx);
|
||||
|
||||
/* get as reference current time */
|
||||
if (timeout > 0)
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
nopoll_win32_gettimeofday (&start, NULL);
|
||||
#else
|
||||
gettimeofday (&start, NULL);
|
||||
#endif
|
||||
|
||||
/* set to keep looping everything this function is called */
|
||||
ctx->keep_looping = nopoll_true;
|
||||
|
||||
while (ctx->keep_looping) {
|
||||
/* ok, now implement wait operation */
|
||||
ctx->io_engine->clear (ctx, ctx->io_engine->io_object);
|
||||
|
||||
/* add all connections */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding connections to watch: %d", ctx->conn_num); */
|
||||
nopoll_ctx_foreach_conn (ctx, nopoll_loop_register, NULL);
|
||||
|
||||
/* if (errno == EBADF) { */
|
||||
/* detected some descriptor not properly
|
||||
* working, try to check them */
|
||||
/* nopoll_ctx_foreach_conn (ctx, nopoll_loop_clean_descriptors, NULL); */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found some descriptor is not valid (errno==%d)", errno);
|
||||
continue; */
|
||||
/* } */ /* end if */
|
||||
|
||||
/* implement wait operation */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting for changes into %d connections", ctx->conn_num); */
|
||||
wait_status = ctx->io_engine->wait (ctx, ctx->io_engine->io_object);
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting finished with result %d", wait_status); */
|
||||
if (wait_status == -1) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received error from wait operation, error code was: %d", errno);
|
||||
break;
|
||||
} /* end if */
|
||||
|
||||
/* check how many connections changed and restart */
|
||||
if (wait_status > 0) {
|
||||
/* check and call for connections with something
|
||||
* interesting */
|
||||
nopoll_ctx_foreach_conn (ctx, nopoll_loop_process, &wait_status);
|
||||
}
|
||||
|
||||
/* check to stop wait operation */
|
||||
if (timeout > 0) {
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
nopoll_win32_gettimeofday (&stop, NULL);
|
||||
#else
|
||||
gettimeofday (&stop, NULL);
|
||||
#endif
|
||||
nopoll_timeval_substract (&stop, &start, &diff);
|
||||
ellapsed = (diff.tv_sec * 1000000) + diff.tv_usec;
|
||||
if (ellapsed > timeout)
|
||||
break;
|
||||
} /* end if */
|
||||
} /* end while */
|
||||
|
||||
/* release engine */
|
||||
nopoll_io_release_engine (ctx->io_engine);
|
||||
ctx->io_engine = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
|
Reference in New Issue
Block a user