Improved the management of locks in multithreaded sessions.

Managed the assurance of all threads is terminate before close the application.
This commit is contained in:
vemax78 2013-11-02 19:11:01 +01:00
parent 6ee885f9b6
commit 98b81311f5
5 changed files with 369 additions and 179 deletions

View File

@ -1,5 +1,6 @@
#include "ac.h"
#include "ac_soap.h"
#include "ac_session.h"
#include "capwap_dtls.h"
#include "capwap_socket.h"
@ -18,9 +19,13 @@ static char g_configurationfile[260] = AC_DEFAULT_CONFIGURATION_FILE;
/* Alloc AC */
static int ac_init(void) {
/* */
g_ac.standalone = 1;
/* Sessions message queue */
if (!ac_session_msgqueue_init()) {
return 0;
}
/* Network */
capwap_network_init(&g_ac.net);
g_ac.mtu = CAPWAP_MTU_DEFAULT;
@ -48,21 +53,21 @@ static int ac_init(void) {
g_ac.dfa.decrypterrorreport_interval = AC_DEFAULT_DECRYPT_ERROR_PERIOD_INTERVAL;
g_ac.dfa.idletimeout.timeout = AC_DEFAULT_IDLE_TIMEOUT_INTERVAL;
g_ac.dfa.wtpfallback.mode = AC_DEFAULT_WTP_FALLBACK_MODE;
/* */
g_ac.dfa.acipv4list.addresses = capwap_array_create(sizeof(struct in_addr), 0, 0);
g_ac.dfa.acipv6list.addresses = capwap_array_create(sizeof(struct in6_addr), 0, 0);
/* */
g_ac.dfa.rfcWaitJoin = AC_DEFAULT_WAITJOIN_INTERVAL;
g_ac.dfa.rfcWaitDTLS = AC_DEFAULT_WAITDTLS_INTERVAL;
g_ac.dfa.rfcChangeStatePendingTimer = AC_DEFAULT_CHANGE_STATE_PENDING_TIMER;
g_ac.dfa.rfcDataCheckTimer = AC_DEFAULT_DATA_CHECK_TIMER;
/* Sessions */
capwap_event_init(&g_ac.changesessionlist);
g_ac.sessions = capwap_list_create();
capwap_lock_init(&g_ac.sessionslock);
g_ac.sessionsthread = capwap_list_create();
capwap_rwlock_init(&g_ac.sessionslock);
g_ac.datasessionshandshake = capwap_list_create();
/* Backend */
@ -98,9 +103,10 @@ static void ac_destroy(void) {
/* Sessions */
capwap_list_free(g_ac.sessions);
capwap_lock_destroy(&g_ac.sessionslock);
capwap_event_destroy(&g_ac.changesessionlist);
capwap_list_free(g_ac.sessionsthread);
capwap_rwlock_destroy(&g_ac.sessionslock);
capwap_list_free(g_ac.datasessionshandshake);
ac_session_msgqueue_free();
/* Backend */
if (g_ac.backendacid) {

View File

@ -5,9 +5,10 @@
#include "capwap.h"
#include "capwap_network.h"
#include "capwap_protocol.h"
#include "capwap_lock.h"
#include "capwap_list.h"
#include "capwap_event.h"
#include "capwap_lock.h"
#include "capwap_rwlock.h"
#include "capwap_list.h"
#include "capwap_element.h"
#include <pthread.h>
@ -96,10 +97,13 @@ struct ac_t {
struct capwap_acname_element acname;
struct capwap_acdescriptor_element descriptor;
/* Sessions message queue */
int fdmsgsessions[2];
/* Sessions */
capwap_event_t changesessionlist;
struct capwap_list* sessions;
capwap_lock_t sessionslock;
struct capwap_list* sessionsthread;
capwap_rwlock_t sessionslock;
struct capwap_list* datasessionshandshake;
/* Dtls */
@ -113,6 +117,24 @@ struct ac_t {
struct capwap_array* availablebackends;
};
/* AC session thread */
struct ac_session_thread_t {
pthread_t threadid;
};
/* AC session message queue item */
#define AC_MESSAGE_QUEUE_CLOSE_THREAD 1
struct ac_session_msgqueue_item_t {
unsigned long message;
union {
struct {
pthread_t threadid;
} message_close_thread;
};
};
extern struct ac_t g_ac;
/* Primary thread */

View File

@ -1,12 +1,142 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_event.h"
#include "ac_session.h"
#include "ac_discovery.h"
#include "ac_backend.h"
#include <signal.h>
#define AC_RECV_NOERROR_MSGQUEUE -1001
/* */
static int ac_recvmsgqueue(int fd, struct ac_session_msgqueue_item_t* item) {
int packetsize = -1;
do {
packetsize = recv(fd, (void*)item, sizeof(struct ac_session_msgqueue_item_t), 0);
} while ((packetsize < 0) && ((errno == EAGAIN) || (errno == EINTR)));
return ((packetsize == sizeof(struct ac_session_msgqueue_item_t)) ? 1 : 0);
}
/* */
static void ac_session_msgqueue_parsing_item(struct ac_session_msgqueue_item_t* item) {
switch (item->message) {
case AC_MESSAGE_QUEUE_CLOSE_THREAD: {
struct capwap_list_item* search = g_ac.sessionsthread->first;
while (search != NULL) {
struct ac_session_thread_t* sessionthread = (struct ac_session_thread_t*)search->item;
ASSERT(sessionthread != NULL);
if (sessionthread->threadid == item->message_close_thread.threadid) {
void* dummy;
/* Clean thread resource */
pthread_join(sessionthread->threadid, &dummy);
capwap_itemlist_free(capwap_itemlist_remove(g_ac.sessionsthread, search));
break;
}
/* */
search = search->next;
}
break;
}
default: {
capwap_logging_debug("Unknown message queue item: %lu", item->message);
break;
}
}
}
/* */
static void ac_wait_terminate_allsessions(void) {
struct ac_session_msgqueue_item_t item;
/* Wait that list is empty */
while (g_ac.sessionsthread->count > 0) {
capwap_logging_debug("Waiting for %d session terminate", g_ac.sessionsthread->count);
/* Receive message queue packet */
if (!ac_recvmsgqueue(g_ac.fdmsgsessions[1], &item)) {
capwap_logging_debug("Unable to receive message queue");
break;
}
/* Parsing message queue packet */
if (item.message == AC_MESSAGE_QUEUE_CLOSE_THREAD) {
ac_session_msgqueue_parsing_item(&item);
}
}
}
/* Initialize message queue */
int ac_session_msgqueue_init(void) {
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_ac.fdmsgsessions)) {
return 0;
}
return 1;
}
/* Free sessions message queue */
void ac_session_msgqueue_free(void) {
close(g_ac.fdmsgsessions[1]);
close(g_ac.fdmsgsessions[0]);
}
/* */
void ac_session_msgqueue_notify_closethread(pthread_t threadid) {
struct ac_session_msgqueue_item_t item;
/* Send message */
memset(&item, 0, sizeof(struct ac_session_msgqueue_item_t));
item.message = AC_MESSAGE_QUEUE_CLOSE_THREAD;
item.message_close_thread.threadid = threadid;
send(g_ac.fdmsgsessions[0], (void*)&item, sizeof(struct ac_session_msgqueue_item_t), 0);
}
/* */
static int ac_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) {
int index;
ASSERT(fds);
ASSERT(fdscount > 0);
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
/* Wait packet */
index = capwap_wait_recvready(fds, fdscount, timeout);
if (index < 0) {
return index;
} else if (index == (fdscount - 1)) {
struct ac_session_msgqueue_item_t item;
/* Receive message queue packet */
if (!ac_recvmsgqueue(fds[index].fd, &item)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
/* Parsing message queue packet */
ac_session_msgqueue_parsing_item(&item);
return AC_RECV_NOERROR_MSGQUEUE;
}
/* Receive packet */
if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
return index;
}
/* Add packet to session */
static void ac_session_add_packet(struct ac_session_t* session, char* buffer, int size, int isctrlsocket, int plainbuffer) {
struct capwap_list_item* item;
@ -30,7 +160,7 @@ static void ac_session_add_packet(struct ac_session_t* session, char* buffer, in
}
/* Add action to session */
void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length) {
static void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length) {
struct capwap_list_item* item;
struct ac_session_action* actionsession;
@ -62,7 +192,7 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
ASSERT(address != NULL);
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
@ -70,19 +200,20 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
ASSERT(session != NULL);
if (!capwap_compare_ip(address, (isctrlsocket ? &session->wtpctrladdress : &session->wtpdataaddress))) {
/* Return session if not teardown */
if (!session->teardown) {
session->count++;
result = session;
}
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
capwap_lock_exit(&session->sessionlock);
/* */
result = session;
break;
}
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
@ -94,12 +225,11 @@ int ac_has_sessionid(struct capwap_sessionid_element* sessionid) {
ASSERT(sessionid != NULL);
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
@ -110,7 +240,7 @@ int ac_has_sessionid(struct capwap_sessionid_element* sessionid) {
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
@ -124,12 +254,11 @@ int ac_has_wtpid(char* wtpid) {
return -1;
}
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (session->wtpid && !strcmp(session->wtpid, wtpid)) {
@ -140,7 +269,7 @@ int ac_has_wtpid(char* wtpid) {
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
@ -197,27 +326,28 @@ static struct ac_session_t* ac_get_session_from_keepalive(void* buffer, int buff
struct capwap_list_item* search;
struct capwap_sessionid_element* sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(&packet, CAPWAP_ELEMENT_SESSIONID);
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
if (!session->teardown) {
session->count++;
result = session;
}
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
capwap_lock_exit(&session->sessionlock);
/* */
result = session;
break;
}
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
} else {
capwap_logging_debug("Failed validation parsed data packet");
}
@ -232,25 +362,47 @@ static struct ac_session_t* ac_get_session_from_keepalive(void* buffer, int buff
return result;
}
/* Close sessions */
static void ac_close_sessions() {
/* */
void ac_notify_event_session(struct capwap_sessionid_element* sessionid, long param) {
struct capwap_list_item* search;
capwap_lock_enter(&g_ac.sessionslock);
ASSERT(sessionid != NULL);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!session->teardown) {
ac_session_send_action(session, AC_SESSION_ACTION_CLOSE, 0, NULL, 0);
if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, param, NULL, 0);
break;
}
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Close sessions */
static void ac_close_sessions() {
struct capwap_list_item* search;
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
ac_session_send_action(session, AC_SESSION_ACTION_CLOSE, 0, NULL, 0);
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* DTLS Handshake BIO send */
@ -386,6 +538,7 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
session = (struct ac_session_t*)itemlist->item;
memset(session, 0, sizeof(struct ac_session_t));
session->itemlist = itemlist;
session->count = 2;
memcpy(&session->acctrladdress, acaddress, sizeof(struct sockaddr_storage));
memcpy(&session->wtpctrladdress, wtpaddress, sizeof(struct sockaddr_storage));
@ -425,39 +578,51 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
session->state = CAPWAP_IDLE_STATE;
/* Update session list */
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_insert_after(g_ac.sessions, NULL, itemlist);
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Create thread */
result = pthread_create(&session->threadid, NULL, ac_session_thread, (void*)session);
if (!result) {
pthread_detach(session->threadid);
struct ac_session_thread_t* sessionthread;
/* Notify change session list */
capwap_event_signal(&g_ac.changesessionlist);
/* Keeps trace of active threads */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_thread_t));
sessionthread = (struct ac_session_thread_t*)itemlist->item;
sessionthread->threadid = session->threadid;
/* */
capwap_itemlist_insert_after(g_ac.sessionsthread, NULL, itemlist);
} else {
capwap_logging_debug("Unable create session thread, error code %d", result);
/* Destroy element */
capwap_lock_enter(&g_ac.sessionslock);
capwap_itemlist_free(capwap_itemlist_remove(g_ac.sessions, itemlist));
capwap_lock_exit(&g_ac.sessionslock);
session = NULL;
capwap_logging_fatal("Unable create session thread, error code %d", result);
capwap_exit(CAPWAP_OUT_OF_MEMORY);
}
return session;
}
/* Release reference of session */
void ac_session_release_reference(struct ac_session_t* session) {
ASSERT(session != NULL);
capwap_lock_enter(&session->sessionlock);
/* Release reference must not destroy device, reference count > 0 */
session->count--;
ASSERT(session->count > 0);
capwap_lock_exit(&session->sessionlock);
}
/* Update statistics */
void ac_update_statistics(void) {
g_ac.descriptor.stations = 0; /* TODO */
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
g_ac.descriptor.activewtp = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Handler signal */
@ -469,10 +634,10 @@ static void ac_signal_handler(int signum) {
/* AC running */
int ac_execute(void) {
int fdscount = CAPWAP_MAX_SOCKETS * 2;
struct pollfd* fds;
int result = CAPWAP_SUCCESSFUL;
int fdscount = CAPWAP_MAX_SOCKETS * 2 + 1;
int index;
int check;
int isctrlsocket = 0;
@ -488,11 +653,16 @@ int ac_execute(void) {
/* Configure poll struct */
fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fdscount);
/* Retrive all socket for polling */
fdscount = capwap_network_set_pollfd(&g_ac.net, fds, fdscount);
ASSERT(fdscount > 0);
/* Unix socket message queue */
fds[fdscount].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
fds[fdscount].fd = g_ac.fdmsgsessions[1];
fdscount++;
/* Handler signal */
g_ac.running = 1;
signal(SIGPIPE, SIG_IGN);
@ -519,7 +689,7 @@ int ac_execute(void) {
/* Receive packet */
isrecvpacket = 0;
buffersize = sizeof(buffer);
index = capwap_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, NULL);
index = ac_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, NULL);
if (!g_ac.running) {
capwap_logging_debug("Closing AC");
break;
@ -557,9 +727,9 @@ int ac_execute(void) {
unsigned short sessioncount;
/* Get current session number */
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
/* PreParsing packet for reduce a DoS attack */
check = capwap_sanity_check(isctrlsocket, CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls, 0);
@ -584,12 +754,10 @@ int ac_execute(void) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
if (session) {
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 1);
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 1);
/* Release reference */
ac_session_release_reference(session);
}
/* Release reference */
ac_session_release_reference(session);
}
}
}
@ -606,12 +774,10 @@ int ac_execute(void) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
if (session) {
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0);
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0);
/* Release reference */
ac_session_release_reference(session);
}
/* Release reference */
ac_session_release_reference(session);
}
}
}
@ -623,7 +789,7 @@ int ac_execute(void) {
ac_update_session_from_datapacket(&datasocket, &recvfromaddr, &recvtoaddr, buffer, buffersize);
}
}
} else if (index == CAPWAP_RECV_ERROR_INTR) {
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE)) {
/* Ignore recv */
continue;
} else if (index == CAPWAP_RECV_ERROR_SOCKET) {
@ -642,24 +808,9 @@ int ac_execute(void) {
ac_close_sessions();
/* Wait to terminate all sessions */
capwap_event_reset(&g_ac.changesessionlist);
for (;;) {
int count;
capwap_lock_enter(&g_ac.sessionslock);
count = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
if (!count) {
break;
}
/* Wait that list is changed */
capwap_logging_debug("Waiting for %d session terminate", count);
capwap_event_wait(&g_ac.changesessionlist);
}
ac_wait_terminate_allsessions();
/* Free handshark session */
/* Free handshake session */
while (g_ac.datasessionshandshake->first != NULL) {
struct ac_data_session_handshake* handshake = (struct ac_data_session_handshake*)g_ac.datasessionshandshake->first->item;

View File

@ -48,11 +48,6 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
/* Free packet */
capwap_itemlist_free(itemaction);
return result;
} else if (session->teardown) {
/* Remove all pending packets, connection is teardown */
while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets)));
}
} else if ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
struct capwap_list_item* itempacket;
@ -474,6 +469,74 @@ static void ac_send_invalid_request(struct ac_session_t* session, struct capwap_
capwap_list_free(responsefragmentpacket);
}
/* Release reference of session */
static void ac_session_destroy(struct ac_session_t* session) {
ASSERT(session != NULL);
/* Free resource */
#ifdef DEBUG
char sessionname[33];
/* */
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Release Session AC %s", sessionname);
#endif
/* Release last reference */
capwap_lock_enter(&session->sessionlock);
session->count--;
/* Check if all reference is release */
while (session->count > 0) {
#ifdef DEBUG
capwap_logging_debug("Wait for release Session AC %s (count=%d)", sessionname, session->count);
#endif
/* Wait */
capwap_lock_exit(&session->sessionlock);
sleep(10);
capwap_lock_enter(&session->sessionlock);
}
capwap_lock_exit(&session->sessionlock);
/* Free DTSL Control */
capwap_crypt_freesession(&session->ctrldtls);
/* Free DTLS Data */
capwap_crypt_freesession(&session->datadtls);
/* Free resource */
while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets)));
}
/* */
capwap_event_destroy(&session->waitpacket);
capwap_lock_destroy(&session->sessionlock);
capwap_list_free(session->actionsession);
capwap_list_free(session->controlpackets);
capwap_list_free(session->datapackets);
/* Free fragments packet */
ac_free_packet_rxmng(session, 1);
ac_free_packet_rxmng(session, 0);
capwap_list_free(session->requestfragmentpacket);
capwap_list_free(session->responsefragmentpacket);
/* Free DFA resource */
capwap_array_free(session->dfa.acipv4list.addresses);
capwap_array_free(session->dfa.acipv6list.addresses);
if (session->wtpid) {
capwap_free(session->wtpid);
}
/* Free item */
capwap_itemlist_free(session->itemlist);
}
/* */
static void ac_session_run(struct ac_session_t* session) {
int res;
@ -597,9 +660,7 @@ static void ac_session_run(struct ac_session_t* session) {
}
/* Release reference session */
if (!ac_session_release_reference(session)) {
capwap_logging_debug("Reference session is > 0 to exit thread");
}
ac_session_destroy(session);
}
/* Change WTP state machine */
@ -621,8 +682,15 @@ void ac_dfa_change_state(struct ac_session_t* session, int state) {
int ac_session_teardown_connection(struct ac_session_t* session) {
ASSERT(session != NULL);
/* */
session->teardown = 1;
/* Remove session from list */
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_remove(g_ac.sessions, session->itemlist);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Remove all pending packets */
while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets)));
}
/* Close DTSL Control */
if (session->ctrldtls.enable) {
@ -641,86 +709,23 @@ int ac_session_teardown_connection(struct ac_session_t* session) {
return AC_DFA_DROP_PACKET;
}
/* Release reference of session */
int ac_session_release_reference(struct ac_session_t* session) {
int remove = 0;
struct capwap_list_item* search;
ASSERT(session != NULL);
capwap_lock_enter(&g_ac.sessionslock);
session->count--;
if (!session->count) {
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* item = (struct ac_session_t*)search->item;
if (session == item) {
#ifdef DEBUG
char sessionname[33];
/* */
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Release Session AC %s", sessionname);
#endif
/* Free DTSL Control */
capwap_crypt_freesession(&session->ctrldtls);
/* Free DTLS Data */
capwap_crypt_freesession(&session->datadtls);
/* Free resource */
while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets)));
}
capwap_event_destroy(&session->waitpacket);
capwap_lock_destroy(&session->sessionlock);
capwap_list_free(session->actionsession);
capwap_list_free(session->controlpackets);
capwap_list_free(session->datapackets);
/* Free fragments packet */
ac_free_packet_rxmng(session, 1);
ac_free_packet_rxmng(session, 0);
capwap_list_free(session->requestfragmentpacket);
capwap_list_free(session->responsefragmentpacket);
/* Free DFA resource */
capwap_array_free(session->dfa.acipv4list.addresses);
capwap_array_free(session->dfa.acipv6list.addresses);
if (session->wtpid) {
capwap_free(session->wtpid);
}
/* Remove item from list */
remove = 1;
capwap_itemlist_free(capwap_itemlist_remove(g_ac.sessions, search));
capwap_event_signal(&g_ac.changesessionlist);
break;
}
search = search->next;
}
}
capwap_lock_exit(&g_ac.sessionslock);
return remove;
}
/* */
void* ac_session_thread(void* param) {
pthread_t threadid;
struct ac_session_t* session = (struct ac_session_t*)param;
ASSERT(param != NULL);
threadid = session->threadid;
/* */
capwap_logging_debug("Session start");
ac_session_run((struct ac_session_t*)param);
ac_session_run(session);
capwap_logging_debug("Session end");
/* Notify terminate thread */
ac_session_msgqueue_notify_closethread(threadid);
/* Thread exit */
pthread_exit(NULL);
return NULL;
@ -757,7 +762,7 @@ void ac_get_control_information(struct capwap_list* controllist) {
capwap_list_free(addrlist);
/* */
capwap_lock_enter(&g_ac.sessionslock);
capwap_rwlock_rdlock(&g_ac.sessionslock);
/* Get wtp count from any local address */
for (item = controllist->first; item != NULL; item = item->next) {
@ -774,7 +779,7 @@ void ac_get_control_information(struct capwap_list* controllist) {
}
/* */
capwap_lock_exit(&g_ac.sessionslock);
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* */

View File

@ -2,6 +2,8 @@
#define __AC_SESSION_HEADER__
#include "capwap_dtls.h"
#include "capwap_event.h"
#include "capwap_lock.h"
#include "ac_soap.h"
#define AC_DFA_NO_PACKET 0
@ -10,7 +12,8 @@
#define AC_DFA_DEAD 3
/* */
#define AC_SESSION_ACTION_CLOSE 0
#define AC_SESSION_ACTION_CLOSE 0
#define AC_SESSION_ACTION_NOTIFY_EVENT 1
/* AC packet */
struct ac_packet {
@ -34,6 +37,7 @@ struct ac_session_action {
/* AC sessions */
struct ac_session_t {
struct capwap_list_item* itemlist; /* My itemlist into g_ac.sessions */
struct ac_state dfa;
/* Soap */
@ -84,10 +88,7 @@ struct ac_session_t {
/* */
void* ac_session_thread(void* param);
int ac_session_teardown_connection(struct ac_session_t* session);
int ac_session_release_reference(struct ac_session_t* session);
/* */
void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length);
void ac_session_release_reference(struct ac_session_t* session);
/* */
void ac_dfa_change_state(struct ac_session_t* session, int state);
@ -99,6 +100,11 @@ void ac_get_control_information(struct capwap_list* controllist);
void ac_free_reference_last_request(struct ac_session_t* session);
void ac_free_reference_last_response(struct ac_session_t* session);
/* */
int ac_session_msgqueue_init(void);
void ac_session_msgqueue_free(void);
void ac_session_msgqueue_notify_closethread(pthread_t threadid);
/* */
int ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet);
int ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_parsed_packet* packet);