Commit 1171cd31 authored by 's avatar

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){
......
This diff is collapsed.
......@@ -30,6 +30,10 @@
#define MAPIDGSOCKHOME "%s/.mapid%d.sock"
#define MAPIDGSOCKGLOBAL "/tmp/mapid%d.sock"
#define ASYN_GNP_BUFFER_SIZE 500 // buffer size for mapi_asynchronous_get_next_pkt() function
#define MAX_CAPLEN 1540U
#define ASYN_GNP_THRESHOLD 0.1
//All IPC code needs to be rewritten and cleand up.
//To support dynamic loading of new functions we should have an IPC
//system that do not need to be changed for each new function type
......@@ -96,6 +100,8 @@ typedef enum {
SEND_FD,
GET_NEXT_PKT,
GET_NEXT_PKT_ACK,
GET_NEXT_PKT_ASYN,
GET_NEXT_PKT_ASYN_ACK,
IGNORE_SLEEP, // start reconnection ...
IGNORE_NOTIFY,
READ_RESULT_ACK_RECONNECT, // end reconnection ...
......@@ -141,7 +147,6 @@ int mapiipc_write(struct mapiipcbuf *qbuf);
//Reads an IPC message. Blocking call.
int mapiipc_read(struct mapiipcbuf *qbuf);
//Send a file handle
int mapiipc_send_fd(int sendfd);
//receive a file handle
......@@ -159,6 +164,7 @@ struct host {
int sockfd;
#ifdef DIMAPISSL
SSL *con;
SSL_CTX *ctx;
#endif
int num_flows; // to know when to close the socket
flist_t *flows;
......@@ -166,6 +172,9 @@ struct host {
pthread_t* comm_thread; // communication thread
#ifdef RECONNECT
sem_t connection; // use it in mapiipc.c source code file
pthread_mutex_t rec_lock;
pthread_cond_t rec_condition;
int host_down;
#endif
flist_t *stats; //for mapi_stats
};
......@@ -181,7 +190,7 @@ struct dmapiipcbuf {
};
#define BASIC_SIZE (sizeof(struct dmapiipcbuf) - DIMAPI_DATA_SIZE)
#define PKT_LENGTH 131072 //pkt info and actual pkt
#define PKT_LENGTH 131072 // pkt info and actual pkt
typedef struct host_flow {
struct host *rhost;
......@@ -189,8 +198,16 @@ typedef struct host_flow {
int scope_fd;
int fd; //fd of flow in the mapid of host
int id;
int sockfd_asyn;
#ifdef DIMAPISSL
SSL *con_asyn;
SSL_CTX *ctx_asyn;
#endif
pthread_t* asyn_comm_thread;
struct dmapiipcbuf *dbuf; //buffer for writting results from this host -for this flow-
struct mapipkt* pkt;
struct asyn_mgnp_buffer *asyn_pkts; // used by mapi_asynchronous_get_next_pkt()
pthread_spinlock_t asyn_get_next_pkt_lock; // used by mapi_asynchronous_get_next_pkt()
flist_t *functions; //holds all fids for this host_flow
} host_flow;
......@@ -212,19 +229,43 @@ typedef struct remote_flowdescr {
#endif
#endif
#ifdef RECONNECT
int to_buffer_fid; // fid returned to user, in response to to_buffer() function apply
int to_buffer_fid; // fid returned to user, in response to to_buffer() function apply [used by mapi_get_next_pkt()]
int to_buffer_fid_asyn; // fid returned to user, in response to to_buffer() function apply [used by mapi_asynchronous_get_next_pkt()]
int daemons_down;
#endif
struct mapipkt* pkt;
unsigned char is_asyn_gnp_called; // this should be 1 if the remote flow has called mapi_asynchronous_get_next_pkt(), 0 otherwise
flist_node_t *asyn_mgnp_fnode; // the last host that returned a packet to a client
} remote_flowdescr_t;
struct asyn_mgnp{ // used by mapi_asynchronous_get_next_pkt()
struct dmapiipcbuf *dbuf;
int sock;
int sent_packets;
#ifdef DIMAPISSL
SSL *con;
#endif
};
struct asyn_mgnp_buffer{ // used by mapi_asynchronous_get_next_pkt() function
struct mapipkt **pkts; // buffer for saving packets
int read; // index for read packet
int write; // index for write packet
int size; // the amount of packets that are stored in the buffer
};
//dmapi functions and ipcbuffer
int mapiipc_remote_init(struct host *h);
int mapiipc_remote_init_asyn(struct host *h, struct host_flow *hflow);
int mapiipc_remote_write(struct dmapiipcbuf *dbuf, struct host *h);
int mapiipc_remote_write_asyn(struct dmapiipcbuf *dbuf, struct host_flow *hflow);
int mapiipc_remote_write_to_all(remote_flowdescr_t* rflow);
void mapiipc_remote_close(struct host *h);
void mapiipc_remote_close_asyn(struct host_flow *hflow);
void *mapiipc_comm_thread(void *host);
void *mapiipc_asyn_comm_thread(void *host);
/* Read "n" bytes from a socket. */
ssize_t readn(int fd, void *vptr, size_t n);
......@@ -239,7 +280,6 @@ void check_for_read_results(struct host *h);
int check_network_mapid(void); // checks if network (mapid) is up. Returns 1 if network is up, 0 otherwise
#endif
#define INT 1
#define STRING 2
#define UNSIGNED_LONG_LONG 3
......
This diff is collapsed.
......@@ -198,11 +198,13 @@ extern int mapi_connect(int fd);
//Get the next packet from a to_buffer function
extern struct mapipkt *mapi_get_next_pkt(int fd,int fid);
//Get the next packet from a to_buffer function, using asynchronous mechanism - PUSH MODEL (only for DiMAPI)
extern struct mapipkt *mapi_asynchronous_get_next_pkt(int fd, int fid);
//Apply a callback function to all packets in to_buffer (mapi_loop is blocking!!!)
extern int mapi_loop(int fd, int fid, int cnt, mapi_handler);
//Read result from a function
//This should be changed to:
extern mapi_results_t* mapi_read_results(int fd, int fid);
//Close a mapi flow
......
......@@ -15,6 +15,7 @@
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include "mapi.h"
#include "mapiipc.h"
#include "parseconf.h"
......@@ -34,12 +35,15 @@ int log_fd_info = -1; // support for logging to file
static char daemonize = 0;
#ifdef DIMAPISSL
void signal_pipe_handle();
struct overload *inst = NULL;
SSL_CTX *ctx;
#endif
extern void set_agent();
void *handle_request(void *);
void *asyn_get_next_pkt(void *); // function that is executed from asynchronous get_next_packet thread
int die(char *msg);
int getfid(struct dmapiipcbuf *dbuf);
void mapicommd_shutdown(int exit_value);
......@@ -218,6 +222,8 @@ int main (int argc, char *argv[]){
ERR_print_errors_fp(stderr);
return -1;
}
signal(SIGPIPE, signal_pipe_handle); // catch SIGPIPE signal (SSL_write)
#endif
/* DANGEROUS, but useful for debugging, so leave it for now */
......@@ -287,7 +293,10 @@ int main (int argc, char *argv[]){
continue;
}
#else
if (pthread_create(&chld_thr, NULL, handle_request, (void *) &new_sock) != 0) {
int *sockfd = (int *)malloc(sizeof(int));
*sockfd = new_sock; // FIXME free ...
if (pthread_create(&chld_thr, NULL, handle_request, (void *) sockfd) != 0) {
die("pthread_create() failed");
continue;
}
......@@ -297,6 +306,7 @@ int main (int argc, char *argv[]){
}
void *handle_request(void *arg) {
#ifdef DIMAPISSL
SSL *con ;
con = ((struct overload*)arg)->connection;
......@@ -304,29 +314,23 @@ void *handle_request(void *arg) {
#else
int sock = *(int *)arg;
#endif
int recv_bytes;
int recv_bytes, i, ac_fl_size=0, errno, *active_flows = NULL, mapid_result;
char errorstr[MAPI_ERRORSTR_LENGTH], str[30], *dev;
long file_size;
struct asyn_mgnp *gnp_arg = NULL;
struct dmapiipcbuf *dbuf=NULL;
int mapid_result;
struct timeval tv; /*used for timestamping results when produced */
struct mapipkt *pkt;
struct mapi_stat stats;
mapi_results_t *result;
int i;
int *active_flows = NULL;
int ac_fl_size=0;
mapi_function_info_t funct_info;
mapi_flow_info_t flow_info;
mapi_device_info_t device_info;
struct timeval tv; /*used for timestamping results when produced */
struct mapipkt *pkt;
int errno;
char errorstr[MAPI_ERRORSTR_LENGTH], str[30];
long file_size;
struct mapi_stat stats;
char* dev;
#ifdef RECONNECT
int flag = 0;
int ignore_flag = 0;
#endif
/* Guarantees that thread resources are deallocated upon return */
pthread_detach(pthread_self());
pthread_detach(pthread_self()); // Guarantees that thread resources are deallocated upon return
dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
#ifdef DIMAPISSL
......@@ -343,11 +347,11 @@ void *handle_request(void *arg) {
#endif
if(log_to_file){
file_size = acquire_write_lock(log_fd_info);
write_to_file(log_fd_info, "MAPICOMMD: new thread %lu, socket number %s\n\n", pthread_self(), str);
write_to_file(log_fd_info, "MAPICOMMD: new thread %lu, socket number %s\n", pthread_self(), str);
release_write_lock(log_fd_info, file_size);
}
while(1) {
while(1){
#ifdef DIMAPISSL
recv_bytes = SSL_readn(con,dbuf,BASIC_SIZE);
......@@ -408,16 +412,16 @@ void *handle_request(void *arg) {
#ifdef RECONNECT
if(dbuf->cmd == IGNORE_SLEEP){ // ignore some messages
flag = 1;
ignore_flag = 1;
continue;
}
if(dbuf->cmd == IGNORE_NOTIFY){ // accept all kind of messages
flag = 0;
ignore_flag = 0;
continue;
}
if(dbuf->cmd != CREATE_FLOW && dbuf->cmd != APPLY_FUNCTION && dbuf->cmd != CONNECT && dbuf->cmd != AUTHENTICATE && flag == 1)
if(dbuf->cmd != CREATE_FLOW && dbuf->cmd != APPLY_FUNCTION && dbuf->cmd != CONNECT && dbuf->cmd != AUTHENTICATE && ignore_flag == 1)
continue;
#endif
switch(dbuf->cmd) {
......@@ -538,7 +542,7 @@ void *handle_request(void *arg) {
pkt = (struct mapipkt *)mapi_get_next_pkt(dbuf->fd,dbuf->fid);
gettimeofday(&tv, NULL);
dbuf->timestamp = tv.tv_usec;
if(pkt!=NULL){
if(pkt != NULL && pkt->caplen <= MAX_CAPLEN){
dbuf->cmd = GET_NEXT_PKT_ACK;
memcpy(dbuf->data, pkt, sizeof(struct mapipkt)-4+pkt->caplen);
dbuf->length = BASIC_SIZE + sizeof(struct mapipkt) - 4 + pkt->caplen;
......@@ -548,6 +552,26 @@ void *handle_request(void *arg) {
dbuf->length = BASIC_SIZE;
}
break;
case GET_NEXT_PKT_ASYN:
fprintf(stdout, "Asynchronous mapi_get_next_pkt\n");
mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
gnp_arg = (struct asyn_mgnp *)malloc(sizeof(struct asyn_mgnp));
gnp_arg->dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
memcpy(gnp_arg->dbuf, dbuf, dbuf->length);
// counts the number of sent packets, before the thread enters sleep mode. If sent_packets becomes equal
// to the number of empty cells in the buffer array, then the thread enters sleep mode, waiting for a next request
gnp_arg->sent_packets = 0;
#ifdef DIMAPISSL
gnp_arg->con = (SSL *)malloc(sizeof(SSL));
memcpy(gnp_arg->con, con, sizeof(SSL));
#else
memcpy(&(gnp_arg->sock), &sock, sizeof(int));
#endif
asyn_get_next_pkt(gnp_arg);
break;
case GET_FLOW_INFO:
fprintf(stdout,"GET_FLOW_INFO\n");
if(mapi_get_flow_info(dbuf->fd, &flow_info)){
......@@ -694,7 +718,7 @@ void *handle_request(void *arg) {
}
//no need to send responce on mapi_close_flow
if (dbuf->cmd!=CLOSE_FLOW) {
if(dbuf->cmd!=CLOSE_FLOW && dbuf->cmd != GET_NEXT_PKT_ASYN){
#ifdef DIMAPISSL
SSL_write(con,dbuf,dbuf->length);
#else
......@@ -708,6 +732,7 @@ void *handle_request(void *arg) {
mapi_close_flow(active_flows[i]);
}
}
free(active_flows);
free(dbuf);
dbuf = NULL;
......@@ -721,10 +746,8 @@ void *handle_request(void *arg) {
SSL_free(con); // decrements the reference count of ssl, and removes the SSL structure pointed to by ssl
// frees up the allocated memory if the the reference count has reached 0
#endif
/* update the global service counter */
service_count++;
#endif
service_count++; // update the global service counter
DEBUG_CMD(Debug_Message("<+> thread %lu exiting", pthread_self()));
DEBUG_CMD(Debug_Message("<+> total sockets served: %d", service_count));
......@@ -735,8 +758,89 @@ void *handle_request(void *arg) {
write_to_file(log_fd_info, "\nMAPICOMMD: Total sockets served: %d\n", service_count);
release_write_lock(log_fd_info, file_size);
}
pthread_exit((void *)0);
pthread_exit((void *) 0);
}
void *asyn_get_next_pkt(void *buf){
struct dmapiipcbuf *dbuf = NULL;
struct asyn_mgnp *gnp_arg = NULL;
struct mapipkt *pkt;
struct timeval tv; // used for timestamping results when produced
char errorstr[MAPI_ERRORSTR_LENGTH];
int recv_bytes;
gnp_arg = (struct asyn_mgnp *)buf;
dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
while(1){
pkt = (struct mapipkt *)mapi_asynchronous_get_next_pkt(gnp_arg->dbuf->fd, gnp_arg->dbuf->fid);
gettimeofday(&tv, NULL);
dbuf->timestamp = tv.tv_usec;
if(pkt != NULL && pkt->caplen <= MAX_CAPLEN){
dbuf->cmd = GET_NEXT_PKT_ASYN_ACK;
dbuf->fd = gnp_arg->dbuf->fd;
memcpy(dbuf->data, pkt, sizeof(struct mapipkt) - 4 + pkt->caplen);
dbuf->length = BASIC_SIZE + sizeof(struct mapipkt) - 4 + pkt->caplen;
}
else{ // 'NULL' packet ... probably from a non-blocking way of reading packets
dbuf->cmd = GET_NEXT_PKT_ASYN_ACK;
mapi_read_error(&errno, errorstr);
dbuf->fd = gnp_arg->dbuf->fd;
dbuf->length = BASIC_SIZE;
//if(errno != MAPI_INVALID_FLOW){
// DEBUG_CMD(Debug_Message("mapi_asynchronous_get_next_pkt failed"));
//}
if(errno == MAPI_INVALID_FLOW) // flow with fd 'gnp_arg->dbuf->fd' is closed ...
break;
}
#ifdef DIMAPISSL
SSL_write(gnp_arg->con, dbuf, dbuf->length);
#else
if(send(gnp_arg->sock, dbuf, dbuf->length, MSG_NOSIGNAL) == -1)
break;
#endif
gnp_arg->sent_packets++;
if(gnp_arg->sent_packets == (int) gnp_arg->dbuf->timestamp){ // buffer is full
#ifdef DIMAPISSL
recv_bytes = SSL_readn(gnp_arg->con, dbuf, BASIC_SIZE);
#else
recv_bytes = readn(gnp_arg->sock, dbuf, BASIC_SIZE);
#endif
if(dbuf->length - BASIC_SIZE > 0){
#ifdef DIMAPISSL
recv_bytes = SSL_readn(gnp_arg->con, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE);
#else
recv_bytes = readn(gnp_arg->sock, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE);
#endif
}
gnp_arg->dbuf->timestamp = dbuf->timestamp; // number of packets that must be sent
gnp_arg->sent_packets = 0; // initialize again
}
}
DEBUG_CMD(Debug_Message("<++> thread %lu exiting", pthread_self()));
free(dbuf);
dbuf = NULL;
free(gnp_arg->dbuf);
#ifdef DIMAPISSL
free(gnp_arg->con);
#endif
free(gnp_arg);
gnp_arg = NULL;
pthread_exit(NULL);
return NULL;
}
int die(char *msg){
......@@ -776,15 +880,23 @@ void mapicommd_shutdown(int exit_value){
ERR_remove_state(0); // the current thread will have its error queue removed
EVP_cleanup(); // removes all ciphers and digests from the table
#endif
if(log_to_file){
if(log_to_file){
daemon_terminated(log_fd_info, "MAPICOMMD", daemonize, 0);
daemon_terminated(log_fd_debug, "MAPICOMMD", daemonize, 0);
}
if(log_to_syslog)
log_message("MAPICOMMD was terminated %s", daemonize ? " ( was running as daemon )" : "");
exit(exit_value);
}
#ifdef DIMAPISSL
void signal_pipe_handle(){ // catch the signal - SIGPIPE
DEBUG_CMD(Debug_Message("Broken pipe (signal handler)"));
DEBUG_CMD(Debug_Message("<++> thread %lu exiting", pthread_self()));
pthread_exit(NULL);
return;
}
#endif
#include <stdio.h>
#include <unistd.h>
#include <mapi.h>
#include "test.h"
int main(int argc, char *argv[]){
int fd, fid, err_no = 0, flag = 0, i;
struct mapipkt *pkt;
char error[512];
if(argc!=2){
printf("\nWrong arguments\n");
return -1;
}
if( (fd = mapi_create_flow(argv[1])) < 0){
fprintf(stderr, "Could not create flow using '%s'\n", argv[1]);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if( (fid = mapi_apply_function(fd, "TO_BUFFER", WAIT)) < 0){
fprintf(stderr, "Could not apply TO_BUFFER to flow %d\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s \n", err_no, error);
return -1;
}
DOT;
if(mapi_connect(fd) < 0){
fprintf(stderr, "Connecting to flow %d failed\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
// Sanity check
if( (pkt = mapi_asynchronous_get_next_pkt(fd, fid)) != NULL)
printf("Got a packet\n");
else
printf("\nError in mapi_asynchronous_get_next_packet\n");
if(mapi_close_flow(fd) < 0){
fprintf(stderr, "Close flow failed\n");
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
// Non-blocking buffer test
if( (fd = mapi_create_flow(argv[1])) < 0){
fprintf(stderr, "Could not create flow using '%s'\n", argv[1]);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if( (fid = mapi_apply_function(fd, "TO_BUFFER", NOWAIT)) < 0){
fprintf(stderr, "Could not apply TO_BUFFER to flow %d\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if(mapi_connect(fd) < 0){
fprintf(stderr, "Connecting to flow failed %d\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
// Sanity check
printf("<+> Non-blocking buffer test ...\n");
for(i = 0; i < 50; i++){
if( (pkt = mapi_asynchronous_get_next_pkt(fd, fid)) != NULL)
printf("Got packet #%d\n", i + 1);
else
printf("No packet\n");
usleep(200000); // 0.2 seconds
}
if(mapi_close_flow(fd) < 0){
fprintf(stderr, "Close flow failed\n");
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
// Blocking buffer test
if( (fd = mapi_create_flow(argv[1])) < 0){
fprintf(stderr, "Could not create flow using '%s'\n", argv[1]);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if( (fid = mapi_apply_function(fd, "TO_BUFFER", WAIT)) < 0){
fprintf(stderr, "Could not apply TO_BUFFER to flow %d\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if(mapi_connect(fd) < 0){
fprintf(stderr, "Connecting to flow failed %d\n", fd);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
// Sanity check
printf("<+> Blocking buffer test ...\n");
for(i = 0; i < 50; i++){
if( (pkt = mapi_asynchronous_get_next_pkt(fd, fid)) != NULL)
printf("Got packet #%d\n", i + 1);
else
printf("No packet\n");
usleep(200000); // 0.2 seconds
}
if(mapi_close_flow(fd) < 0){
fprintf(stderr, "Close flow failed\n");
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
printf("\nmapi_asynchornous_get_next_packet OK\n\n");
// Error reporting checking
fd = 0;
if(mapi_asynchronous_get_next_pkt(fd , fid) == NULL){
mapi_read_error(&err_no, error);
printf("Testing error case1: Errorcode: %d description: %s\n", err_no, error);
if(err_no != 6147){
printf("Wrong ERRORCODE returned\n");
flag = 1;
}
}
DOT;
if( (fd = mapi_create_flow(argv[1])) < 0){
fprintf(stderr, "Could not create flow using '%s'\n", argv[1]);
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if(mapi_asynchronous_get_next_pkt(fd, fid) == NULL){
mapi_read_error(&err_no, error);
printf("Testing error case2: Errorcode: %d description: %s \n\n", err_no, error);
if(err_no != 6143){
printf("Wrong ERRORCODE returned\n");
flag = 1;
}
}
DOT;
if(mapi_close_flow(fd) < 0){
fprintf(stderr, "Close flow failed\n");
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode: %d description: %s\n", err_no, error);
return -1;
}
DOT;
if(!flag)
printf("\nAsynchronous Get Next Packet Error Checking OK !!!\n");
else
printf("\nAsynchronous Get Next Packet Error Checking FAILED ...\n");
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment