Commit 1171cd31 authored by 's avatar
Browse files

Added a new function - mapi_asynchronous_get_next_pkt() - for packet...

Added a new function - mapi_asynchronous_get_next_pkt() - for packet pre-fetching, using the PUSH model

git-svn-id: file:///home/svn/mapi/trunk@1392 8d5bb341-7cf1-0310-8cf6-ba355fef3186
parent 42a139cf
......@@ -417,6 +417,17 @@ void mapicommd_logging(int log_to_file, int log_to_syslog, int log_fd, struct dm
log_message("read results (fd: %d, fid: %d) FAILED", dbuf->fd, dbuf->fid);
break;
case GET_NEXT_PKT_ASYN:
if(log_to_file){
file_size = acquire_write_lock(log_fd);
write_to_file(log_fd, "MAPICOMMD: asynchronous get next packet (fd: %d, fid: %d) at ", dbuf->fd, dbuf->fid);
write_date(log_fd); write_newline(log_fd, "\n");
release_write_lock(log_fd, file_size);
}
if(log_to_syslog)
log_message("asynchronous get next packet (fd: %d, fid: %d)", dbuf->fd, dbuf->fid);
break;
case GET_FLOW_INFO:
case GET_NEXT_FLOW_INFO:
if(log_to_file){
......
......@@ -44,34 +44,36 @@ static char* mapidsocketglobal = NULL;
flist_t *flowlist = NULL;
#ifdef DIMAPISSL
static SSL_CTX *ctx;
void sigpipe_handle();
#endif
#ifdef RECONNECT
#ifdef DIMAPI
int check_network_mapicommd(struct host *h); // checks if network (mapicommd) is up. Returns 1 if network is up, 0 otherwise
void restore_network_mapicommd(struct host *h); // restores the connection to mapicommd in case of a breakdown, using back-off mechanism
void mapi_recreate_flow(struct host *h); // recreates all flows, that host which broke down the connection had created
void mapi_reapply_function(struct host *h); // reapplies all functions, that host which broke down the connection had applyed
void mapi_reconnect(struct host *h); // checks which flows of the specified host, had called mapi_connect() function
#ifdef WITH_AUTHENTICATION
void mapi_reauthenticate(struct host *h); // checks which flows of the specified host, had called mapi_authenticate() function
#endif
void check_mapi_functions(struct host *h); // checks all functions that can be called, when a break down happens
void mapi_get_next_packet(struct host *h); // checks which flows of the specified host, had called mapi_get_next_pkt() function
typedef struct function_data{
int fid; // real fid returned from mapicommd
mapidflib_function_def_t *fdef; // function definition
int fidseed; // fid returned to mapi user
mapidflib_function_def_t* fdef; // function definition
struct dmapiipcbuf *dbuf; // need for asynchronous mapi_read_results
#ifdef RECONNECT
host_flow *hflow; // flow of a specified host
char args[DIMAPI_DATA_SIZE]; // function's arguments
int index; // need for functions that have arguments that reference to a flow
#endif
} function_data;
#ifdef RECONNECT
#ifdef DIMAPI
int check_network_mapicommd(struct host *h); // checks if network (mapicommd) is up. Returns 1 if network is up, 0 otherwise
void restore_network_mapicommd(struct host *h); // restores the connection to mapicommd in case of a breakdown, using back-off mechanism
void mapi_recreate_flow(struct host *h); // recreates all flows, that host which broke down the connection had created
void mapi_reapply_function(struct host *h); // reapplies all functions, that host which broke down the connection had applyed
void mapi_reconnect(struct host *h); // checks which flows of the specified host, had called mapi_connect() function
#ifdef WITH_AUTHENTICATION
void mapi_reauthenticate(struct host *h); // checks which flows of the specified host, had called mapi_authenticate() function
#endif
void check_mapi_functions(struct host *h); // checks all functions that can be called, when a break down happens
void mapi_get_next_packet(struct host *h); // checks which flows of the specified host, had called mapi_get_next_pkt() function
void mapi_asynchronous_get_next_packet(struct host_flow *hflow); // checks which flows of the specified host, had called mapi_asynchronous_get_next_pkt() function
#endif
void restore_network_mapid(void); // restores the connection to mapid in case of a breakdown, using back-off mechanism
......@@ -295,6 +297,42 @@ int mapiipc_remote_write(struct dmapiipcbuf *dbuf, struct host *h){ // sends an
return 0;
}
int mapiipc_remote_write_asyn(struct dmapiipcbuf *dbuf, struct host_flow *hflow){ // sends an IPC message to mapid
#ifdef DIMAPISSL
#ifdef RECONNECT
if(SSL_write(hflow->con_asyn, dbuf, dbuf->length) <= 0){
printf("WARNING: SSL_write (%s) [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
sem_wait(&(hflow->rhost->connection)); // lock the semaphore
}
#else
if(SSL_write(hflow->con_asyn, dbuf, dbuf->length) <= 0){
printf("WARNING: SSL_write (%s) [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
return -1;
}
#endif
#else
#ifdef RECONNECT
// MSG_NOSIGNAL : requests not to send SIGPIPE on errors on stream oriented sockets when the other end breaks the connection
// need in mapi_get_next_packet()
if(send(hflow->sockfd_asyn, dbuf, dbuf->length, MSG_NOSIGNAL) <= 0){
//printf("send: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
sem_wait(&(hflow->rhost->connection)); // lock the semaphore
}
#else
if(send(hflow->sockfd_asyn, dbuf, dbuf->length, 0) == -1) {
printf("WARNING: send (%s) [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
return -1;
}
#endif
#endif
return 0;
}
int mapiipc_remote_write_to_all(remote_flowdescr_t* rflow)
{
host_flow* hflow;
......@@ -303,6 +341,7 @@ int mapiipc_remote_write_to_all(remote_flowdescr_t* rflow)
for (fnode=flist_head(rflow->host_flowlist); fnode!=NULL; fnode=flist_next(fnode)) {
hflow=(host_flow*)fnode->data;
hflow->dbuf->fd=hflow->fd;
if (mapiipc_remote_write(hflow->dbuf, hflow->rhost)<0) return -1;
}
......@@ -314,6 +353,7 @@ int mapiipc_remote_write_to_all(remote_flowdescr_t* rflow)
}
void cleanup_handler(void *arg){ //the cleanup handler
free(arg);
return;
}
......@@ -330,6 +370,7 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
#ifdef RECONNECT
int check_net;
struct dmapiipcbuf dbuf_;
struct host *host_ = (struct host *)host;
#endif
/* Guarantees that thread resources are deallocated upon return */
......@@ -354,40 +395,50 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
#else
recv_bytes = readn( ((struct host *) host)->sockfd, dbuf, BASIC_SIZE);
#endif
if(recv_bytes == 0){ // the peer has gone
#ifdef RECONNECT
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", ((struct host *)host)->hostname);
check_net = check_network_mapicommd((struct host *) host);
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", host_->hostname);
pthread_mutex_lock(&(host_->rec_lock));
host_->host_down = 1;
check_net = check_network_mapicommd(host_);
if(check_net == 1) // network is up
continue;
else{ // network is down
//printf("\nNetwork down ...\n");
restore_network_mapicommd((struct host *) host);
restore_network_mapicommd(host_);
dbuf_.cmd = IGNORE_SLEEP;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
mapi_recreate_flow((struct host *) host);
mapi_reapply_function((struct host *) host);
mapi_reconnect((struct host *) host);
mapi_recreate_flow(host_);
mapi_reapply_function(host_);
mapi_reconnect(host_);
#ifdef WITH_AUTHENTICATION
mapi_reauthenticate((struct host *) host);
mapi_reauthenticate(host_);
#endif
dbuf_.cmd = IGNORE_NOTIFY;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions((struct host *) host);
mapi_get_next_packet((struct host *) host);
sem_trywait(& ((struct host *) host)->connection); // lock the semaphore only if the semaphore is currently not locked
sem_post(& ((struct host *) host)->connection); // unlock the semaphore
check_mapi_functions(host_);
mapi_get_next_packet(host_);
sem_trywait(&(host_->connection)); // lock the semaphore only if the semaphore is currently not locked
sem_post(&(host_->connection)); // unlock the semaphore
host_->host_down = 0;
if(host_->host_down == 0)
pthread_cond_broadcast(&(host_->rec_condition));
pthread_mutex_unlock(&(host_->rec_lock));
continue;
}
#else
......@@ -398,37 +449,48 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
else if(recv_bytes == -1){
#ifdef RECONNECT
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", ((struct host *)host)->hostname);
check_net = check_network_mapicommd((struct host *) host);
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", host_->hostname);
pthread_mutex_lock(&(host_->rec_lock));
host_->host_down = 1;
check_net = check_network_mapicommd(host_);
if(check_net == 1) // network is up
if(check_net == 1) // network is up
continue;
else{ // network is down
//printf("\nNetwork down ...\n");
restore_network_mapicommd((struct host *) host);
restore_network_mapicommd(host_);
dbuf_.cmd = IGNORE_SLEEP;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
mapi_recreate_flow((struct host *) host);
mapi_reapply_function((struct host *) host);
mapi_reconnect((struct host *) host);
mapi_recreate_flow(host_);
mapi_reapply_function(host_);
mapi_reconnect(host_);
#ifdef WITH_AUTHENTICATION
mapi_reauthenticate((struct host *) host);
mapi_reauthenticate(host_);
#endif
dbuf_.cmd = IGNORE_NOTIFY;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions(host_);
mapi_get_next_packet(host_);
sem_trywait(&(host_->connection)); // lock the semaphore only if the semaphore is currently not locked
sem_post(&(host_->connection)); // unlock the semaphore
host_->host_down = 0;
check_mapi_functions((struct host *) host);
mapi_get_next_packet((struct host *) host);
sem_trywait(& ((struct host *) host)->connection); // lock the semaphore only if the semaphore is currently not locked
sem_post(& ((struct host *) host)->connection); // unlock the semaphore
if(host_->host_down == 0)
pthread_cond_broadcast(&(host_->rec_condition));
pthread_mutex_unlock(&(host_->rec_lock));
continue;
}
#else
......@@ -437,7 +499,7 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
}
if (dbuf->length > DIMAPI_DATA_SIZE) {
printf("Bad IPC message from agent [%s:%d]\n", __FILE__, __LINE__);
printf("Bad IPC message from agent [%s:%d]\n", __FILE__, __LINE__);
continue;
}
......@@ -450,37 +512,48 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
#endif
if(recv_bytes == 0){ // the peer has gone
#ifdef RECONNECT
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", ((struct host *)host)->hostname);
check_net = check_network_mapicommd((struct host *) host);
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", host_->hostname);
pthread_mutex_lock(&(host_->rec_lock));
host_->host_down = 1;
check_net = check_network_mapicommd(host_);
if(check_net == 1) // network is up
continue;
else{ // network is down
//printf("\nNetwork down ...\n");
restore_network_mapicommd((struct host *) host);
restore_network_mapicommd(host_);
dbuf_.cmd = IGNORE_SLEEP;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
mapi_recreate_flow((struct host *) host);
mapi_reapply_function((struct host *) host);
mapi_reconnect((struct host *) host);
mapi_recreate_flow(host_);
mapi_reapply_function(host_);
mapi_reconnect(host_);
#ifdef WITH_AUTHENTICATION
mapi_reauthenticate((struct host *) host);
mapi_reauthenticate(host_);
#endif
dbuf_.cmd = IGNORE_NOTIFY;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions((struct host *) host);
mapi_get_next_packet((struct host *) host);
sem_trywait(& ((struct host *) host)->connection); // lock the semaphore only if the semaphore is currently not locked
sem_post(& ((struct host *) host)->connection); // unlock the semaphore
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions(host_);
mapi_get_next_packet(host_);
sem_trywait(&(host_->connection)); // lock the semaphore only if the semaphore is currently not locked
sem_post(&(host_->connection)); // unlock the semaphore
host_->host_down = 0;
if(host_->host_down == 0)
pthread_cond_broadcast(&(host_->rec_condition));
pthread_mutex_unlock(&(host_->rec_lock));
continue;
}
#else
......@@ -490,38 +563,49 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
}
else if(recv_bytes == -1){
#ifdef RECONNECT
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", ((struct host *)host)->hostname);
check_net = check_network_mapicommd((struct host *) host);
#ifdef RECONNECT
//printf("\n\t---> Mapicommd is down. Socket closed from host: %s\n", host_->hostname);
pthread_mutex_lock(&(host_->rec_lock));
host_->host_down = 1;
check_net = check_network_mapicommd(host_);
if(check_net == 1) // network is up
continue;
else{ // network is down
//printf("\nNetwork down ...\n");
restore_network_mapicommd((struct host *) host);
restore_network_mapicommd(host_);
dbuf_.cmd = IGNORE_SLEEP;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
mapi_recreate_flow((struct host *) host);
mapi_reapply_function((struct host *) host);
mapi_reconnect((struct host *) host);
mapi_recreate_flow(host_);
mapi_reapply_function(host_);
mapi_reconnect(host_);
#ifdef WITH_AUTHENTICATION
mapi_reauthenticate((struct host *) host);
mapi_reauthenticate(host_);
#endif
dbuf_.cmd = IGNORE_NOTIFY;
dbuf_.length = BASIC_SIZE;
if(mapiipc_remote_write(&dbuf_, (struct host *) host) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions((struct host *) host);
mapi_get_next_packet((struct host *) host);
sem_trywait(& ((struct host *) host)->connection); // lock the semaphore only if the semaphore is currently not locked
sem_post(& ((struct host *) host)->connection); // unlock the semaphore
if(mapiipc_remote_write(&dbuf_, host_) < 0) // send an IPC message to mapicommd
break;
check_mapi_functions(host_);
mapi_get_next_packet(host_);
sem_trywait(&(host_->connection)); // lock the semaphore only if the semaphore is currently not locked
sem_post(&(host_->connection)); // unlock the semaphore
host_->host_down = 0;
if(host_->host_down == 0)
pthread_cond_broadcast(&(host_->rec_condition));
pthread_mutex_unlock(&(host_->rec_lock));
continue;
}
#else
......@@ -598,6 +682,163 @@ void *mapiipc_comm_thread(void *host){ // reads an IPC message - blocking call
return NULL;
}
// A separate thread for mapi_asynchronous_get_next_pkt() function
void *mapiipc_asyn_comm_thread(void *hflow_){
struct dmapiipcbuf *dbuf;
struct host *host;
remote_flowdescr_t *rflow;
host_flow *hflow, *temp_hflow;
int recv_bytes, index;
/* Guarantees that thread resources are deallocated upon return */
pthread_detach(pthread_self());
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); // enable cancellation
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // changes the type of responses to cancellation requests for the calling thread
// asynchronous (cancel the calling thread as soon as the cancellation request is received)
dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
pthread_cleanup_push(cleanup_handler, dbuf);
temp_hflow = (struct host_flow *)hflow_;
host = (struct host *)temp_hflow->rhost;
while(1){
if(host == NULL) break;
#ifdef DIMAPISSL
recv_bytes = SSL_readn( ((struct host_flow *) hflow_)->con_asyn, dbuf, BASIC_SIZE);
#else
recv_bytes = readn( ((struct host_flow *) hflow_)->sockfd_asyn, dbuf, BASIC_SIZE);
#endif
if(recv_bytes == 0){ // the peer has gone
#ifdef RECONNECT
pthread_mutex_lock(&(host->rec_lock));
while(host->host_down == 1)
pthread_cond_wait(&(host->rec_condition), &(host->rec_lock));
pthread_mutex_unlock(&(host->rec_lock));
mapiipc_remote_close_asyn(temp_hflow); // release previous socket resources
mapiipc_remote_init_asyn(host, temp_hflow); // initializes IPC for DiMAPI functions
mapi_asynchronous_get_next_packet(temp_hflow);
sem_trywait(&host->connection);
sem_post(&host->connection);
continue;
#else
break;
#endif
}
else if(recv_bytes == -1){
#ifdef RECONNECT
pthread_mutex_lock(&(host->rec_lock));
while(host->host_down == 1)
pthread_cond_wait(&(host->rec_condition), &(host->rec_lock));
pthread_mutex_unlock(&(host->rec_lock));
mapiipc_remote_close_asyn(temp_hflow); // release previous socket resources
mapiipc_remote_init_asyn(host, temp_hflow); // initializes IPC for DiMAPI functions
mapi_asynchronous_get_next_packet(temp_hflow);
sem_trywait(&host->connection);
sem_post(&host->connection);
continue;
#else
continue;
#endif
}
if(dbuf->length > DIMAPI_DATA_SIZE){
printf("Bad IPC message from agent [%s:%d]\n", __FILE__, __LINE__);
continue;
}
if (dbuf->length - BASIC_SIZE>0) {
#ifdef DIMAPISSL
recv_bytes = SSL_readn( ((struct host_flow *) hflow_)->con_asyn, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE );
#else
recv_bytes = readn( ((struct host_flow *) hflow_)->sockfd_asyn, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE);
#endif
if(recv_bytes == 0){ // the peer has gone
#ifdef RECONNECT
pthread_mutex_lock(&(host->rec_lock));
while(host->host_down == 1)
pthread_cond_wait(&(host->rec_condition), &(host->rec_lock));
pthread_mutex_unlock(&(host->rec_lock));
mapiipc_remote_close_asyn(temp_hflow); // release previous socket resources
mapiipc_remote_init_asyn(host, temp_hflow); // initializes IPC for DiMAPI functions
mapi_asynchronous_get_next_packet(temp_hflow);
sem_trywait(&host->connection);
sem_post(&host->connection);
continue;
#else
break;
#endif
}
else if(recv_bytes == -1){
#ifdef RECONNECT
pthread_mutex_lock(&(host->rec_lock));
while(host->host_down == 1)
pthread_cond_wait(&(host->rec_condition), &(host->rec_lock));
pthread_mutex_unlock(&(host->rec_lock));
mapiipc_remote_close_asyn(temp_hflow); // release previous socket resources
mapiipc_remote_init_asyn(host, temp_hflow); // initializes IPC for DiMAPI functions
mapi_asynchronous_get_next_packet(temp_hflow);
sem_trywait(&host->connection);
sem_post(&host->connection);
continue;
#else
continue;
#endif
}
}
hflow = (host_flow *)flist_get(host->flows, dbuf->fd);
if(hflow != NULL){
rflow = flist_get(remote_flowlist, hflow->scope_fd);
if(dbuf->cmd == GET_NEXT_PKT_ASYN_ACK){
pthread_spin_lock(&(hflow->asyn_get_next_pkt_lock));
index = hflow->asyn_pkts->write; // where to write the new packet ???
hflow->asyn_pkts->write++;
hflow->asyn_pkts->size++;
pthread_spin_unlock(&(hflow->asyn_get_next_pkt_lock));
if(dbuf->length == BASIC_SIZE) // need for non-blocking way of reading packets
hflow->asyn_pkts->pkts[index]->caplen = 0;
memcpy(hflow->asyn_pkts->pkts[index], dbuf->data, dbuf->length - BASIC_SIZE);
sem_post(&rflow->pkt_sem);
}
}
else{
printf("Invalid IPC message, unknown fd %d [%s:%d]\n", dbuf->fd, __FILE__, __LINE__);
continue;
}
}
pthread_cleanup_pop(1); // pthread_cleanup_pop() function shall remove the routine at the top of the
// calling thread's cancellation cleanup stack and invoke it
return NULL;
}
int mapiipc_remote_init(struct host *h)
//Initializes IPC for dmapi functions
{
......@@ -608,11 +849,11 @@ int mapiipc_remote_init(struct host *h)
SSL_library_init(); // registers the available ciphers and digests
SSL_load_error_strings(); // registers the error strings for all libcrypto functions and libssl
if ((ctx=SSL_CTX_new(SSLv3_client_method())) == NULL) {
if ((h->ctx=SSL_CTX_new(SSLv3_client_method())) == NULL) {
ERR_print_errors_fp(stderr);
return -1;
}
if ((h->con = SSL_new(ctx)) == NULL) {
if ((h->con = SSL_new(h->ctx)) == NULL) {
ERR_print_errors_fp(stderr);
return -1;
}
......@@ -667,6 +908,69 @@ int mapiipc_remote_init(struct host *h)
}
int mapiipc_remote_init_asyn(struct host *h, struct host_flow *hflow){
struct hostent *host = gethostbyname(h->hostname);
struct timeval tv;
if(host == NULL){
printf("ERROR: Could not determine address for host %s [%s:%d]\n", h->hostname, __FILE__, __LINE__);
return -1;
}
#ifdef DIMAPISSL
if( (hflow->ctx_asyn = SSL_CTX_new(SSLv3_client_method())) == NULL){
ERR_print_errors_fp(stderr);
return -1;
}
if( (hflow->con_asyn = SSL_new(hflow->ctx_asyn)) == NULL){
ERR_print_errors_fp(stderr);
return -1;
}
signal(SIGPIPE, sigpipe_handle); // catch SIGPIPE signal (SSL_write), in case of reconnection ...
#endif