Add support for HTTP transport errors callbacks (to end-user application).

This commit is contained in:
bossiel 2010-05-26 10:44:08 +00:00
parent 203fe0e859
commit 94e401647f
8 changed files with 84 additions and 19 deletions

View File

@ -66,6 +66,7 @@ typedef enum thttp_action_type_e
/* common */
atype_closed,
atype_error,
atype_close,
atype_cancel,

View File

@ -45,6 +45,7 @@ typedef enum thttp_event_type_e
thttp_event_message,
thttp_event_auth_failed,
thttp_event_closed,
thttp_event_transport_error
}
thttp_event_type_t;

View File

@ -194,7 +194,10 @@ TINYHTTP_API thttp_session_id_t thttp_session_get_id(const thttp_session_handle_
TINYHTTP_API const void* thttp_session_get_userdata(const thttp_session_handle_t *self);
int thttp_session_update_challenges(thttp_session_t *self, const thttp_response_t* response, tsk_bool_t answered);
int thttp_session_signal_closed(thttp_session_t *self);
int thttp_session_signal_error(thttp_session_t *self);
thttp_session_t* thttp_session_get_by_fd(thttp_sessions_L_t* sessions, tnet_fd_t fd);

View File

@ -270,6 +270,12 @@ static int thttp_transport_layer_stream_cb(const tnet_transport_event_t* e)
}
goto bail;
case event_error:
// alert all dialogs
if((session = thttp_session_get_by_fd(stack->sessions, e->fd))){
ret = thttp_session_signal_error(session);
}
goto bail;
case event_connected:
default:{
tsk_safeobj_unlock(stack);

View File

@ -45,6 +45,7 @@
#define DEBUG_STATE_MACHINE 1
#define THTTP_MESSAGE_DESCRIPTION(message) \
THTTP_MESSAGE_IS_RESPONSE(message) ? THTTP_RESPONSE_PHRASE(message) : THTTP_REQUEST_METHOD(message)
#define THTTP_DIALOG_TRANSPORT_ERROR_CODE -0xFF
/* ======================== internal functions ======================== */
int thttp_dialog_send_request(thttp_dialog_t *self);
@ -78,9 +79,9 @@ typedef enum _fsm_action_e
_fsm_action_close = atype_close,
_fsm_action_message = atype_i_message,
_fsm_action_closed = atype_closed,
_fsm_action_error = atype_error, // Transport error and not HTTP message error (e.g. 409)
_fsm_action_transporterror = 0xFF,
_fsm_action_error,
/* _fsm_action_any_other = 0xFF */
}
_fsm_action_t;
@ -151,7 +152,18 @@ int thttp_dialog_Transfering_2_Transfering_X_401_407(va_list *app)
self->answered = tsk_true;
/* Retry with creadentials. */
return thttp_dialog_send_request(self);
ret = thttp_dialog_send_request(self);
/* very important: do not break the state machine for transport error events
* => let the transport layer do it for us throught (transport_error).
* => transport_error event will be queued and sent after this event (i_message)
*/
if(ret == THTTP_DIALOG_TRANSPORT_ERROR_CODE){
return 0;
}
else{
return ret;
}
}
/* Transfering -> (1xx) -> Transfering */
@ -183,11 +195,10 @@ int thttp_dialog_Any_2_Terminated_X_closed(va_list *app)
{
int ret = -2;
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t *);
thttp_event_t* e = tsk_null;
thttp_event_t* e;
//self->fd = TNET_INVALID_FD; // to avoid close(fd) in the destructor
// alert the user
/* Alert the user. */
/* Alert the user */
if((e = thttp_event_create(thttp_event_closed, self->session, "Connection closed", tsk_null))){
ret = thttp_stack_alert(self->session->stack, e);
TSK_OBJECT_SAFE_FREE(e);
@ -199,6 +210,16 @@ int thttp_dialog_Any_2_Terminated_X_closed(va_list *app)
/* Any -> (error) -> Terminated */
int thttp_dialog_Any_2_Terminated_X_Error(va_list *app)
{
int ret = -2;
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t *);
thttp_event_t* e;
/* Alert the user */
if((e = thttp_event_create(thttp_event_transport_error, self->session, "Transport error", tsk_null))){
ret = thttp_stack_alert(self->session->stack, e);
TSK_OBJECT_SAFE_FREE(e);
}
return 0;
}
@ -348,7 +369,7 @@ int thttp_dialog_send_request(thttp_dialog_t *self)
}
else{
TSK_DEBUG_INFO("Failed to sent HTTP/HTTPS message.");
ret = -15;
ret = THTTP_DIALOG_TRANSPORT_ERROR_CODE;
}
bail:

View File

@ -40,6 +40,8 @@
/**@defgroup thttp_session_group HTTP Session
*/
int thttp_session_signal(thttp_session_t *self, thttp_action_type_t atype);
/**Sets parameters.
*/
int __thttp_session_set(thttp_session_t *self, va_list* app)
@ -352,31 +354,51 @@ bail:
}
/** Signals to all dialogs that the connection have been closed.
*/
int thttp_session_signal_closed(thttp_session_t *self)
/* internal function */
int thttp_session_signal(thttp_session_t *self, thttp_action_type_t atype)
{
tsk_list_item_t *item;
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(self);
again:
tsk_list_foreach(item, self->dialogs){
// FIXME: not thread-safe
//--thttp_dialog_fsm_act((thttp_dialog_t*)item->data, atype_closed, tsk_null, tsk_null);
thttp_dialog_fsm_act((thttp_dialog_t*)item->data, atype, tsk_null, tsk_null);
/* As the above action could terminate the dialog (which means change the content of self->dialogs)
* => list becomes unsafe */
goto again;
}
switch(atype){
case atype_closed:
self->fd = TNET_INVALID_FD;
break;
default:
break;
}
self->fd = TNET_INVALID_FD;
tsk_safeobj_unlock(self);
return 0;
}
/** Retrieves a session by fd.
*/
/** Signals to all dialogs that the connection have been closed. */
int thttp_session_signal_closed(thttp_session_t *self)
{
return thttp_session_signal(self, atype_closed);
}
/** Signals to all dialogss that we got an error */
int thttp_session_signal_error(thttp_session_t *self)
{
return thttp_session_signal(self, atype_error);
}
/** Retrieves a session by fd */
thttp_session_t* thttp_session_get_by_fd(thttp_sessions_L_t* sessions, tnet_fd_t fd)
{
thttp_session_t* ret = tsk_null;

View File

@ -56,6 +56,12 @@ int test_stack_callback(const thttp_event_t *httpevent)
TSK_DEBUG_INFO("closed sid=%llu", id);
break;
}
case thttp_event_transport_error: /* HTTP connection closed (informational) */
{
TSK_DEBUG_INFO("Transport sid=%llu", id);
break;
}
}
return 0;
@ -103,7 +109,8 @@ void test_stack()
// session-level headers
THTTP_SESSION_SET_HEADER("Pragma", "No-Cache"),
THTTP_SESSION_SET_HEADER("Connection", "Keep-Alive"),
//THTTP_SESSION_SET_HEADER("Connection", "Keep-Alive"),
THTTP_SESSION_SET_HEADER("Connection", "close"),
THTTP_SESSION_SET_HEADER("User-Agent", "doubango 1.0"),
THTTP_SESSION_SET_NULL()); /* MUST always be present */

View File

@ -492,6 +492,7 @@ void *tnet_transport_mainthread(void *param)
/* Get the network events flags */
if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR){
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed.");
tsk_safeobj_unlock(context);
@ -506,6 +507,7 @@ void *tnet_transport_mainthread(void *param)
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description);
if(networkEvents.iErrorCode[FD_ACCEPT_BIT]){
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
goto done;
}
@ -538,6 +540,7 @@ void *tnet_transport_mainthread(void *param)
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description);
if(networkEvents.iErrorCode[FD_CONNECT_BIT]){
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
TNET_PRINT_LAST_ERROR("CONNECT FAILED.");
goto done;
}
@ -557,6 +560,7 @@ void *tnet_transport_mainthread(void *param)
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description);
if(networkEvents.iErrorCode[FD_READ_BIT]){
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
TNET_PRINT_LAST_ERROR("READ FAILED.");
goto done;
}
@ -592,8 +596,7 @@ void *tnet_transport_mainthread(void *param)
ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0);
}
if(ret)
{
if(ret){
ret = WSAGetLastError();
if(ret == WSAEWOULDBLOCK){
TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION");
@ -630,6 +633,7 @@ void *tnet_transport_mainthread(void *param)
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description);
if(networkEvents.iErrorCode[FD_WRITE_BIT]){
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
TNET_PRINT_LAST_ERROR("WRITE FAILED.");
goto done;
}