From 010e33b556719cf3ca51a9a71d989907dfc002dd Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 26 Feb 2013 13:05:38 +0530 Subject: [PATCH 01/18] First commit of NDMP server in the new file structure organization. comm currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. utils contains the necessary utilities for communication (as of now). Queues are implemented here. Locks are used to make queues thread-safe. --- comm/src/comm.c | 283 +++++++++++++++++++++++++++++++++++ comm/src/comm.h | 58 +++++++ comm/src/test/makefile | 27 ++++ comm/src/test/testcomm.c | 12 ++ comm/src/worker.c | 76 ++++++++++ comm/src/worker.h | 15 ++ utils/src/hexdump.c | 63 ++++++++ utils/src/hexdump.h | 14 ++ utils/src/locks.c | 25 ++++ utils/src/locks.h | 14 ++ utils/src/queue.c | 142 ++++++++++++++++++ utils/src/queue.h | 34 +++++ utils/src/test/makefile | 21 +++ utils/src/test/mtestq.c | 134 +++++++++++++++++ utils/src/test/testhexdump.c | 10 ++ utils/src/test/testq.c | 87 +++++++++++ 16 files changed, 1015 insertions(+) create mode 100644 comm/src/comm.c create mode 100644 comm/src/comm.h create mode 100644 comm/src/test/makefile create mode 100644 comm/src/test/testcomm.c create mode 100644 comm/src/worker.c create mode 100644 comm/src/worker.h create mode 100644 utils/src/hexdump.c create mode 100644 utils/src/hexdump.h create mode 100644 utils/src/locks.c create mode 100644 utils/src/locks.h create mode 100644 utils/src/queue.c create mode 100644 utils/src/queue.h create mode 100644 utils/src/test/makefile create mode 100644 utils/src/test/mtestq.c create mode 100644 utils/src/test/testhexdump.c create mode 100644 utils/src/test/testq.c diff --git a/comm/src/comm.c b/comm/src/comm.c new file mode 100644 index 0000000..9f55f7a --- /dev/null +++ b/comm/src/comm.c @@ -0,0 +1,283 @@ +/* + * Copyright place holder +*/ + +#include +#include + +/* + * comm_int: + * Creates a comm_context structure + * which is the anchor structure that + * holds the session structures for all + * active sessions + */ + + +int session_comparator(void *target, void *elem); +void handle_client_requests(fd_set *read_socks, struct comm_context *ctx); +void handle_a_client_request(int fd, struct comm_context *ctx); + +struct comm_context* comm_context() { + static struct comm_context *retval = NULL; + if (retval == NULL) { + retval = calloc(1,sizeof(struct comm_context)); + init_queue(); + retval->sessions = malloc(sizeof(struct queue_hdr)); + retval->client_jobs = malloc(sizeof(struct queue_hdr)); + } + return retval; +} + + +/* + * + * create_listener + * creates a listener socket to listen on specified port and + * returns the socket to the caller + * + * NOTE: THIS CREATES A IPV4 LISTENER + * FOR IPV6, a similar function + * can be written for the caller + * + * + */ + +int create_listener(int port) { + + int retval; /* return the socket the listener should listen on */ + struct sockaddr_in listener; + int reuse = 1; + + listener.sin_family = AF_INET; + listener.sin_addr.s_addr = INADDR_ANY; + listener.sin_port = htons(port); + + /* now create a socket and bind to listener */ + retval = socket(AF_INET, SOCK_STREAM, 0); + + setsockopt(retval, SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int)); + fcntl(retval, F_SETFL, O_NONBLOCK); + if (bind(retval, (struct sockaddr *)&listener, + sizeof(struct sockaddr_in)) == -1) + errExit("Error:bind"); + + return retval; + +} + +struct client_endpoint accept_connection(int listener) { + + struct sockaddr_in client; + socklen_t len; + int sockfd; + struct client_endpoint retval; + + retval.fd = -1; + printf("Accepting new connection ..\n"); + sockfd = accept(listener, (struct sockaddr *)&client, + &len); + if (sockfd< 0) { + printf("Oops! Cannot accept new connection :( \n"); + return retval; + } + + fcntl(sockfd, F_SETFL, O_NONBLOCK); + retval.client = client; + retval.fd = sockfd; + + printf("Accepted new connection ..\n"); + return retval; +} + + +/* + * set_fd_flags sets all the sockets + * that we want to multiplex on fd_set + */ + + +void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) +{ + + struct session **active_sessions; + int n,i; + FD_ZERO(fds); + FD_SET(listener, fds); + + active_sessions = (struct session **) get_all_elems(ctx->sessions); + n = num_elems(ctx->sessions); + for (i=0; isession_id, fds); + } +} + + +/* + * comm_listen: + * comm_listen listens on a socket at the address + * specified by LISTEN_PORT + * + * We separate creation of listener from listening + * so that support for IPV6 can be provided by + * creating a IPV6 listener and rest of logic should, + * hopefully, be invariant. + * + * When a connect request is received, a session is + * created and the session is added to the list of + * active sessions. + * + */ + +void comm_listen(struct comm_context *ctx) { + + fd_set read_socks; + int listener = create_listener(LISTEN_PORT); + struct client_endpoint endpoint; + struct client_endpoint *temp; + int ready; + int new_connections; + + FD_ZERO(&read_socks); + + listener = create_listener(LISTEN_PORT); + listen(listener, NUM_SESSIONS); + + printf ("Listening on port %d....\n", LISTEN_PORT); + /* + * add listening socket to read_socks + * for multiplexing listening as well + */ + FD_SET(listener, &read_socks); + ctx->maxfds = listener; + + /* Create Worker Threads */ +// create_worker_threads(THREAD_POOL_SIZE); + /* when the listener wakes up create a session */ + + for (;;) { + printf("Wait on select \n"); + set_fd_flags(&read_socks,listener,ctx); + ready = select((ctx->maxfds)+1, &read_socks, NULL, NULL, NULL); + printf("Woke up from select \n"); + if (ready != -1) { + if (FD_ISSET(listener, &read_socks)) { + new_connections = accept_all_connections( + listener, + &read_socks,ctx); + printf("%d new connection(s) \n", + new_connections); + } + else { + /* + * Some client session is active + */ + handle_client_requests(&read_socks,ctx); + } + } + + } + +} + + +int accept_all_connections(int listener, fd_set *read_socks, + struct comm_context *ctx) +{ + struct client_endpoint endpoint; + struct session* new_session; + + int num_new_sessions = 0; + +// do { + endpoint = accept_connection(listener); + if (endpoint.fd != -1) { + /* + * Add new connection to session queue + * in comm_context + */ + + new_session = (struct session*)malloc( + sizeof(struct session)); + new_session->session_id = endpoint.fd; + new_session->client_info = endpoint; + enqueue(ctx->sessions,new_session); + /* + * add to select list of sockets + */ + FD_SET(endpoint.fd, read_socks); + if (endpoint.fd > ctx->maxfds) { + ctx->maxfds = endpoint.fd; + } + + printf("Connection request from %s at %d\n", + inet_ntoa(endpoint.client.sin_addr), + ntohs(endpoint.client.sin_port)); + num_new_sessions++; + } +// } while (endpoint.fd != -1); + + return num_new_sessions; +} + +void handle_client_requests(fd_set *read_socks, struct comm_context *ctx) +{ + + int i; + for (i=0; i<=ctx->maxfds; i++) { + printf("Checking for event on sock %d\n", i); + if (FD_ISSET(i,read_socks)) { + handle_a_client_request(i,ctx); + } + } +} + +/* + * create a new transaction for the new request received + */ + +void handle_a_client_request(int fd, struct comm_context *ctx) +{ + struct session tmp; + tmp.session_id = fd; + struct client_txn* txn; + int n; + + txn = (struct client_txn *) malloc(sizeof(struct client_txn)); + tmp = *(struct session *)get_elem(ctx->sessions, + &tmp, session_comparator); + txn->client_session = tmp; + txn->request.length = recv(fd, txn->request.message, + MAX_MESSAGE_SIZE, 0); + if (txn->request.length == 0) { + /* + * Event on this socket indicated socket closure + */ + close(fd); + remove_elem(ctx->sessions, &tmp, session_comparator); + free(txn); + printf("Detected socket closure\n"); + return; + } + enqueue(ctx->client_jobs, txn); + printf("\tcreated a new job on %d [%d bytes]\n", fd, txn->request.length); +} + +int session_comparator(void *target, void *elem) { + + int target_id; + int elem_id; + + target_id = ((struct session *)target)->session_id; + elem_id = ((struct session *)elem)->session_id; + + return elem_id == target_id; +} + + +int errExit(char *s) { + + fprintf(stderr,"%s\n", s); + exit(-1); +} + diff --git a/comm/src/comm.h b/comm/src/comm.h new file mode 100644 index 0000000..ce49b75 --- /dev/null +++ b/comm/src/comm.h @@ -0,0 +1,58 @@ +/* + * + * Copyright place holder + * +*/ + +#ifndef __H__COMM__ +#define __H__COMM__ + +#define LISTEN_PORT 10000 +#define NUM_SESSIONS 512 +#define MAX_MESSAGE_SIZE 1024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct client_endpoint { + struct sockaddr_in client; + int fd; +}; + +struct comm_message { + int message_id; + char message[MAX_MESSAGE_SIZE]; + int length; + int whence; +}; + +struct session { + int session_id; + struct client_endpoint client_info; +}; + +struct client_txn { + struct session client_session; + struct comm_message request; + struct comm_message response; +}; + +typedef void (*message_handler) (struct client_txn *); +struct comm_context { + message_handler marshal_unmarshal; + struct queue_hdr *sessions; + struct queue_hdr *client_jobs; + int maxfds; +}; + +struct comm_context* comm_context(); /* creates/returns comm_context struct */ +void comm_listen(struct comm_context *); /* listens for messages */ +#endif diff --git a/comm/src/test/makefile b/comm/src/test/makefile new file mode 100644 index 0000000..753abe3 --- /dev/null +++ b/comm/src/test/makefile @@ -0,0 +1,27 @@ +SRC = testhexdump.c ../hexdump.c +OBJS = testhexdump.o hexdump.o +CFLAGS = -g -I ../ -I../../../utils/src + +all: comm + +comm: testcomm.o comm.o queue.o locks.o worker.o + gcc -o testcomm -g testcomm.o comm.o queue.o locks.o worker.o -lpthread + +testcomm.o : testcomm.c ../comm.h + gcc -c $(CFLAGS) testcomm.c + +comm.o: ../comm.h ../comm.c + gcc -c $(CFLAGS) ../comm.c + +worker.o: ../worker.h ../worker.c + gcc -c $(CFLAGS) ../worker.c + +queue.o: ../../../utils/src/queue.h ../../../utils/src/queue.c + gcc -c $(CFLAGS) ../../../utils/src/queue.c + + +locks.o: ../../../utils/src/locks.h ../../../utils/src/locks.c + gcc -c $(CFLAGS) ../../../utils/src/locks.c + +clean: + rm *.o testcomm diff --git a/comm/src/test/testcomm.c b/comm/src/test/testcomm.c new file mode 100644 index 0000000..5444e60 --- /dev/null +++ b/comm/src/test/testcomm.c @@ -0,0 +1,12 @@ +#include +#include +#include + + +main() { + + struct comm_context *ctx = comm_context(); + comm_listen(ctx); +} + + diff --git a/comm/src/worker.c b/comm/src/worker.c new file mode 100644 index 0000000..3545481 --- /dev/null +++ b/comm/src/worker.c @@ -0,0 +1,76 @@ +/* + * Copyright place holder + */ + +#include +#include + +static pthread_t* threads = NULL; +static int num_threads; +void* run_job(void *context); + +void create_worker_threads(int thread_pool_size) +{ + int i; + if (threads == NULL) { + threads = (pthread_t *)malloc(thread_pool_size* + sizeof(pthread_t)); + for (i=0; iclient_jobs); + + if (job != NULL) { + + /* + * Make the up call + */ + + // upcall + + /* + * Add response to response queue + */ + + // add response to response queue + + + // Process next job + } + else { + printf("Job Queue Empty: Will wait for job\n"); + } + } +} + +void * process_response(struct comm_context *context) +{ + + +} diff --git a/comm/src/worker.h b/comm/src/worker.h new file mode 100644 index 0000000..51717cc --- /dev/null +++ b/comm/src/worker.h @@ -0,0 +1,15 @@ +/* + * Copyright place holder + */ + +#ifndef __H_WORKER__ +#define __H_WORKER__ + +#include + +#define THREAD_POOL_SIZE 5 + +void create_thread_pool(int n); +void shutdown_thread_pool(); + +#endif diff --git a/utils/src/hexdump.c b/utils/src/hexdump.c new file mode 100644 index 0000000..77a12f2 --- /dev/null +++ b/utils/src/hexdump.c @@ -0,0 +1,63 @@ +/* + * Copyright placeholder + */ + +#include "hexdump.h" +void hexdump(void *buffer, unsigned int size) +{ + + unsigned char *buf = (unsigned char*)buffer; + int i, j; + + for (i=0; i +#include +void dump_hex(unsigned char *buf, unsigned int whence, unsigned int size); +void dump_ascii(unsigned char *buf, unsigned int whence, unsigned int size); +void hexdump(void *buffer, unsigned int size); + +#endif diff --git a/utils/src/locks.c b/utils/src/locks.c new file mode 100644 index 0000000..990498e --- /dev/null +++ b/utils/src/locks.c @@ -0,0 +1,25 @@ +#include +#include + +struct lock* get_lock() +{ + struct lock* retval; + pthread_mutexattr_t attr; + + retval = (struct lock *) malloc(sizeof(struct lock)); + /* create a recursive lock */ + pthread_mutex_init(&retval->mutex, NULL); + return retval; +} + +void enter_critical_section(struct lock* a_lock) +{ + + pthread_mutex_lock(&a_lock->mutex); +} + +void exit_critical_section(struct lock* a_lock) +{ + + pthread_mutex_unlock(&a_lock->mutex); +} diff --git a/utils/src/locks.h b/utils/src/locks.h new file mode 100644 index 0000000..f7923d4 --- /dev/null +++ b/utils/src/locks.h @@ -0,0 +1,14 @@ +#ifndef __H_LOCKS__ +#define __H_LOCKS__ +#include + +struct lock { + pthread_mutex_t mutex; + +}; + +struct lock* get_lock(); +void enter_critical_section(struct lock* a_lock); +void exit_critical_section(struct lock* a_lock); + +#endif diff --git a/utils/src/queue.c b/utils/src/queue.c new file mode 100644 index 0000000..aaaa013 --- /dev/null +++ b/utils/src/queue.c @@ -0,0 +1,142 @@ +#include +#include +#include + +static struct lock *q_lock = NULL; +void enter_critical_section(struct lock* q_lock); +void exit_critical_section(struct lock *q_lock); + +struct queue_hdr* init_queue() +{ + if (q_lock == NULL) + q_lock = get_lock(); + return (struct queue_hdr *) calloc (1,sizeof(struct queue_hdr)); +} + +void enqueue(struct queue_hdr* hdr, void *elem) +{ + + struct queue_node *node = (struct queue_node *) + malloc(sizeof(struct queue_node)); + node->elem = elem; + node->next = NULL; + + enter_critical_section(q_lock); + /* + * Queue can either be empty or non-empty + */ + + if (hdr->first == NULL) { // empty queue + hdr->first = node; + hdr->last = node; + } + else { // non-empty queue + hdr->last->next = node; + hdr->last = node; + } + hdr->num_elems++; + exit_critical_section(q_lock); +} + +void *dequeue(struct queue_hdr *hdr) +{ + void* retval; + struct queue_node *node; + + enter_critical_section(q_lock); + if (hdr->first == NULL) { + exit_critical_section(q_lock); + return NULL; + } + node = hdr->first; + hdr->first = node->next; // dequeue elem + + retval = node->elem; + free(node); // free what we created in enqueue + hdr->num_elems--; + exit_critical_section(q_lock); + + return retval; +} + + +void* get_elem(struct queue_hdr *hdr, void* target, comparator cmp) +{ + int result; + struct queue_node *node; + enter_critical_section(q_lock); + node = hdr->first; + while (node != NULL) { + if (result = cmp(target,node->elem)) { + exit_critical_section(q_lock); + return node->elem; + } + else + node = node->next; + } + exit_critical_section(q_lock); + return NULL; +} + +void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) +{ + + struct queue_node *node, *nodeprev; + + enter_critical_section(q_lock); + nodeprev = hdr->first; + node = nodeprev; + + while (node != NULL) { + if (cmp(target,node->elem)) { + /* Is target the first element? */ + if (node == hdr->first) { + hdr->first = node->next; + } + /* Is target the last element? */ + else if (node == hdr->last) { + hdr->last = nodeprev; + nodeprev->next = NULL; + } + /* Else it is in the middle of the list */ + else { + nodeprev->next = node->next; + } + hdr->num_elems--; + free(node); + break; + } + nodeprev = node; + node = node->next; + } + exit_critical_section(q_lock); +} + +void** get_all_elems(struct queue_hdr *hdr) +{ + int n = num_elems(hdr); + int i = 0; + struct queue_node *node = hdr->first; + void** retval = calloc(n, sizeof(void *)); + enter_critical_section(q_lock); + while (node != NULL) { + retval[i++] = node->elem; + node = node->next; + } + exit_critical_section(q_lock); + return retval; +} + +int num_elems(struct queue_hdr *hdr) +{ + + int retval = 0; + + enter_critical_section(q_lock); + retval = hdr->num_elems; + exit_critical_section(q_lock); + + return retval; +} + + diff --git a/utils/src/queue.h b/utils/src/queue.h new file mode 100644 index 0000000..98c80ea --- /dev/null +++ b/utils/src/queue.h @@ -0,0 +1,34 @@ +#ifndef __H__QUEUE__ +#define __H__QUEUE__ +/* + * The queue implementation is thread-safe FIFO + * queue. The user is responsbile for managing + * the space allocated for queue element + * + */ + +struct queue_node { + void *elem; + struct queue_node *next; +}; + +struct queue_hdr { + struct queue_node *first; + struct queue_node *last; + int num_elems; +}; + +typedef int (*comparator) (void *target, void *elem); /* returns 1 if target matches + * elem + */ +struct queue_hdr* init_queue(); +void enqueue(struct queue_hdr* hdr, void *elem); +void *dequeue(struct queue_hdr *hdr); + +void* get_elem(struct queue_hdr *hdr, void* target, comparator cmp); +void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp); + +void** get_all_elems(struct queue_hdr *hdr); + +int num_elems(struct queue_hdr *hdr); +#endif diff --git a/utils/src/test/makefile b/utils/src/test/makefile new file mode 100644 index 0000000..644fe0b --- /dev/null +++ b/utils/src/test/makefile @@ -0,0 +1,21 @@ + +CFLAGS = -I../ -g +CC = gcc + +all: testq testhexdump + +testq: ../queue.h testq.c mtestq.c ../queue.c ../locks.c + $(CC) -c $(CFLAGS) ../queue.c + $(CC) -c $(CFLAGS) ../locks.c + $(CC) -c $(CFLAGS) testq.c + $(CC) -c $(CFLAGS) mtestq.c + $(CC) -g -o testq testq.o queue.o locks.o + $(CC) -g -o mtestq mtestq.o queue.o locks.o -lpthread + +testhexdump: testhexdump.c ../hexdump.h ../hexdump.c + $(CC) -c $(CFLAGS) testhexdump.c + $(CC) -c $(CFLAGS) ../hexdump.c + $(CC) -g -o testhexdump testhexdump.o hexdump.o + +clean: + rm *.o testq mtestq testhexdump diff --git a/utils/src/test/mtestq.c b/utils/src/test/mtestq.c new file mode 100644 index 0000000..55d1c82 --- /dev/null +++ b/utils/src/test/mtestq.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include + + +static struct lock *num_lock; +int queue_size; + +struct thread_args { + struct queue_hdr *queue; + int num_jobs; +}; + +void set_up_job_queue(struct queue_hdr* queue, int num_jobs); +int check_job_queue(struct queue_hdr* queue, int num_jobs, int num_threads); +void *get_jobs(void *queue) ; +int queue_cmp(void *target, void *elem); +void *get_and_remove_jobs(void *args); + + +int main() +{ + + + struct queue_hdr *job_queue = init_queue(); + set_up_job_queue(job_queue,100); + check_job_queue(job_queue,100,10); + printf ("Multi-threaded enqueue-dequeue test passed\n"); + set_up_job_queue(job_queue,100); + check_job_removal(job_queue,100,10); + printf ("Multi-threaded check_job_removal test passed\n"); +} + +void add_a_job(struct queue_hdr *job_queue, int i) +{ + int *jobid = (int *) malloc(sizeof(int)); + *jobid = i; + enqueue(job_queue, jobid); +} + +int *get_job_from_queue(struct queue_hdr *job_queue) { + + return dequeue(job_queue); +} + +void set_up_job_queue(struct queue_hdr* queue, int n) +{ + + int i; + for (i=0; iqueue; + int i,n; + + n = ((struct thread_args *) args)->num_jobs; + + for (i=0; i +#include +main() +{ + + char *c = "This is a \n \t hexdump test"; + hexdump(c,strlen(c)); + +} diff --git a/utils/src/test/testq.c b/utils/src/test/testq.c new file mode 100644 index 0000000..f507de8 --- /dev/null +++ b/utils/src/test/testq.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + + +void set_up_job_queue(struct queue_hdr* queue, int num_jobs); +void check_job_queue(struct queue_hdr* queue, int num_jobs); +int queue_cmp(void *target, void *elem); +void check_get_from_queue(struct queue_hdr *queue, int n); +void check_remove_from_queue(struct queue_hdr *queue, int n); + + +int main() +{ + + int n = 100; + int i; + struct queue_hdr *job_queue = init_queue(); + set_up_job_queue(job_queue,n); + int ** elems = (int **) get_all_elems(job_queue); + for (i=0; i Date: Tue, 5 Mar 2013 12:43:49 +0530 Subject: [PATCH 02/18] Updated a few files Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils. In each component the source code is in a src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe (spinlock capability will be added in a future commit). utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. Issues (to be addressed in future commits): 1. Code alignment. 2. Copyright license to be appended. 3. Support for spinlock locks. --- xdr/src/ndmp_config.c | 40 ++ xdr/src/ndmp_connect.c | 11 + xdr/src/ndmp_xdr.c | 63 +++ xdr/src/ndmp_xdr.h | 48 ++ xdr/src/ndmp_xdr_structs.h | 981 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1143 insertions(+) create mode 100644 xdr/src/ndmp_config.c create mode 100644 xdr/src/ndmp_connect.c create mode 100644 xdr/src/ndmp_xdr.c create mode 100644 xdr/src/ndmp_xdr.h create mode 100644 xdr/src/ndmp_xdr_structs.h diff --git a/xdr/src/ndmp_config.c b/xdr/src/ndmp_config.c new file mode 100644 index 0000000..f018186 --- /dev/null +++ b/xdr/src/ndmp_config.c @@ -0,0 +1,40 @@ +#include + +void ndmp_config_get_host_info(struct client_txn *, XDR*) +{ + +} + +void ndmp_config_get_connection_type(struct client_txn *, XDR* ) +{ + +} + +void ndmp_config_get_auth_attr(struct client_txn *, XDR* ) +{ + +} + +void ndmp_config_get_butype_info(struct client_txn *, XDR* ) +{ + +} + +void ndmp_config_get_fs_info(struct client_txn *, XDR* ) +{ + +} + +void ndmp_config_get_tape_info(struct client_txn *, XDR* ) +{ + +} +void ndmp_config_get_scsi_info(struct client_txn *, XDR* ) +{ + +} + +void ndmp_config_get_server_info(struct client_txn *, XDR* ) +{ + +} diff --git a/xdr/src/ndmp_connect.c b/xdr/src/ndmp_connect.c new file mode 100644 index 0000000..af89bd7 --- /dev/null +++ b/xdr/src/ndmp_connect.c @@ -0,0 +1,11 @@ +#include +void ndmp_connect_open(struct client_txn *txn, XDR* request_stream) +{ + +} + + +void ndmp_connect_close(struct client_txn *, XDR*) +{ + +} diff --git a/xdr/src/ndmp_xdr.c b/xdr/src/ndmp_xdr.c new file mode 100644 index 0000000..98fdc1f --- /dev/null +++ b/xdr/src/ndmp_xdr.c @@ -0,0 +1,63 @@ +#include + +/* + * xdr_decode_encode is the entry point + * and callback method for the comm layer + * This is the first upcall made by a worker + * thread. + * + */ + +void xdr_decode_encode(struct client_txn *txn) +{ + + /* + * 1. Decode the message type from txn->request + * 2. Depending on the message type call the appropriate + * NDMP message handler. When the handler returns, + * txn->response will hold the marshaled (encoded)NDMP response + * 3. Enqueue the response into the response queue + */ + + XDR *request_stream = (XDR *)malloc(sizeof(XDR)); + int message_type; + struct_comm_context *ctx; + + xdrmem_create(request_stream,txn->request.message, + txn->request.length, XDR_DECODE); + /* + * Get the message type + */ + + message_type; // = .... + + ndmp_dispatch(message_type)(txn, request_stream); + + enqueue(ctx->response_jobs, txn); + +} + + +ndmp_message_handler ndmp_dispatch(int message_type) +{ + + switch(message_type) { + case 0x900: return ndmp_connect_open; + case 0x902: return ndmp_connect_close; + case 0x100: return ndmp_config_get_host_info; + case 0x102: return ndmp_config_get_configion_type; + case 0x103: return ndmp_config_get_auth_attr; + case 0x104: return ndmp_config_butype_info; + case 0x105: return ndmp_config_fs_info; + case 0x106: return ndmp_config_tape_info; + case 0x107: return ndmp_config_scsi_info; + case 0x108: return ndmp_config_server_info; + default: return ndmp_error_message; + } +} + +void ndmp_error_message(struct client_txn *, XDR* ) +{ + +} + diff --git a/xdr/src/ndmp_xdr.h b/xdr/src/ndmp_xdr.h new file mode 100644 index 0000000..f86af22 --- /dev/null +++ b/xdr/src/ndmp_xdr.h @@ -0,0 +1,48 @@ +#ifndef __H__NDMP_XDR__ +#define __H__NDMP_XDR__ + +#include +#include + +/* + * xdr_decode_encode is the entry point + * and callback method for the comm layer + * This is the first upcall made by a worker + * thread. + * + */ + +void xdr_decode_encode(struct client_txn *txn); + +/* + * Each NDMP message will have a message handler that is + * responsible for decoding(unmarshaling) the NDMP XDR request + * and invoking the appropriate NDMP action + */ + +typedef void (* ndmp_message_handler)(struct client_txn *txn, + XDR* request_stream); + +/* + * ndmp_dispatch determines the message handler for a given + * NDMP message type + */ + +ndmp_message_handler ndmp_dispatch(int message_type); + +/* + * + * The various NDMP message handlers + */ +void ndmp_connect_open(struct client_txn *txn, XDR* request_stream); +void ndmp_connect_close(struct client_txn *, XDR*); +void ndmp_config_get_host_info(struct client_txn *, XDR*); +void ndmp_config_get_connection_type(struct client_txn *, XDR* ); +void ndmp_config_get_auth_attr(struct client_txn *, XDR* ); +void ndmp_config_get_butype_info(struct client_txn *, XDR* ); +void ndmp_config_get_fs_info(struct client_txn *, XDR* ); +void ndmp_config_get_tape_info(struct client_txn *, XDR* ); +void ndmp_config_get_scsi_info(struct client_txn *, XDR* ); +void ndmp_config_get_server_info(struct client_txn *, XDR* ); +void ndmp_error_message(struct client *, XDR *); // For wrong message type +#endif diff --git a/xdr/src/ndmp_xdr_structs.h b/xdr/src/ndmp_xdr_structs.h new file mode 100644 index 0000000..ef869fb --- /dev/null +++ b/xdr/src/ndmp_xdr_structs.h @@ -0,0 +1,981 @@ +#ifndef __H_NDMP__ +#define __H_NDMP__ + +/* + * Type definitions based on NDMP V3 spec + */ + +enum ndmp_error { + NDMP_NO_ERR = 0, + NDMP_NOT_SUPPORTED_ERR = 1, + NDMP_DEVICE_BUSY_ERR = 2, + NDMP_DEVICE_OPENED_ERR = 3, + NDMP_NOT_AUTHORIZED_ERR = 4, + NDMP_PERMISSION_ERR = 5, + NDMP_DEV_NOT_OPEN_ERR = 6, + NDMP_IO_ERR = 7, + NDMP_TIMEOUT_ERR = 8, + NDMP_ILLEGAL_ARGS_ERR = 9, + NDMP_NO_TAPE_LOADED_ERR = 10, + NDMP_WRITE_PROTECT_ERR = 11, + NDMP_EOF_ERR = 12, + NDMP_EOM_ERR = 13, + NDMP_FILE_NOT_FOUND_ERR = 14, + NDMP_BAD_FILE_ERR = 15, + NDMP_NO_DEVICE_ERR = 16, + NDMP_NO_BUS_ERR = 17, + NDMP_XDR_DECODE_ERR = 18, + NDMP_ILLEGAL_STATE_ERR = 19, + NDMP_UNDEFINED_ERR = 20, + NDMP_XDR_ENCODE_ERR = 21, + NDMP_NO_MEM_ERR = 22, + NDMP_CONNECT_ERR = 23, +}; + +typedef enum ndmp_error ndmp_error; + +enum ndmp_header_message_type { + NDMP_MESSAGE_REQUEST = 0, + NDMP_MESSAGE_REPLY = 1, +}; +typedef enum ndmp_header_message_type ndmp_header_message_type; + +enum ndmp_message { + NDMP_CONNECT_OPEN = 0x900, + NDMP_CONNECT_CLIENT_AUTH = 0x901, + NDMP_CONNECT_CLOSE = 0x902, + NDMP_CONNECT_SERVER_AUTH = 0x903, + NDMP_CONFIG_GET_HOST_INFO = 0x100, + NDMP_CONFIG_GET_CONNECTION_TYPE = 0x102, + NDMP_CONFIG_GET_AUTH_ATTR = 0x103, + NDMP_CONFIG_GET_BUTYPE_INFO = 0x104, + NDMP_CONFIG_GET_FS_INFO = 0x105, + NDMP_CONFIG_GET_TAPE_INFO = 0x106, + NDMP_CONFIG_GET_SCSI_INFO = 0x107, + NDMP_CONFIG_GET_SERVER_INFO = 0x108, + NDMP_SCSI_OPEN = 0x200, + NDMP_SCSI_CLOSE = 0x201, + NDMP_SCSI_GET_STATE = 0x202, + NDMP_SCSI_SET_TARGET = 0x203, + NDMP_SCSI_RESET_DEVICE = 0x204, + NDMP_SCSI_RESET_BUS = 0x205, + NDMP_SCSI_EXECUTE_CDB = 0x206, + NDMP_TAPE_OPEN = 0x300, + NDMP_TAPE_CLOSE = 0x301, + NDMP_TAPE_GET_STATE = 0x302, + NDMP_TAPE_MTIO = 0x303, + NDMP_TAPE_WRITE = 0x304, + NDMP_TAPE_READ = 0x305, + NDMP_TAPE_EXECUTE_CDB = 0x307, + NDMP_DATA_GET_STATE = 0x400, + NDMP_DATA_START_BACKUP = 0x401, + NDMP_DATA_START_RECOVER = 0x402, + NDMP_DATA_ABORT = 0x403, + NDMP_DATA_GET_ENV = 0x404, + NDMP_DATA_STOP = 0x407, + NDMP_DATA_LISTEN = 0x409, + NDMP_DATA_CONNECT = 0x40a, + NDMP_NOTIFY_DATA_HALTED = 0x501, + NDMP_NOTIFY_CONNECTED = 0x502, + NDMP_NOTIFY_MOVER_HALTED = 0x503, + NDMP_NOTIFY_MOVER_PAUSED = 0x504, + NDMP_NOTIFY_DATA_READ = 0x505, + NDMP_LOG_FILE = 0x602, + NDMP_LOG_MESSAGE = 0x603, + NDMP_FH_ADD_FILE = 0x703, + NDMP_FH_ADD_DIR = 0x704, + NDMP_FH_ADD_NODE = 0x705, + NDMP_MOVER_GET_STATE = 0xa00, + NDMP_MOVER_LISTEN = 0xa01, + NDMP_MOVER_CONTINUE = 0xa02, + NDMP_MOVER_ABORT = 0xa03, + NDMP_MOVER_STOP = 0xa04, + NDMP_MOVER_SET_WINDOW = 0xa05, + NDMP_MOVER_READ = 0xa06, + NDMP_MOVER_CLOSE = 0xa07, + NDMP_MOVER_SET_RECORD_SIZE = 0xa08, + NDMP_MOVER_CONNECT = 0xa09, + NDMP_VENDORS_BASE = 0xf000, + NDMP_RESERVED_BASE = 0xff00, +}; + +typedef enum ndmp_message ndmp_message; + +struct ndmp_header { + u_long sequence; + u_long time_stamp; + ndmp_header_message_type message_type; + enum ndmp_message message; + u_long reply_sequence; + ndmp_error error; +}; + +typedef struct ndmp_header ndmp_header; + +struct ndmp_connect_open_request { + u_short protocol_version; +}; +typedef struct ndmp_connect_open_request ndmp_connect_open_request; + +struct ndmp_connect_open_reply { + ndmp_error error; +}; +typedef struct ndmp_connect_open_reply ndmp_connect_open_reply; + +enum ndmp_auth_type { + NDMP_AUTH_NONE = 0, + NDMP_AUTH_TEXT = 1, + NDMP_AUTH_MD5 = 2, +}; +typedef enum ndmp_auth_type ndmp_auth_type; + +struct ndmp_auth_text { + char *auth_id; + char *auth_password; +}; +typedef struct ndmp_auth_text ndmp_auth_text; + +struct ndmp_auth_md5 { + char *auth_id; + char auth_digest[16]; +}; +typedef struct ndmp_auth_md5 ndmp_auth_md5; + +struct ndmp_auth_data { + ndmp_auth_type auth_type; + union { + struct ndmp_auth_text auth_text; + struct ndmp_auth_md5 auth_md5; + } ndmp_auth_data_u; +}; + +typedef struct ndmp_auth_data ndmp_auth_data; + +struct ndmp_connect_client_auth_request { + ndmp_auth_data auth_data; +}; + +typedef struct ndmp_connect_client_auth_request ndmp_connect_client_auth_request; + +struct ndmp_connect_client_auth_reply { + ndmp_error error; +}; + +typedef struct ndmp_connect_client_auth_reply ndmp_connect_client_auth_reply; + +struct ndmp_auth_attr { + ndmp_auth_type auth_type; + union { + char challenge[64]; + } ndmp_auth_attr_u; +}; + +typedef struct ndmp_auth_attr ndmp_auth_attr; + +struct ndmp_connect_server_auth_request { + ndmp_auth_attr client_attr; +}; + +typedef struct ndmp_connect_server_auth_request ndmp_connect_server_auth_request; + +struct ndmp_connect_server_auth_reply { + ndmp_error error; + ndmp_auth_data server_result; +}; + +typedef struct ndmp_connect_server_auth_reply ndmp_connect_server_auth_reply; + +struct ndmp_config_get_host_info_reply { + ndmp_error error; + char *hostname; + char *os_type; + char *os_vers; + char *hostid; +}; +typedef struct ndmp_config_get_host_info_reply ndmp_config_get_host_info_reply; + +enum ndmp_addr_type { + NDMP_ADDR_LOCAL = 0, + NDMP_ADDR_TCP = 1, + NDMP_ADDR_FC = 2, + NDMP_ADDR_IPC = 3, +}; +typedef enum ndmp_addr_type ndmp_addr_type; + +struct ndmp_config_get_connection_type_reply { + ndmp_error error; + struct { + u_int addr_types_len; + ndmp_addr_type *addr_types_val; + } addr_types; +}; +typedef struct ndmp_config_get_connection_type_reply ndmp_config_get_connection_type_reply; + +struct ndmp_config_get_auth_attr_request { + ndmp_auth_type auth_type; +}; + +typedef struct ndmp_config_get_auth_attr_request ndmp_config_get_auth_attr_request; + +struct ndmp_config_get_auth_attr_reply { + ndmp_error error; + ndmp_auth_attr server_attr; +}; + +typedef struct ndmp_config_get_auth_attr_reply ndmp_config_get_auth_attr_reply; + +struct ndmp_config_get_server_info_reply { + ndmp_error error; + char *vendor_name; + char *product_name; + char *revision_number; + struct { + u_int auth_type_len; + ndmp_auth_type *auth_type_val; + } auth_type; +}; + +typedef struct ndmp_config_get_server_info_reply ndmp_config_get_server_info_reply; + +#define NDMP_BUTYPE_BACKUP_FILE_HISTORY 0x0001 +#define NDMP_BUTYPE_BACKUP_FILELIST 0x0002 +#define NDMP_BUTYPE_RECOVER_FILELIST 0x0004 +#define NDMP_BUTYPE_BACKUP_DIRECT 0x0008 +#define NDMP_BUTYPE_RECOVER_DIRECT 0x0010 +#define NDMP_BUTYPE_BACKUP_INCREMENTAL 0x0020 +#define NDMP_BUTYPE_RECOVER_INCREMENTAL 0x0040 +#define NDMP_BUTYPE_BACKUP_UTF8 0x0080 +#define NDMP_BUTYPE_RECOVER_UTF8 0x0100 + +struct ndmp_butype_info { + char *butype_name; + struct { + u_int default_env_len; + ndmp_pval *default_env_val; + } default_env; + u_long attrs; +}; +typedef struct ndmp_butype_info ndmp_butype_info; + +struct ndmp_config_get_butype_info_reply { + ndmp_error error; + struct { + u_int butype_info_len; + ndmp_butype_info *butype_info_val; + } butype_info; +}; +typedef struct ndmp_config_get_butype_info_reply ndmp_config_get_butype_info_reply; +#define NDMP_FS_INFO_TOTAL_SIZE_INVALID 0x00000001 +#define NDMP_FS_INFO_USED_SIZE_INVALID 0x00000002 +#define NDMP_FS_INFO_AVAIL_SIZE_INVALID 0x00000004 +#define NDMP_FS_INFO_TOTAL_INODES_INVALID 0x00000008 +#define NDMP_FS_INFO_USED_INODES_INVALID 0x00000010 + +struct ndmp_fs_info { + u_long invalid; + char *fs_type; + char *fs_logical_device; + char *fs_physical_device; + ndmp_u_quad total_size; + ndmp_u_quad used_size; + ndmp_u_quad avail_size; + ndmp_u_quad total_inodes; + ndmp_u_quad used_inodes; + struct { + u_int fs_env_len; + ndmp_pval *fs_env_val; + } fs_env; + char *fs_status; +}; +typedef struct ndmp_fs_info ndmp_fs_info; + +struct ndmp_config_get_fs_info_reply { + ndmp_error error; + struct { + u_int fs_info_len; + ndmp_fs_info *fs_info_val; + } fs_info; +}; +typedef struct ndmp_config_get_fs_info_reply ndmp_config_get_fs_info_reply; +#define NDMP_TAPE_ATTR_REWIND 0x00000001 +#define NDMP_TAPE_ATTR_UNLOAD 0x00000002 + +struct ndmp_device_capability { + char *device; + u_long attr; + struct { + u_int capability_len; + ndmp_pval *capability_val; + } capability; +}; +typedef struct ndmp_device_capability ndmp_device_capability; + +struct ndmp_device_info { + char *model; + struct { + u_int caplist_len; + ndmp_device_capability *caplist_val; + } caplist; +}; +typedef struct ndmp_device_info ndmp_device_info; + +struct ndmp_config_get_tape_info_reply { + ndmp_error error; + struct { + u_int tape_info_len; + ndmp_device_info *tape_info_val; + } tape_info; +}; +typedef struct ndmp_config_get_tape_info_reply ndmp_config_get_tape_info_reply; + +struct ndmp_config_get_scsi_info_reply { + ndmp_error error; + struct { + u_int scsi_info_len; + ndmp_device_info *scsi_info_val; + } scsi_info; +}; +typedef struct ndmp_config_get_scsi_info_reply ndmp_config_get_scsi_info_reply; + +struct ndmp_scsi_open_request { + char *device; +}; +typedef struct ndmp_scsi_open_request ndmp_scsi_open_request; + +struct ndmp_scsi_open_reply { + ndmp_error error; +}; +typedef struct ndmp_scsi_open_reply ndmp_scsi_open_reply; + +struct ndmp_scsi_close_reply { + ndmp_error error; +}; +typedef struct ndmp_scsi_close_reply ndmp_scsi_close_reply; + +struct ndmp_scsi_get_state_reply { + ndmp_error error; + short target_controller; + short target_id; + short target_lun; +}; +typedef struct ndmp_scsi_get_state_reply ndmp_scsi_get_state_reply; + +struct ndmp_scsi_set_target_request { + char *device; + u_short target_controller; + u_short target_id; + u_short target_lun; +}; +typedef struct ndmp_scsi_set_target_request ndmp_scsi_set_target_request; + +struct ndmp_scsi_set_target_reply { + ndmp_error error; +}; +typedef struct ndmp_scsi_set_target_reply ndmp_scsi_set_target_reply; + +struct ndmp_scsi_reset_device_reply { + ndmp_error error; +}; +typedef struct ndmp_scsi_reset_device_reply ndmp_scsi_reset_device_reply; + +struct ndmp_scsi_reset_bus_reply { + ndmp_error error; +}; +typedef struct ndmp_scsi_reset_bus_reply ndmp_scsi_reset_bus_reply; +#define NDMP_SCSI_DATA_IN 0x00000001 +#define NDMP_SCSI_DATA_OUT 0x00000002 + +struct ndmp_execute_cdb_request { + u_long flags; + u_long timeout; + u_long datain_len; + struct { + u_int cdb_len; + char *cdb_val; + } cdb; + struct { + u_int dataout_len; + char *dataout_val; + } dataout; +}; +typedef struct ndmp_execute_cdb_request ndmp_execute_cdb_request; + +struct ndmp_execute_cdb_reply { + ndmp_error error; + u_char status; + u_long dataout_len; + struct { + u_int datain_len; + char *datain_val; + } datain; + struct { + u_int ext_sense_len; + char *ext_sense_val; + } ext_sense; +}; +typedef struct ndmp_execute_cdb_reply ndmp_execute_cdb_reply; + +enum ndmp_tape_open_mode { + NDMP_TAPE_READ_MODE = 0, + NDMP_TAPE_RDWR_MODE = 1, +}; +typedef enum ndmp_tape_open_mode ndmp_tape_open_mode; + +struct ndmp_tape_open_request { + char *device; + ndmp_tape_open_mode mode; +}; +typedef struct ndmp_tape_open_request ndmp_tape_open_request; + +struct ndmp_tape_open_reply { + ndmp_error error; +}; +typedef struct ndmp_tape_open_reply ndmp_tape_open_reply; + +struct ndmp_tape_close_reply { + ndmp_error error; +}; +typedef struct ndmp_tape_close_reply ndmp_tape_close_reply; +#define NDMP_TAPE_STATE_NOREWIND 0x0008 +#define NDMP_TAPE_STATE_WR_PROT 0x0010 +#define NDMP_TAPE_STATE_ERROR 0x0020 +#define NDMP_TAPE_STATE_UNLOAD 0x0040 +#define NDMP_TAPE_STATE_FILE_NUM_INVALID 0x00000001 +#define NDMP_TAPE_STATE_SOFT_ERRORS_INVALID 0x00000002 +#define NDMP_TAPE_STATE_BLOCK_SIZE_INVALID 0x00000004 +#define NDMP_TAPE_STATE_BLOCKNO_INVALID 0x00000008 +#define NDMP_TAPE_STATE_TOTAL_SPACE_INVALID 0x00000010 +#define NDMP_TAPE_STATE_SPACE_REMAIN_INVALID 0x00000020 +#define NDMP_TAPE_STATE_PARTITION_INVALID 0x00000040 + +struct ndmp_tape_get_state_reply { + u_long invalid; + ndmp_error error; + u_long flags; + u_long file_num; + u_long soft_errors; + u_long block_size; + u_long blockno; + ndmp_u_quad total_space; + ndmp_u_quad space_remain; + u_long partition; +}; +typedef struct ndmp_tape_get_state_reply ndmp_tape_get_state_reply; + +enum ndmp_tape_mtio_op { + NDMP_MTIO_FSF = 0, + NDMP_MTIO_BSF = 1, + NDMP_MTIO_FSR = 2, + NDMP_MTIO_BSR = 3, + NDMP_MTIO_REW = 4, + NDMP_MTIO_EOF = 5, + NDMP_MTIO_OFF = 6, +}; +typedef enum ndmp_tape_mtio_op ndmp_tape_mtio_op; + +struct ndmp_tape_mtio_request { + ndmp_tape_mtio_op tape_op; + u_long count; +}; +typedef struct ndmp_tape_mtio_request ndmp_tape_mtio_request; + +struct ndmp_tape_mtio_reply { + ndmp_error error; + u_long resid_count; +}; +typedef struct ndmp_tape_mtio_reply ndmp_tape_mtio_reply; + +struct ndmp_tape_write_request { + struct { + u_int data_out_len; + char *data_out_val; + } data_out; +}; +typedef struct ndmp_tape_write_request ndmp_tape_write_request; + +struct ndmp_tape_write_reply { + ndmp_error error; + u_long count; +}; +typedef struct ndmp_tape_write_reply ndmp_tape_write_reply; + +struct ndmp_tape_read_request { + u_long count; +}; +typedef struct ndmp_tape_read_request ndmp_tape_read_request; + +struct ndmp_tape_read_reply { + ndmp_error error; + struct { + u_int data_in_len; + char *data_in_val; + } data_in; +}; +typedef struct ndmp_tape_read_reply ndmp_tape_read_reply; + +typedef ndmp_execute_cdb_request ndmp_tape_execute_cdb_request; + +typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; + +enum ndmp_mover_state { + NDMP_MOVER_STATE_IDLE = 0, + NDMP_MOVER_STATE_LISTEN = 1, + NDMP_MOVER_STATE_ACTIVE = 2, + NDMP_MOVER_STATE_PAUSED = 3, + NDMP_MOVER_STATE_HALTED = 4, +}; +typedef enum ndmp_mover_state ndmp_mover_state; + +enum ndmp_mover_pause_reason { + NDMP_MOVER_PAUSE_NA = 0, + NDMP_MOVER_PAUSE_EOM = 1, + NDMP_MOVER_PAUSE_EOF = 2, + NDMP_MOVER_PAUSE_SEEK = 3, + NDMP_MOVER_PAUSE_MEDIA_ERROR = 4, + NDMP_MOVER_PAUSE_EOW = 5, +}; +typedef enum ndmp_mover_pause_reason ndmp_mover_pause_reason; + +enum ndmp_mover_halt_reason { + NDMP_MOVER_HALT_NA = 0, + NDMP_MOVER_HALT_CONNECT_CLOSED = 1, + NDMP_MOVER_HALT_ABORTED = 2, + NDMP_MOVER_HALT_INTERNAL_ERROR = 3, + NDMP_MOVER_HALT_CONNECT_ERROR = 4, +}; +typedef enum ndmp_mover_halt_reason ndmp_mover_halt_reason; + +enum ndmp_mover_mode { + NDMP_MOVER_MODE_READ = 0, + NDMP_MOVER_MODE_WRITE = 1, +}; +typedef enum ndmp_mover_mode ndmp_mover_mode; + +struct ndmp_tcp_addr { + u_long ip_addr; + u_short port; +}; +typedef struct ndmp_tcp_addr ndmp_tcp_addr; + +struct ndmp_fc_addr { + u_long loop_id; +}; +typedef struct ndmp_fc_addr ndmp_fc_addr; + +struct ndmp_ipc_addr { + struct { + u_int comm_data_len; + char *comm_data_val; + } comm_data; +}; +typedef struct ndmp_ipc_addr ndmp_ipc_addr; + +struct ndmp_addr { + ndmp_addr_type addr_type; + union { + ndmp_tcp_addr tcp_addr; + ndmp_fc_addr fc_addr; + ndmp_ipc_addr ipc_addr; + } ndmp_addr_u; +}; + +typedef struct ndmp_addr ndmp_addr; + +struct ndmp_mover_get_state_reply { + ndmp_error error; + ndmp_mover_state state; + ndmp_mover_pause_reason pause_reason; + ndmp_mover_halt_reason halt_reason; + u_long record_size; + u_long record_num; + ndmp_u_quad data_written; + ndmp_u_quad seek_position; + ndmp_u_quad bytes_left_to_read; + ndmp_u_quad window_offset; + ndmp_u_quad window_length; + ndmp_addr data_connection_addr; +}; + +typedef struct ndmp_mover_get_state_reply ndmp_mover_get_state_reply; + +struct ndmp_mover_listen_request { + ndmp_mover_mode mode; + ndmp_addr_type addr_type; +}; + +typedef struct ndmp_mover_listen_request ndmp_mover_listen_request; + +struct ndmp_mover_listen_reply { + ndmp_error error; + ndmp_addr data_connection_addr; +}; + +typedef struct ndmp_mover_listen_reply ndmp_mover_listen_reply; + +struct ndmp_mover_connect_request { + ndmp_mover_mode mode; + ndmp_addr addr; +}; + +typedef struct ndmp_mover_connect_request ndmp_mover_connect_request; + +struct ndmp_mover_connect_reply { + ndmp_error error; +}; + +typedef struct ndmp_mover_connect_reply ndmp_mover_connect_reply; + +struct ndmp_mover_set_record_size_request { + u_long len; +}; + +typedef struct ndmp_mover_set_record_size_request ndmp_mover_set_record_size_request; + +struct ndmp_mover_set_record_size_reply { + ndmp_error error; +}; + +typedef struct ndmp_mover_set_record_size_reply ndmp_mover_set_record_size_reply; + +struct ndmp_mover_set_window_request { + ndmp_u_quad offset; + ndmp_u_quad length; +}; + +typedef struct ndmp_mover_set_window_request ndmp_mover_set_window_request; + +struct ndmp_mover_set_window_reply { + ndmp_error error; +}; + +typedef struct ndmp_mover_set_window_reply ndmp_mover_set_window_reply; + +struct ndmp_mover_continue_reply { + ndmp_error error; +}; +typedef struct ndmp_mover_continue_reply ndmp_mover_continue_reply; + +struct ndmp_mover_abort_reply { + ndmp_error error; +}; +typedef struct ndmp_mover_abort_reply ndmp_mover_abort_reply; + +struct ndmp_mover_stop_reply { + ndmp_error error; +}; +typedef struct ndmp_mover_stop_reply ndmp_mover_stop_reply; + +struct ndmp_mover_read_request { + ndmp_u_quad offset; + ndmp_u_quad length; +}; +typedef struct ndmp_mover_read_request ndmp_mover_read_request; + +struct ndmp_mover_read_reply { + ndmp_error error; +}; +typedef struct ndmp_mover_read_reply ndmp_mover_read_reply; + +struct ndmp_mover_close_reply { + ndmp_error error; +}; +typedef struct ndmp_mover_close_reply ndmp_mover_close_reply; + +enum ndmp_data_operation { + NDMP_DATA_OP_NOACTION = 0, + NDMP_DATA_OP_BACKUP = 1, + NDMP_DATA_OP_RESTORE = 2, +}; +typedef enum ndmp_data_operation ndmp_data_operation; + +enum ndmp_data_state { + NDMP_DATA_STATE_IDLE = 0, + NDMP_DATA_STATE_ACTIVE = 1, + NDMP_DATA_STATE_HALTED = 2, + NDMP_DATA_STATE_LISTEN = 3, + NDMP_DATA_STATE_CONNECTED = 4, +}; +typedef enum ndmp_data_state ndmp_data_state; + +enum ndmp_data_halt_reason { + NDMP_DATA_HALT_NA = 0, + NDMP_DATA_HALT_SUCCESSFUL = 1, + NDMP_DATA_HALT_ABORTED = 2, + NDMP_DATA_HALT_INTERNAL_ERROR = 3, + NDMP_DATA_HALT_CONNECT_ERROR = 4, +}; +typedef enum ndmp_data_halt_reason ndmp_data_halt_reason; +#define NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID 0x00000001 +#define NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID 0x00000002 + +struct ndmp_data_get_state_reply { + u_long invalid; + ndmp_error error; + ndmp_data_operation operation; + ndmp_data_state state; + ndmp_data_halt_reason halt_reason; + ndmp_u_quad bytes_processed; + ndmp_u_quad est_bytes_remain; + u_long est_time_remain; + ndmp_addr data_connection_addr; + ndmp_u_quad read_offset; + ndmp_u_quad read_length; +}; +typedef struct ndmp_data_get_state_reply ndmp_data_get_state_reply; + +struct ndmp_data_start_backup_request { + char *bu_type; + struct { + u_int env_len; + ndmp_pval *env_val; + } env; +}; +typedef struct ndmp_data_start_backup_request ndmp_data_start_backup_request; + +struct ndmp_data_start_backup_reply { + ndmp_error error; +}; +typedef struct ndmp_data_start_backup_reply ndmp_data_start_backup_reply; + +struct ndmp_name { + char *original_path; + char *destination_dir; + char *new_name; + char *other_name; + ndmp_u_quad node; + ndmp_u_quad fh_info; +}; +typedef struct ndmp_name ndmp_name; + +struct ndmp_data_start_recover_request { + struct { + u_int env_len; + ndmp_pval *env_val; + } env; + struct { + u_int nlist_len; + ndmp_name *nlist_val; + } nlist; + char *bu_type; +}; +typedef struct ndmp_data_start_recover_request ndmp_data_start_recover_request; + +struct ndmp_data_start_recover_reply { + ndmp_error error; +}; +typedef struct ndmp_data_start_recover_reply ndmp_data_start_recover_reply; + +struct ndmp_data_abort_reply { + ndmp_error error; +}; +typedef struct ndmp_data_abort_reply ndmp_data_abort_reply; + +struct ndmp_data_stop_reply { + ndmp_error error; +}; +typedef struct ndmp_data_stop_reply ndmp_data_stop_reply; + +struct ndmp_data_get_env_reply { + ndmp_error error; + struct { + u_int env_len; + ndmp_pval *env_val; + } env; +}; +typedef struct ndmp_data_get_env_reply ndmp_data_get_env_reply; + +struct ndmp_data_listen_request { + ndmp_addr_type addr_type; +}; +typedef struct ndmp_data_listen_request ndmp_data_listen_request; + +struct ndmp_data_listen_reply { + ndmp_error error; + ndmp_addr data_connection_addr; +}; +typedef struct ndmp_data_listen_reply ndmp_data_listen_reply; + +struct ndmp_data_connect_request { + ndmp_addr addr; +}; +typedef struct ndmp_data_connect_request ndmp_data_connect_request; + +struct ndmp_data_connect_reply { + ndmp_error error; +}; +typedef struct ndmp_data_connect_reply ndmp_data_connect_reply; + +struct ndmp_notify_data_halted_request { + ndmp_data_halt_reason reason; + char *text_reason; +}; +typedef struct ndmp_notify_data_halted_request ndmp_notify_data_halted_request; + +enum ndmp_connect_reason { + NDMP_CONNECTED = 0, + NDMP_SHUTDOWN = 1, + NDMP_REFUSED = 2, +}; +typedef enum ndmp_connect_reason ndmp_connect_reason; + +struct ndmp_notify_connected_request { + ndmp_connect_reason reason; + u_short protocol_version; + char *text_reason; +}; +typedef struct ndmp_notify_connected_request ndmp_notify_connected_request; + +struct ndmp_notify_mover_paused_request { + ndmp_mover_pause_reason reason; + ndmp_u_quad seek_position; +}; +typedef struct ndmp_notify_mover_paused_request ndmp_notify_mover_paused_request; + +struct ndmp_notify_mover_halted_request { + ndmp_mover_halt_reason reason; + char *text_reason; +}; +typedef struct ndmp_notify_mover_halted_request ndmp_notify_mover_halted_request; + +struct ndmp_notify_data_read_request { + ndmp_u_quad offset; + ndmp_u_quad length; +}; +typedef struct ndmp_notify_data_read_request ndmp_notify_data_read_request; + +enum ndmp_log_type { + NDMP_LOG_NORMAL = 0, + NDMP_LOG_DEBUG = 1, + NDMP_LOG_ERROR = 2, + NDMP_LOG_WARNING = 3, +}; +typedef enum ndmp_log_type ndmp_log_type; + +struct ndmp_log_message_request { + ndmp_log_type log_type; + u_long message_id; + char *entry; +}; +typedef struct ndmp_log_message_request ndmp_log_message_request; + +struct ndmp_log_file_request { + char *name; + ndmp_error error; +}; +typedef struct ndmp_log_file_request ndmp_log_file_request; + +enum ndmp_fs_type { + NDMP_FS_UNIX = 0, + NDMP_FS_NT = 1, + NDMP_FS_OTHER = 2, +}; +typedef enum ndmp_fs_type ndmp_fs_type; + +typedef char *ndmp_path; + +struct ndmp_nt_path { + ndmp_path nt_path; + ndmp_path dos_path; +}; +typedef struct ndmp_nt_path ndmp_nt_path; + +struct ndmp_file_name { + ndmp_fs_type fs_type; + union { + ndmp_path unix_name; + ndmp_nt_path nt_name; + ndmp_path other_name; + } ndmp_file_name_u; +}; +typedef struct ndmp_file_name ndmp_file_name; + +enum ndmp_file_type { + NDMP_FILE_DIR = 0, + NDMP_FILE_FIFO = 1, + NDMP_FILE_CSPEC = 2, + NDMP_FILE_BSPEC = 3, + NDMP_FILE_REG = 4, + NDMP_FILE_SLINK = 5, + NDMP_FILE_SOCK = 6, + NDMP_FILE_REGISTRY = 7, + NDMP_FILE_OTHER = 8, +}; +typedef enum ndmp_file_type ndmp_file_type; +#define NDMP_FILE_STAT_ATIME_INVALID 0x00000001 +#define NDMP_FILE_STAT_CTIME_INVALID 0x00000002 +#define NDMP_FILE_STAT_GROUP_INVALID 0x00000004 + +struct ndmp_file_stat { + u_long invalid; + ndmp_fs_type fs_type; + ndmp_file_type ftype; + u_long mtime; + u_long atime; + u_long ctime; + u_long owner; + u_long group; + u_long fattr; + ndmp_u_quad size; + u_long links; +}; +typedef struct ndmp_file_stat ndmp_file_stat; + +struct ndmp_file { + struct { + u_int names_len; + ndmp_file_name *names_val; + } names; + struct { + u_int stats_len; + ndmp_file_stat *stats_val; + } stats; + ndmp_u_quad node; + ndmp_u_quad fh_info; +}; +typedef struct ndmp_file ndmp_file; + +struct ndmp_fh_add_file_request { + struct { + u_int files_len; + ndmp_file *files_val; + } files; +}; +typedef struct ndmp_fh_add_file_request ndmp_fh_add_file_request; + +struct ndmp_dir { + struct { + u_int names_len; + ndmp_file_name *names_val; + } names; + ndmp_u_quad node; + ndmp_u_quad parent; +}; +typedef struct ndmp_dir ndmp_dir; + +struct ndmp_fh_add_dir_request { + struct { + u_int dirs_len; + ndmp_dir *dirs_val; + } dirs; +}; +typedef struct ndmp_fh_add_dir_request ndmp_fh_add_dir_request; + +struct ndmp_node { + struct { + u_int stats_len; + ndmp_file_stat *stats_val; + } stats; + ndmp_u_quad node; + ndmp_u_quad fh_info; +}; +typedef struct ndmp_node ndmp_node; + +struct ndmp_fh_add_node_request { + struct { + u_int nodes_len; + ndmp_node *nodes_val; + } nodes; +}; +typedef struct ndmp_fh_add_node_request ndmp_fh_add_node_request; + +#endif From fa2b8238b433bad5395823c1618b28daa2b177cd Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 5 Mar 2013 12:46:06 +0530 Subject: [PATCH 03/18] Updated a few files Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils. In each component the source code is in a src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe (spinlock capability will be added in a future commit). utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. Issues (to be addressed in future commits): 1. Code alignment. 2. Copyright license to be appended. 3. Support for spinlock locks. --- comm/src/comm.c | 11 +++---- comm/src/comm.h | 5 ++-- comm/src/test/makefile | 8 ++++-- comm/src/test/testcomm.c | 7 +++++ comm/src/worker.c | 62 ++++++++++++++++++++++++++++++++++------ comm/src/worker.h | 2 +- utils/src/queue.c | 37 ++++++++++++------------ utils/src/queue.h | 3 +- 8 files changed, 97 insertions(+), 38 deletions(-) diff --git a/comm/src/comm.c b/comm/src/comm.c index 9f55f7a..9326b9a 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -22,9 +22,9 @@ struct comm_context* comm_context() { static struct comm_context *retval = NULL; if (retval == NULL) { retval = calloc(1,sizeof(struct comm_context)); - init_queue(); - retval->sessions = malloc(sizeof(struct queue_hdr)); - retval->client_jobs = malloc(sizeof(struct queue_hdr)); + retval->sessions = init_queue(); + retval->request_jobs = init_queue(); + retval->response_jobs = init_queue(); } return retval; } @@ -152,7 +152,7 @@ void comm_listen(struct comm_context *ctx) { ctx->maxfds = listener; /* Create Worker Threads */ -// create_worker_threads(THREAD_POOL_SIZE); + create_worker_threads(THREAD_POOL_SIZE); /* when the listener wakes up create a session */ for (;;) { @@ -259,8 +259,9 @@ void handle_a_client_request(int fd, struct comm_context *ctx) printf("Detected socket closure\n"); return; } - enqueue(ctx->client_jobs, txn); + enqueue(ctx->request_jobs, txn); printf("\tcreated a new job on %d [%d bytes]\n", fd, txn->request.length); + } int session_comparator(void *target, void *elem) { diff --git a/comm/src/comm.h b/comm/src/comm.h index ce49b75..0abe688 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -9,7 +9,7 @@ #define LISTEN_PORT 10000 #define NUM_SESSIONS 512 -#define MAX_MESSAGE_SIZE 1024 +#define MAX_MESSAGE_SIZE 2048 #include #include @@ -49,7 +49,8 @@ typedef void (*message_handler) (struct client_txn *); struct comm_context { message_handler marshal_unmarshal; struct queue_hdr *sessions; - struct queue_hdr *client_jobs; + struct queue_hdr *request_jobs; + struct queue_hdr *response_jobs; int maxfds; }; diff --git a/comm/src/test/makefile b/comm/src/test/makefile index 753abe3..de16ade 100644 --- a/comm/src/test/makefile +++ b/comm/src/test/makefile @@ -4,8 +4,8 @@ CFLAGS = -g -I ../ -I../../../utils/src all: comm -comm: testcomm.o comm.o queue.o locks.o worker.o - gcc -o testcomm -g testcomm.o comm.o queue.o locks.o worker.o -lpthread +comm: testcomm.o comm.o queue.o locks.o worker.o hexdump.o + gcc -o testcomm -g testcomm.o comm.o queue.o locks.o worker.o hexdump.o -lpthread testcomm.o : testcomm.c ../comm.h gcc -c $(CFLAGS) testcomm.c @@ -16,10 +16,12 @@ comm.o: ../comm.h ../comm.c worker.o: ../worker.h ../worker.c gcc -c $(CFLAGS) ../worker.c +hexdump.o: ../../../utils/src/queue.h ../../../utils/src/queue.c + gcc -c $(CFLAGS) ../../../utils/src/hexdump.c + queue.o: ../../../utils/src/queue.h ../../../utils/src/queue.c gcc -c $(CFLAGS) ../../../utils/src/queue.c - locks.o: ../../../utils/src/locks.h ../../../utils/src/locks.c gcc -c $(CFLAGS) ../../../utils/src/locks.c diff --git a/comm/src/test/testcomm.c b/comm/src/test/testcomm.c index 5444e60..a66456d 100644 --- a/comm/src/test/testcomm.c +++ b/comm/src/test/testcomm.c @@ -3,10 +3,17 @@ #include +void process_job(struct client_txn *job); + main() { struct comm_context *ctx = comm_context(); + ctx->marshal_unmarshal = process_job; comm_listen(ctx); } +void process_job(struct client_txn *job) +{ + hexdump(job->request.message, job->request.length); +} diff --git a/comm/src/worker.c b/comm/src/worker.c index 3545481..1c671ea 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -8,19 +8,24 @@ static pthread_t* threads = NULL; static int num_threads; void* run_job(void *context); +void* process_response(void *context); void create_worker_threads(int thread_pool_size) { int i; if (threads == NULL) { - threads = (pthread_t *)malloc(thread_pool_size* + threads = (pthread_t *)malloc((thread_pool_size+1)* sizeof(pthread_t)); for (i=0; iclient_jobs); + job = (struct client_txn *)dequeue(ctx->request_jobs); if (job != NULL) { @@ -53,24 +58,65 @@ void* run_job(void *context) */ // upcall + ctx->marshal_unmarshal(job); /* * Add response to response queue */ - - // add response to response queue - - + enqueue(ctx->response_jobs, job); + printf("Processed a job \n"); // Process next job } else { - printf("Job Queue Empty: Will wait for job\n"); +// printf("Job Queue Empty: Will wait for job\n"); + pthread_yield(); // Let another thread run } } } -void * process_response(struct comm_context *context) +void *process_response(void *context) { + int write_result; + struct comm_message response; + struct comm_context *ctx = (struct comm_context *)context; + struct client_txn *job; + while (1) { + /* + * Process the next job in response queue and send + * response to client + */ + job = (struct client_txn *)dequeue(ctx->response_jobs); + + if (job != NULL) { + // Write message to client + write_result = write_message(job); + if (write_result == -1) + printf("Write message error\n"); + free(job); + } + else + pthread_yield(); + + } + return ctx; +} +int write_message(struct client_txn *job) +{ + struct session tmp; + struct comm_message response; + int fd, sent_bytes; + tmp = job->client_session; + response = job->response; + fd = tmp.session_id; + if (response.length > 0) { + + sent_bytes = send(fd,response.message,response.length,0); + + printf("Sent a %d byte response to (%s,%d) on sock %d\n", + sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), + ntohs(tmp.client_info.client.sin_port), fd); + } + return -1 * (sent_bytes != response.length); } diff --git a/comm/src/worker.h b/comm/src/worker.h index 51717cc..db5ddbc 100644 --- a/comm/src/worker.h +++ b/comm/src/worker.h @@ -7,7 +7,7 @@ #include -#define THREAD_POOL_SIZE 5 +#define THREAD_POOL_SIZE 1 void create_thread_pool(int n); void shutdown_thread_pool(); diff --git a/utils/src/queue.c b/utils/src/queue.c index aaaa013..132dd0d 100644 --- a/utils/src/queue.c +++ b/utils/src/queue.c @@ -2,15 +2,16 @@ #include #include -static struct lock *q_lock = NULL; void enter_critical_section(struct lock* q_lock); void exit_critical_section(struct lock *q_lock); struct queue_hdr* init_queue() { - if (q_lock == NULL) - q_lock = get_lock(); - return (struct queue_hdr *) calloc (1,sizeof(struct queue_hdr)); + struct queue_hdr* retval = (struct queue_hdr *) + calloc (1,sizeof(struct queue_hdr)); + retval->lock = get_lock(); + + return retval; } void enqueue(struct queue_hdr* hdr, void *elem) @@ -21,7 +22,7 @@ void enqueue(struct queue_hdr* hdr, void *elem) node->elem = elem; node->next = NULL; - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); /* * Queue can either be empty or non-empty */ @@ -35,7 +36,7 @@ void enqueue(struct queue_hdr* hdr, void *elem) hdr->last = node; } hdr->num_elems++; - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); } void *dequeue(struct queue_hdr *hdr) @@ -43,9 +44,9 @@ void *dequeue(struct queue_hdr *hdr) void* retval; struct queue_node *node; - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); if (hdr->first == NULL) { - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return NULL; } node = hdr->first; @@ -54,7 +55,7 @@ void *dequeue(struct queue_hdr *hdr) retval = node->elem; free(node); // free what we created in enqueue hdr->num_elems--; - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return retval; } @@ -64,17 +65,17 @@ void* get_elem(struct queue_hdr *hdr, void* target, comparator cmp) { int result; struct queue_node *node; - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); node = hdr->first; while (node != NULL) { if (result = cmp(target,node->elem)) { - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return node->elem; } else node = node->next; } - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return NULL; } @@ -83,7 +84,7 @@ void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) struct queue_node *node, *nodeprev; - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); nodeprev = hdr->first; node = nodeprev; @@ -109,7 +110,7 @@ void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) nodeprev = node; node = node->next; } - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); } void** get_all_elems(struct queue_hdr *hdr) @@ -118,12 +119,12 @@ void** get_all_elems(struct queue_hdr *hdr) int i = 0; struct queue_node *node = hdr->first; void** retval = calloc(n, sizeof(void *)); - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); while (node != NULL) { retval[i++] = node->elem; node = node->next; } - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return retval; } @@ -132,9 +133,9 @@ int num_elems(struct queue_hdr *hdr) int retval = 0; - enter_critical_section(q_lock); + enter_critical_section(hdr->lock); retval = hdr->num_elems; - exit_critical_section(q_lock); + exit_critical_section(hdr->lock); return retval; } diff --git a/utils/src/queue.h b/utils/src/queue.h index 98c80ea..7a68e02 100644 --- a/utils/src/queue.h +++ b/utils/src/queue.h @@ -6,7 +6,7 @@ * the space allocated for queue element * */ - +#include struct queue_node { void *elem; struct queue_node *next; @@ -15,6 +15,7 @@ struct queue_node { struct queue_hdr { struct queue_node *first; struct queue_node *last; + struct lock *lock; int num_elems; }; From bd740113bf7c0c1ed3151df8c07262f44185da0f Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 5 Mar 2013 12:49:29 +0530 Subject: [PATCH 04/18] Updated a few files Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils. In each component the source code is in a src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe (spinlock capability will be added in a future commit). utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. Issues (to be addressed in future commits): 1. Code alignment. 2. Copyright license to be appended. 3. Support for spinlock locks. --- NDMPServerDesignv5.odt | Bin 31938 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 NDMPServerDesignv5.odt diff --git a/NDMPServerDesignv5.odt b/NDMPServerDesignv5.odt deleted file mode 100644 index 5ead8665c66e8e43d89977b2d8b8e70323b01946..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31938 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 From a9c0ec672309648fc42d6aa93c5de46df1037597 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Wed, 6 Mar 2013 14:48:57 +0530 Subject: [PATCH 05/18] Added copyright license for all files. Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils, xdr. In each component the source code is in an src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. XDR is incomplete as of now. Issues (to be addressed in future commits): 1. Align code (Code seems to be aligned in local files, but is not in GitHub). 2. Support for spinlock locks. 3. Complete the XDR integration. --- comm/src/comm.c | 190 +++++++++++++++++------------------ comm/src/comm.h | 11 +- comm/src/test/makefile | 8 ++ comm/src/test/testcomm.c | 15 ++- comm/src/worker.c | 9 +- comm/src/worker.h | 7 +- utils/src/hexdump.c | 66 ++++++------ utils/src/hexdump.h | 8 +- utils/src/locks.c | 21 ++-- utils/src/locks.h | 11 +- utils/src/queue.c | 110 ++++++++++---------- utils/src/queue.h | 22 ++-- utils/src/test/makefile | 8 +- utils/src/test/mtestq.c | 89 ++++++++-------- utils/src/test/testhexdump.c | 11 +- utils/src/test/testq.c | 18 ++-- xdr/src/ndmp_config.c | 10 ++ xdr/src/ndmp_connect.c | 10 ++ xdr/src/ndmp_xdr.c | 88 +++++++++------- xdr/src/ndmp_xdr.h | 27 +++-- xdr/src/ndmp_xdr_structs.h | 32 +++--- 21 files changed, 445 insertions(+), 326 deletions(-) diff --git a/comm/src/comm.c b/comm/src/comm.c index 9326b9a..bddb453 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -1,6 +1,11 @@ /* - * Copyright place holder -*/ + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ #include #include @@ -13,15 +18,15 @@ * active sessions */ - int session_comparator(void *target, void *elem); void handle_client_requests(fd_set *read_socks, struct comm_context *ctx); void handle_a_client_request(int fd, struct comm_context *ctx); -struct comm_context* comm_context() { +struct comm_context* comm_context() +{ static struct comm_context *retval = NULL; - if (retval == NULL) { - retval = calloc(1,sizeof(struct comm_context)); + if (retval == NULL ) { + retval = calloc(1, sizeof(struct comm_context)); retval->sessions = init_queue(); retval->request_jobs = init_queue(); retval->response_jobs = init_queue(); @@ -29,7 +34,6 @@ struct comm_context* comm_context() { return retval; } - /* * * create_listener @@ -48,41 +52,40 @@ int create_listener(int port) { int retval; /* return the socket the listener should listen on */ struct sockaddr_in listener; int reuse = 1; - + listener.sin_family = AF_INET; listener.sin_addr.s_addr = INADDR_ANY; listener.sin_port = htons(port); - + /* now create a socket and bind to listener */ retval = socket(AF_INET, SOCK_STREAM, 0); - setsockopt(retval, SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int)); - fcntl(retval, F_SETFL, O_NONBLOCK); - if (bind(retval, (struct sockaddr *)&listener, - sizeof(struct sockaddr_in)) == -1) + setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); + fcntl(retval, F_SETFL, O_NONBLOCK); + if (bind(retval, (struct sockaddr *) &listener, + sizeof(struct sockaddr_in)) == -1) errExit("Error:bind"); - + return retval; } -struct client_endpoint accept_connection(int listener) { - +struct client_endpoint accept_connection(int listener) +{ struct sockaddr_in client; socklen_t len; int sockfd; - struct client_endpoint retval; + struct client_endpoint retval; retval.fd = -1; printf("Accepting new connection ..\n"); - sockfd = accept(listener, (struct sockaddr *)&client, - &len); - if (sockfd< 0) { + sockfd = accept(listener, (struct sockaddr *) &client, &len); + if (sockfd < 0) { printf("Oops! Cannot accept new connection :( \n"); return retval; } - fcntl(sockfd, F_SETFL, O_NONBLOCK); + fcntl(sockfd, F_SETFL, O_NONBLOCK); retval.client = client; retval.fd = sockfd; @@ -90,29 +93,25 @@ struct client_endpoint accept_connection(int listener) { return retval; } - /* * set_fd_flags sets all the sockets * that we want to multiplex on fd_set */ - -void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) +void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) { - struct session **active_sessions; - int n,i; + int n, i; FD_ZERO(fds); - FD_SET(listener, fds); - + FD_SET(listener, fds); + active_sessions = (struct session **) get_all_elems(ctx->sessions); n = num_elems(ctx->sessions); - for (i=0; isession_id, fds); + for (i = 0; i < n; i++) { + FD_SET(active_sessions[i]->session_id, fds); } } - /* * comm_listen: * comm_listen listens on a socket at the address @@ -129,8 +128,8 @@ void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) * */ -void comm_listen(struct comm_context *ctx) { - +void comm_listen(struct comm_context *ctx) +{ fd_set read_socks; int listener = create_listener(LISTEN_PORT); struct client_endpoint endpoint; @@ -143,92 +142,88 @@ void comm_listen(struct comm_context *ctx) { listener = create_listener(LISTEN_PORT); listen(listener, NUM_SESSIONS); - printf ("Listening on port %d....\n", LISTEN_PORT); + printf("Listening on port %d....\n", LISTEN_PORT); /* - * add listening socket to read_socks + * add listening socket to read_socks * for multiplexing listening as well */ FD_SET(listener, &read_socks); ctx->maxfds = listener; - /* Create Worker Threads */ + /* Create Worker Threads */ create_worker_threads(THREAD_POOL_SIZE); /* when the listener wakes up create a session */ for (;;) { printf("Wait on select \n"); - set_fd_flags(&read_socks,listener,ctx); - ready = select((ctx->maxfds)+1, &read_socks, NULL, NULL, NULL); + set_fd_flags(&read_socks, listener, ctx); + ready = select((ctx->maxfds) + 1, &read_socks, NULL, NULL, + NULL ); printf("Woke up from select \n"); if (ready != -1) { if (FD_ISSET(listener, &read_socks)) { new_connections = accept_all_connections( - listener, - &read_socks,ctx); - printf("%d new connection(s) \n", - new_connections); - } - else { + listener, &read_socks, ctx); + printf("%d new connection(s) \n", + new_connections); + } else { /* * Some client session is active */ - handle_client_requests(&read_socks,ctx); + handle_client_requests(&read_socks, ctx); } } - + } - -} +} int accept_all_connections(int listener, fd_set *read_socks, - struct comm_context *ctx) + struct comm_context *ctx) { struct client_endpoint endpoint; struct session* new_session; - + int num_new_sessions = 0; -// do { - endpoint = accept_connection(listener); - if (endpoint.fd != -1) { - /* - * Add new connection to session queue - * in comm_context - */ - - new_session = (struct session*)malloc( - sizeof(struct session)); - new_session->session_id = endpoint.fd; - new_session->client_info = endpoint; - enqueue(ctx->sessions,new_session); - /* - * add to select list of sockets - */ - FD_SET(endpoint.fd, read_socks); - if (endpoint.fd > ctx->maxfds) { - ctx->maxfds = endpoint.fd; - } - - printf("Connection request from %s at %d\n", + // do { + endpoint = accept_connection(listener); + if (endpoint.fd != -1) { + /* + * Add new connection to session queue + * in comm_context + */ + + new_session = (struct session*) malloc(sizeof(struct session)); + new_session->session_id = endpoint.fd; + new_session->client_info = endpoint; + enqueue(ctx->sessions, new_session); + /* + * add to select list of sockets + */ + FD_SET(endpoint.fd, read_socks); + if (endpoint.fd > ctx->maxfds) { + ctx->maxfds = endpoint.fd; + } + + printf("Connection request from %s at %d\n", inet_ntoa(endpoint.client.sin_addr), ntohs(endpoint.client.sin_port)); - num_new_sessions++; - } -// } while (endpoint.fd != -1); + num_new_sessions++; + } + // } while (endpoint.fd != -1); return num_new_sessions; } -void handle_client_requests(fd_set *read_socks, struct comm_context *ctx) +void handle_client_requests(fd_set *read_socks, struct comm_context *ctx) { - int i; - for (i=0; i<=ctx->maxfds; i++) { + for (i = 0; i <= ctx->maxfds; i++) { printf("Checking for event on sock %d\n", i); if (FD_ISSET(i,read_socks)) { - handle_a_client_request(i,ctx); - } + handle_a_client_request(i, ctx); + } } } @@ -242,13 +237,13 @@ void handle_a_client_request(int fd, struct comm_context *ctx) tmp.session_id = fd; struct client_txn* txn; int n; - + txn = (struct client_txn *) malloc(sizeof(struct client_txn)); - tmp = *(struct session *)get_elem(ctx->sessions, - &tmp, session_comparator); + tmp = *(struct session *) get_elem(ctx->sessions, &tmp, + session_comparator); txn->client_session = tmp; - txn->request.length = recv(fd, txn->request.message, - MAX_MESSAGE_SIZE, 0); + txn->request.length = recv(fd, txn->request.message, MAX_MESSAGE_SIZE, + 0); if (txn->request.length == 0) { /* * Event on this socket indicated socket closure @@ -259,26 +254,25 @@ void handle_a_client_request(int fd, struct comm_context *ctx) printf("Detected socket closure\n"); return; } - enqueue(ctx->request_jobs, txn); - printf("\tcreated a new job on %d [%d bytes]\n", fd, txn->request.length); - -} + enqueue(ctx->request_jobs, txn); + printf("\tcreated a new job on %d [%d bytes]\n", fd, + txn->request.length); -int session_comparator(void *target, void *elem) { +} +int session_comparator(void *target, void *elem) +{ int target_id; int elem_id; - target_id = ((struct session *)target)->session_id; - elem_id = ((struct session *)elem)->session_id; - + target_id = ((struct session *) target)->session_id; + elem_id = ((struct session *) elem)->session_id; + return elem_id == target_id; } - -int errExit(char *s) { - - fprintf(stderr,"%s\n", s); +int errExit(char *s) +{ + fprintf(stderr, "%s\n", s); exit(-1); } - diff --git a/comm/src/comm.h b/comm/src/comm.h index 0abe688..61f78c9 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -1,8 +1,11 @@ /* - * - * Copyright place holder - * -*/ + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ #ifndef __H__COMM__ #define __H__COMM__ diff --git a/comm/src/test/makefile b/comm/src/test/makefile index de16ade..ebddd41 100644 --- a/comm/src/test/makefile +++ b/comm/src/test/makefile @@ -1,3 +1,11 @@ + # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + # This file is part of glfs-ndmp. + # This file is licensed to you under your choice of the GNU Lesser + # General Public License, version 3 or any later version (LGPLv3 or + # later), or the GNU General Public License, version 2 (GPLv2), in all + # cases as published by the Free Software Foundation. + + SRC = testhexdump.c ../hexdump.c OBJS = testhexdump.o hexdump.o CFLAGS = -g -I ../ -I../../../utils/src diff --git a/comm/src/test/testcomm.c b/comm/src/test/testcomm.c index a66456d..77359c7 100644 --- a/comm/src/test/testcomm.c +++ b/comm/src/test/testcomm.c @@ -1,12 +1,20 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include #include #include - void process_job(struct client_txn *job); -main() { - +main() +{ struct comm_context *ctx = comm_context(); ctx->marshal_unmarshal = process_job; comm_listen(ctx); @@ -14,6 +22,5 @@ main() { void process_job(struct client_txn *job) { - hexdump(job->request.message, job->request.length); } diff --git a/comm/src/worker.c b/comm/src/worker.c index 1c671ea..9b441ba 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -1,5 +1,10 @@ /* - * Copyright place holder + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. */ #include @@ -40,7 +45,6 @@ void shutdown_worker_threads() void* run_job(void *context) { - struct comm_context *ctx = (struct comm_context *)context; struct client_txn *job; while (1) { @@ -72,6 +76,7 @@ void* run_job(void *context) pthread_yield(); // Let another thread run } } + return *ctx; } void *process_response(void *context) diff --git a/comm/src/worker.h b/comm/src/worker.h index db5ddbc..6a39e04 100644 --- a/comm/src/worker.h +++ b/comm/src/worker.h @@ -1,5 +1,10 @@ /* - * Copyright place holder + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. */ #ifndef __H_WORKER__ diff --git a/utils/src/hexdump.c b/utils/src/hexdump.c index 77a12f2..1ea1392 100644 --- a/utils/src/hexdump.c +++ b/utils/src/hexdump.c @@ -1,19 +1,24 @@ /* - * Copyright placeholder + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. */ #include "hexdump.h" -void hexdump(void *buffer, unsigned int size) -{ - unsigned char *buf = (unsigned char*)buffer; - int i, j; +void hexdump(void *buffer, unsigned int size) +{ + unsigned char *buf = (unsigned char*) buffer; + int i, j; - for (i=0; i #include + void dump_hex(unsigned char *buf, unsigned int whence, unsigned int size); void dump_ascii(unsigned char *buf, unsigned int whence, unsigned int size); void hexdump(void *buffer, unsigned int size); diff --git a/utils/src/locks.c b/utils/src/locks.c index 990498e..d1f95a8 100644 --- a/utils/src/locks.c +++ b/utils/src/locks.c @@ -1,25 +1,32 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include #include -struct lock* get_lock() +struct lock* get_lock() { struct lock* retval; pthread_mutexattr_t attr; - retval = (struct lock *) malloc(sizeof(struct lock)); - /* create a recursive lock */ - pthread_mutex_init(&retval->mutex, NULL); + retval = (struct lock *) malloc(sizeof(struct lock)); + /* create a recursive lock */ + pthread_mutex_init(&retval->mutex, NULL ); return retval; } void enter_critical_section(struct lock* a_lock) { - pthread_mutex_lock(&a_lock->mutex); } void exit_critical_section(struct lock* a_lock) -{ - +{ pthread_mutex_unlock(&a_lock->mutex); } diff --git a/utils/src/locks.h b/utils/src/locks.h index f7923d4..918d5f8 100644 --- a/utils/src/locks.h +++ b/utils/src/locks.h @@ -1,10 +1,19 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #ifndef __H_LOCKS__ #define __H_LOCKS__ #include struct lock { pthread_mutex_t mutex; - + }; struct lock* get_lock(); diff --git a/utils/src/queue.c b/utils/src/queue.c index 132dd0d..8ea1331 100644 --- a/utils/src/queue.c +++ b/utils/src/queue.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include #include #include @@ -5,33 +14,31 @@ void enter_critical_section(struct lock* q_lock); void exit_critical_section(struct lock *q_lock); -struct queue_hdr* init_queue() +struct queue_hdr* init_queue() { - struct queue_hdr* retval = (struct queue_hdr *) - calloc (1,sizeof(struct queue_hdr)); + struct queue_hdr* retval = (struct queue_hdr *) calloc(1, + sizeof(struct queue_hdr)); retval->lock = get_lock(); return retval; } -void enqueue(struct queue_hdr* hdr, void *elem) +void enqueue(struct queue_hdr* hdr, void *elem) { - - struct queue_node *node = (struct queue_node *) - malloc(sizeof(struct queue_node)); + struct queue_node *node = (struct queue_node *) malloc( + sizeof(struct queue_node)); node->elem = elem; node->next = NULL; - enter_critical_section(hdr->lock); + enter_critical_section(hdr->lock); /* * Queue can either be empty or non-empty - */ + */ - if (hdr->first == NULL) { // empty queue - hdr->first = node; - hdr->last = node; - } - else { // non-empty queue + if (hdr->first == NULL ) { // empty queue + hdr->first = node; + hdr->last = node; + } else { // non-empty queue hdr->last->next = node; hdr->last = node; } @@ -39,15 +46,15 @@ void enqueue(struct queue_hdr* hdr, void *elem) exit_critical_section(hdr->lock); } -void *dequeue(struct queue_hdr *hdr) +void *dequeue(struct queue_hdr *hdr) { void* retval; - struct queue_node *node; - - enter_critical_section(hdr->lock); - if (hdr->first == NULL) { - exit_critical_section(hdr->lock); - return NULL; + struct queue_node *node; + + enter_critical_section(hdr->lock); + if (hdr->first == NULL ) { + exit_critical_section(hdr->lock); + return NULL ; } node = hdr->first; hdr->first = node->next; // dequeue elem @@ -60,49 +67,47 @@ void *dequeue(struct queue_hdr *hdr) return retval; } - void* get_elem(struct queue_hdr *hdr, void* target, comparator cmp) { - int result; + int result; struct queue_node *node; - enter_critical_section(hdr->lock); + enter_critical_section(hdr->lock); node = hdr->first; - while (node != NULL) { - if (result = cmp(target,node->elem)) { - exit_critical_section(hdr->lock); + while (node != NULL ) { + result = cmp(target, node->elem); + if (result) { + exit_critical_section(hdr->lock); return node->elem; - } - else + } else node = node->next; } - exit_critical_section(hdr->lock); - return NULL; + exit_critical_section(hdr->lock); + return NULL ; } void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) { - struct queue_node *node, *nodeprev; - - enter_critical_section(hdr->lock); + + enter_critical_section(hdr->lock); nodeprev = hdr->first; node = nodeprev; - - while (node != NULL) { - if (cmp(target,node->elem)) { - /* Is target the first element? */ - if (node == hdr->first) { - hdr->first = node->next; + + while (node != NULL ) { + if (cmp(target, node->elem)) { + /* Is target the first element? */ + if (node == hdr->first) { + hdr->first = node->next; } - /* Is target the last element? */ - else if (node == hdr->last) { + /* Is target the last element? */ + else if (node == hdr->last) { hdr->last = nodeprev; nodeprev->next = NULL; } - /* Else it is in the middle of the list */ + /* Else it is in the middle of the list */ else { nodeprev->next = node->next; - } + } hdr->num_elems--; free(node); break; @@ -110,34 +115,31 @@ void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) nodeprev = node; node = node->next; } - exit_critical_section(hdr->lock); + exit_critical_section(hdr->lock); } -void** get_all_elems(struct queue_hdr *hdr) +void** get_all_elems(struct queue_hdr *hdr) { int n = num_elems(hdr); int i = 0; struct queue_node *node = hdr->first; void** retval = calloc(n, sizeof(void *)); - enter_critical_section(hdr->lock); - while (node != NULL) { + enter_critical_section(hdr->lock); + while (node != NULL ) { retval[i++] = node->elem; - node = node->next; + node = node->next; } exit_critical_section(hdr->lock); return retval; } -int num_elems(struct queue_hdr *hdr) +int num_elems(struct queue_hdr *hdr) { - int retval = 0; enter_critical_section(hdr->lock); retval = hdr->num_elems; exit_critical_section(hdr->lock); - + return retval; } - - diff --git a/utils/src/queue.h b/utils/src/queue.h index 7a68e02..6f52df7 100644 --- a/utils/src/queue.h +++ b/utils/src/queue.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #ifndef __H__QUEUE__ #define __H__QUEUE__ /* @@ -7,21 +16,22 @@ * */ #include + struct queue_node { void *elem; struct queue_node *next; -}; +}; struct queue_hdr { - struct queue_node *first; - struct queue_node *last; + struct queue_node *first; + struct queue_node *last; struct lock *lock; int num_elems; }; -typedef int (*comparator) (void *target, void *elem); /* returns 1 if target matches - * elem - */ +typedef int (*comparator)(void *target, void *elem); /* returns 1 if target matches + * elem + */ struct queue_hdr* init_queue(); void enqueue(struct queue_hdr* hdr, void *elem); void *dequeue(struct queue_hdr *hdr); diff --git a/utils/src/test/makefile b/utils/src/test/makefile index 644fe0b..7593f7e 100644 --- a/utils/src/test/makefile +++ b/utils/src/test/makefile @@ -1,4 +1,10 @@ - + # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + # This file is part of glfs-ndmp. + # This file is licensed to you under your choice of the GNU Lesser + # General Public License, version 3 or any later version (LGPLv3 or + # later), or the GNU General Public License, version 2 (GPLv2), in all + # cases as published by the Free Software Foundation. + CFLAGS = -I../ -g CC = gcc diff --git a/utils/src/test/mtestq.c b/utils/src/test/mtestq.c index 55d1c82..a323320 100644 --- a/utils/src/test/mtestq.c +++ b/utils/src/test/mtestq.c @@ -1,10 +1,18 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include #include #include #include #include - static struct lock *num_lock; int queue_size; @@ -14,23 +22,20 @@ struct thread_args { }; void set_up_job_queue(struct queue_hdr* queue, int num_jobs); -int check_job_queue(struct queue_hdr* queue, int num_jobs, int num_threads); -void *get_jobs(void *queue) ; -int queue_cmp(void *target, void *elem); +void check_job_queue(struct queue_hdr* queue, int num_jobs, int num_threads); +void *get_jobs(void *queue); +void queue_cmp(void *target, void *elem); void *get_and_remove_jobs(void *args); - int main() { - - struct queue_hdr *job_queue = init_queue(); - set_up_job_queue(job_queue,100); - check_job_queue(job_queue,100,10); - printf ("Multi-threaded enqueue-dequeue test passed\n"); - set_up_job_queue(job_queue,100); - check_job_removal(job_queue,100,10); - printf ("Multi-threaded check_job_removal test passed\n"); + set_up_job_queue(job_queue, 100); + check_job_queue(job_queue, 100, 10); + printf("Multi-threaded enqueue-dequeue test passed\n"); + set_up_job_queue(job_queue, 100); + check_job_removal(job_queue, 100, 10); + printf("Multi-threaded check_job_removal test passed\n"); } void add_a_job(struct queue_hdr *job_queue, int i) @@ -40,67 +45,61 @@ void add_a_job(struct queue_hdr *job_queue, int i) enqueue(job_queue, jobid); } -int *get_job_from_queue(struct queue_hdr *job_queue) { - +int *get_job_from_queue(struct queue_hdr *job_queue) +{ return dequeue(job_queue); } void set_up_job_queue(struct queue_hdr* queue, int n) { - int i; - for (i=0; iqueue; - int i,n; - + int i, n; + n = ((struct thread_args *) args)->num_jobs; - for (i=0; i #include + main() { - char *c = "This is a \n \t hexdump test"; hexdump(c,strlen(c)); diff --git a/utils/src/test/testq.c b/utils/src/test/testq.c index f507de8..e92495a 100644 --- a/utils/src/test/testq.c +++ b/utils/src/test/testq.c @@ -1,19 +1,25 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include #include #include #include - void set_up_job_queue(struct queue_hdr* queue, int num_jobs); void check_job_queue(struct queue_hdr* queue, int num_jobs); int queue_cmp(void *target, void *elem); void check_get_from_queue(struct queue_hdr *queue, int n); void check_remove_from_queue(struct queue_hdr *queue, int n); - int main() { - int n = 100; int i; struct queue_hdr *job_queue = init_queue(); @@ -41,7 +47,6 @@ void add_a_job(struct queue_hdr *job_queue, int i) int *get_job_from_queue(struct queue_hdr *job_queue) { - return dequeue(job_queue); } @@ -52,8 +57,8 @@ void set_up_job_queue(struct queue_hdr* queue, int n) add_a_job(queue, i); } -void check_job_queue(struct queue_hdr *queue, int n) { - +void check_job_queue(struct queue_hdr *queue, int n) +{ int i, *j; for (i=0; i void ndmp_config_get_host_info(struct client_txn *, XDR*) @@ -29,6 +38,7 @@ void ndmp_config_get_tape_info(struct client_txn *, XDR* ) { } + void ndmp_config_get_scsi_info(struct client_txn *, XDR* ) { diff --git a/xdr/src/ndmp_connect.c b/xdr/src/ndmp_connect.c index af89bd7..8d5d95b 100644 --- a/xdr/src/ndmp_connect.c +++ b/xdr/src/ndmp_connect.c @@ -1,4 +1,14 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #include + void ndmp_connect_open(struct client_txn *txn, XDR* request_stream) { diff --git a/xdr/src/ndmp_xdr.c b/xdr/src/ndmp_xdr.c index 98fdc1f..528399a 100644 --- a/xdr/src/ndmp_xdr.c +++ b/xdr/src/ndmp_xdr.c @@ -1,5 +1,13 @@ -#include +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ +#include /* * xdr_decode_encode is the entry point * and callback method for the comm layer @@ -8,55 +16,63 @@ * */ -void xdr_decode_encode(struct client_txn *txn) +void xdr_decode_encode(struct client_txn *txn) { + /* + * 1. Decode the message type from txn->request + * 2. Depending on the message type call the appropriate + * NDMP message handler. When the handler returns, + * txn->response will hold the marshaled (encoded)NDMP response + * 3. Enqueue the response into the response queue + */ - /* - * 1. Decode the message type from txn->request - * 2. Depending on the message type call the appropriate - * NDMP message handler. When the handler returns, - * txn->response will hold the marshaled (encoded)NDMP response - * 3. Enqueue the response into the response queue - */ - - XDR *request_stream = (XDR *)malloc(sizeof(XDR)); + XDR *request_stream = (XDR *) malloc(sizeof(XDR)); int message_type; - struct_comm_context *ctx; + struct comm_context *ctx; - xdrmem_create(request_stream,txn->request.message, - txn->request.length, XDR_DECODE); - /* - * Get the message type - */ + xdrmem_create(request_stream, txn->request.message, txn->request.length, + XDR_DECODE); + /* + * Get the message type + */ + + // message_type = ....; - message_type; // = .... - ndmp_dispatch(message_type)(txn, request_stream); - + enqueue(ctx->response_jobs, txn); } +ndmp_message_handler ndmp_dispatch(int message_type) { -ndmp_message_handler ndmp_dispatch(int message_type) -{ - - switch(message_type) { - case 0x900: return ndmp_connect_open; - case 0x902: return ndmp_connect_close; - case 0x100: return ndmp_config_get_host_info; - case 0x102: return ndmp_config_get_configion_type; - case 0x103: return ndmp_config_get_auth_attr; - case 0x104: return ndmp_config_butype_info; - case 0x105: return ndmp_config_fs_info; - case 0x106: return ndmp_config_tape_info; - case 0x107: return ndmp_config_scsi_info; - case 0x108: return ndmp_config_server_info; - default: return ndmp_error_message; + switch (message_type) { + case 0x900: + return ndmp_connect_open; + case 0x902: + return ndmp_connect_close; + case 0x100: + return ndmp_config_get_host_info; + case 0x102: + return ndmp_config_get_connection_type; + case 0x103: + return ndmp_config_get_auth_attr; + case 0x104: + return ndmp_config_get_butype_info; + case 0x105: + return ndmp_config_get_fs_info; + case 0x106: + return ndmp_config_get_tape_info; + case 0x107: + return ndmp_config_get_scsi_info; + case 0x108: + return ndmp_config_get_server_info; + default: + return ndmp_error_message; } } -void ndmp_error_message(struct client_txn *, XDR* ) +void ndmp_error_message(struct client_txn *, XDR*) { } diff --git a/xdr/src/ndmp_xdr.h b/xdr/src/ndmp_xdr.h index f86af22..61966ae 100644 --- a/xdr/src/ndmp_xdr.h +++ b/xdr/src/ndmp_xdr.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #ifndef __H__NDMP_XDR__ #define __H__NDMP_XDR__ @@ -16,11 +25,11 @@ void xdr_decode_encode(struct client_txn *txn); /* * Each NDMP message will have a message handler that is - * responsible for decoding(unmarshaling) the NDMP XDR request + * responsible for decoding(unmarshaling) the NDMP XDR request * and invoking the appropriate NDMP action */ -typedef void (* ndmp_message_handler)(struct client_txn *txn, +typedef void (*ndmp_message_handler)(struct client_txn *txn, XDR* request_stream); /* @@ -37,12 +46,12 @@ ndmp_message_handler ndmp_dispatch(int message_type); void ndmp_connect_open(struct client_txn *txn, XDR* request_stream); void ndmp_connect_close(struct client_txn *, XDR*); void ndmp_config_get_host_info(struct client_txn *, XDR*); -void ndmp_config_get_connection_type(struct client_txn *, XDR* ); -void ndmp_config_get_auth_attr(struct client_txn *, XDR* ); -void ndmp_config_get_butype_info(struct client_txn *, XDR* ); -void ndmp_config_get_fs_info(struct client_txn *, XDR* ); -void ndmp_config_get_tape_info(struct client_txn *, XDR* ); -void ndmp_config_get_scsi_info(struct client_txn *, XDR* ); -void ndmp_config_get_server_info(struct client_txn *, XDR* ); +void ndmp_config_get_connection_type(struct client_txn *, XDR*); +void ndmp_config_get_auth_attr(struct client_txn *, XDR*); +void ndmp_config_get_butype_info(struct client_txn *, XDR*); +void ndmp_config_get_fs_info(struct client_txn *, XDR*); +void ndmp_config_get_tape_info(struct client_txn *, XDR*); +void ndmp_config_get_scsi_info(struct client_txn *, XDR*); +void ndmp_config_get_server_info(struct client_txn *, XDR*); void ndmp_error_message(struct client *, XDR *); // For wrong message type #endif diff --git a/xdr/src/ndmp_xdr_structs.h b/xdr/src/ndmp_xdr_structs.h index ef869fb..2cd6671 100644 --- a/xdr/src/ndmp_xdr_structs.h +++ b/xdr/src/ndmp_xdr_structs.h @@ -1,10 +1,19 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + #ifndef __H_NDMP__ #define __H_NDMP__ /* * Type definitions based on NDMP V3 spec */ - + enum ndmp_error { NDMP_NO_ERR = 0, NDMP_NOT_SUPPORTED_ERR = 1, @@ -35,8 +44,7 @@ enum ndmp_error { typedef enum ndmp_error ndmp_error; enum ndmp_header_message_type { - NDMP_MESSAGE_REQUEST = 0, - NDMP_MESSAGE_REPLY = 1, + NDMP_MESSAGE_REQUEST = 0, NDMP_MESSAGE_REPLY = 1, }; typedef enum ndmp_header_message_type ndmp_header_message_type; @@ -123,9 +131,7 @@ struct ndmp_connect_open_reply { typedef struct ndmp_connect_open_reply ndmp_connect_open_reply; enum ndmp_auth_type { - NDMP_AUTH_NONE = 0, - NDMP_AUTH_TEXT = 1, - NDMP_AUTH_MD5 = 2, + NDMP_AUTH_NONE = 0, NDMP_AUTH_TEXT = 1, NDMP_AUTH_MD5 = 2, }; typedef enum ndmp_auth_type ndmp_auth_type; @@ -416,8 +422,7 @@ struct ndmp_execute_cdb_reply { typedef struct ndmp_execute_cdb_reply ndmp_execute_cdb_reply; enum ndmp_tape_open_mode { - NDMP_TAPE_READ_MODE = 0, - NDMP_TAPE_RDWR_MODE = 1, + NDMP_TAPE_READ_MODE = 0, NDMP_TAPE_RDWR_MODE = 1, }; typedef enum ndmp_tape_open_mode ndmp_tape_open_mode; @@ -546,8 +551,7 @@ enum ndmp_mover_halt_reason { typedef enum ndmp_mover_halt_reason ndmp_mover_halt_reason; enum ndmp_mover_mode { - NDMP_MOVER_MODE_READ = 0, - NDMP_MOVER_MODE_WRITE = 1, + NDMP_MOVER_MODE_READ = 0, NDMP_MOVER_MODE_WRITE = 1, }; typedef enum ndmp_mover_mode ndmp_mover_mode; @@ -812,9 +816,7 @@ struct ndmp_notify_data_halted_request { typedef struct ndmp_notify_data_halted_request ndmp_notify_data_halted_request; enum ndmp_connect_reason { - NDMP_CONNECTED = 0, - NDMP_SHUTDOWN = 1, - NDMP_REFUSED = 2, + NDMP_CONNECTED = 0, NDMP_SHUTDOWN = 1, NDMP_REFUSED = 2, }; typedef enum ndmp_connect_reason ndmp_connect_reason; @@ -865,9 +867,7 @@ struct ndmp_log_file_request { typedef struct ndmp_log_file_request ndmp_log_file_request; enum ndmp_fs_type { - NDMP_FS_UNIX = 0, - NDMP_FS_NT = 1, - NDMP_FS_OTHER = 2, + NDMP_FS_UNIX = 0, NDMP_FS_NT = 1, NDMP_FS_OTHER = 2, }; typedef enum ndmp_fs_type ndmp_fs_type; From 14f82c4974c8e6268f149da467ba6f0b5861477f Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Wed, 13 Mar 2013 16:49:53 +0530 Subject: [PATCH 06/18] Added description of XDR files and fixed a few bugs. Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils, xdr. In each component the source code is in an src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. XDR is incomplete as of now. Issues (to be addressed in future commits): 1. Align code (Code seems to be aligned in local files, but is not in GitHub). 2. Support for spinlock locks. 3. Complete the XDR integration. --- comm/src/comm.c | 3 +- comm/src/comm.h | 5 +- comm/src/worker.c | 11 +-- xdr/src/ndmp_config.c | 178 ++++++++++++++++++++++++++++++++++++- xdr/src/ndmp_connect.c | 40 ++++++++- xdr/src/ndmp_xdr.c | 4 +- xdr/src/ndmp_xdr.h | 1 + xdr/src/ndmp_xdr_structs.h | 12 +++ 8 files changed, 237 insertions(+), 17 deletions(-) diff --git a/comm/src/comm.c b/comm/src/comm.c index bddb453..152b1b8 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -29,7 +29,7 @@ struct comm_context* comm_context() retval = calloc(1, sizeof(struct comm_context)); retval->sessions = init_queue(); retval->request_jobs = init_queue(); - retval->response_jobs = init_queue(); + retval->reply_jobs = init_queue(); } return retval; } @@ -257,7 +257,6 @@ void handle_a_client_request(int fd, struct comm_context *ctx) enqueue(ctx->request_jobs, txn); printf("\tcreated a new job on %d [%d bytes]\n", fd, txn->request.length); - } int session_comparator(void *target, void *elem) diff --git a/comm/src/comm.h b/comm/src/comm.h index 61f78c9..a589204 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -32,6 +32,7 @@ struct client_endpoint { struct comm_message { int message_id; + int seq_num; char message[MAX_MESSAGE_SIZE]; int length; int whence; @@ -45,7 +46,7 @@ struct session { struct client_txn { struct session client_session; struct comm_message request; - struct comm_message response; + struct comm_message reply; }; typedef void (*message_handler) (struct client_txn *); @@ -53,7 +54,7 @@ struct comm_context { message_handler marshal_unmarshal; struct queue_hdr *sessions; struct queue_hdr *request_jobs; - struct queue_hdr *response_jobs; + struct queue_hdr *reply_jobs; int maxfds; }; diff --git a/comm/src/worker.c b/comm/src/worker.c index 9b441ba..ffd1b3b 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -83,6 +83,7 @@ void *process_response(void *context) { int write_result; struct comm_message response; + response->seq_num = 1; struct comm_context *ctx = (struct comm_context *)context; struct client_txn *job; while (1) { @@ -110,18 +111,18 @@ void *process_response(void *context) int write_message(struct client_txn *job) { struct session tmp; - struct comm_message response; + struct comm_message reply; int fd, sent_bytes; tmp = job->client_session; - response = job->response; + reply = job->reply; fd = tmp.session_id; - if (response.length > 0) { + if (reply.length > 0) { - sent_bytes = send(fd,response.message,response.length,0); + sent_bytes = send(fd,reply.message,reply.length,0); printf("Sent a %d byte response to (%s,%d) on sock %d\n", sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), ntohs(tmp.client_info.client.sin_port), fd); } - return -1 * (sent_bytes != response.length); + return -1 * (sent_bytes != reply.length); } diff --git a/xdr/src/ndmp_config.c b/xdr/src/ndmp_config.c index 4d949e9..8f224ee 100644 --- a/xdr/src/ndmp_config.c +++ b/xdr/src/ndmp_config.c @@ -9,42 +9,214 @@ #include +/* + * Each of the functions below take a client_txn and an XDR request stream as + * parameters. The client_txn structure is defined in comm.h and stores + * encoded requests and replies. + * + * By the time control reaches any of the below functions the message type is + * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. + * In each of the functions below we examine the structure that comes after + * the NDMP header. We then create the appropriate full NDMP reply message + * (including header) based on the client's request. Finally, we XDR encode + * (marshal) this reply message into txn. + * + * In summary, each function in this layer has 3 parts: + * 1. Decode rest of request message if present (apart from header) + * 2. Create appropriate message reply (including header) + * 3. Encode reply message and add to txn + * + */ + void ndmp_config_get_host_info(struct client_txn *, XDR*) { - + /* NDMP_CONFIG_GET_HOST_INFO + * + * no request arguments + * + * struct ndmp_config_get_host_info_reply + * { + * ndmp_error error; + * string hostname<>; + * string os_type<>; + * string os_vers<>; + * string hostid<>; + * }; + */ } void ndmp_config_get_connection_type(struct client_txn *, XDR* ) { - + /* NDMP_CONFIG_GET_CONNECTION_TYPE + * + * no request arguments + * + * enum ndmp_addr_type + * { + * NDMP_ADDR_LOCAL, + * NDMP_ADDR_TCP, + * NDMP_ADDR_FC, + * NDMP_ADDR_IPC + * }; + * + * struct ndmp_config_get_connection_type_reply + * { + * ndmp_error error; + * ndmp_addr_type addr_types<>; + * }; + * + */ } void ndmp_config_get_auth_attr(struct client_txn *, XDR* ) { + /* /* NDMP_CONFIG_GET_AUTH_ATTR + * + * struct ndmp_config_get_auth_attr_request + * { + * ndmp_auth_type auth_type; + * }; + * + * struct ndmp_config_get_auth_attr_reply + * { + * ndmp_error error; + * ndmp_auth_attr server_attr; + * }; + */ } void ndmp_config_get_butype_info(struct client_txn *, XDR* ) { + /* NDMP_CONFIG_GET_BUTYPE_INFO + * + * No request arguments + * + * backup type attributes + * const NDMP_BTYPE_BACKUP_FILE_HISTORY = 0x0001; + * const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; + * const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; + * const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; + * const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; + * const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; + * const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; + * const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; + * const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; + * + * struct ndmp_butype_info + * { + * string butype_name <>; + * ndmp_pval default_env <>; + * u_long attrs; + * }; + * struct ndmp_config_get_butype_attr_reply + * { + * ndmp_error error; + * ndmp_butype_info butype_info <>; + * }; + */ } void ndmp_config_get_fs_info(struct client_txn *, XDR* ) { + /* /* NDMP_CONFIG_GET_FS_INFO + * + * No request arguments + * + * const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; + * const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; + * const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; + * const NDMP_FS_INFO_TOTOAL_INODES_INVALID = 0x00000008; + * const NDMP_FS_INFO_USED_INNODES_INVALID = 0x00000010; + * + * struct ndmp_fs_info + * { + * u_long invalid; /* invalid bit + * string fs_type <>; + * string fs_logical_device <>; + * string fs_physical_device <>; + * ndmp_u_quad total_size; + * ndmp_u_quad used_size; + * ndmp_u_quad avail_size; + * ndmp_u_quad total_inodes; + * ndmp_u_quad used_inodes; + * ndmp_pval fs_env <>; + * string fs_status<>; + * }; + * + * struct ndmp_config_get_fs_info_reply + * { + * ndmp_error error; + * ndmp_fs_info fs_info <>; + * }; + */ } void ndmp_config_get_tape_info(struct client_txn *, XDR* ) { + /* NDMP_CONFIG_GET_TAPE_INFO + * + * tape attributes + * + * const NDMP_TAPE_ATTR_REWIND = 0x00000001; + * const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; + * + * No request arguments + * + * struct ndmp_device_capability + * { + * string device <>; + * u_long attr; + * ndmp_pval capability <>; + * }; + * + * struct ndmp_device_info + * { + * string model <>; + * ndmp_device_capability caplist <>; + * }; + * + * struct ndmp_config_get_tape_info_reply + * { + * ndmp_error error; + * ndmp_device_info tape_info <>; + * }; + */ } void ndmp_config_get_scsi_info(struct client_txn *, XDR* ) { + /* NDMP_CONFIG_GET_SCSI_INFO + * + * No request arguments + * + * no SCSI attributes + * + * struct ndmp_config_get_scsi_info_reply + * { + * ndmp_error error; + * ndmp_device_info scsi_info <>; + * }; + */ } void ndmp_config_get_server_info(struct client_txn *, XDR* ) { - + /* NDMP_CONFIG_GET_SERVER_INFO + * + * no request arguments + * + * struct ndmp_config_get_server_info_reply + * { + * ndmp_error error; + * string vendor_name<>; + * string product_name<>; + * string revision_number<>; + * ndmp_auth_type auth_type<>; + * }; + */ } diff --git a/xdr/src/ndmp_connect.c b/xdr/src/ndmp_connect.c index 8d5d95b..d8527d1 100644 --- a/xdr/src/ndmp_connect.c +++ b/xdr/src/ndmp_connect.c @@ -9,13 +9,47 @@ #include +/* + * Each of the functions below take a client_txn and an XDR request stream as + * parameters. The client_txn structure is defined in comm.h and stores + * encoded requests and replies. + * + * By the time control reaches any of the below functions the message type is + * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. + * In each of the functions below we examine the structure that comes after + * the NDMP header. We then create the appropriate full NDMP reply message + * (including header) based on the client's request. Finally, we XDR encode + * (marshal) this reply message into txn. + * + * In summary, each function in this layer has 3 parts: + * 1. Decode rest of request message if present (apart from header) + * 2. Create appropriate message reply (including header) + * 3. Encode reply message and add to txn + * + */ + + void ndmp_connect_open(struct client_txn *txn, XDR* request_stream) { - + /* NDMP_CONNECT_OPEN + * + * struct ndmp_connect_open_request + * { + * u_short protocol_version; + * }; + * + * struct ndmp_connect_open_reply + * { + * ndmp_error error; + * }; + * + */ } -void ndmp_connect_close(struct client_txn *, XDR*) +void ndmp_connect_close(struct client_txn *, XDR* request_stream) { - + /* NDMP_CONNECT_CLOSE */ + /* no request arguments */ + /* no reply message */ } diff --git a/xdr/src/ndmp_xdr.c b/xdr/src/ndmp_xdr.c index 528399a..1fb25a3 100644 --- a/xdr/src/ndmp_xdr.c +++ b/xdr/src/ndmp_xdr.c @@ -22,7 +22,7 @@ void xdr_decode_encode(struct client_txn *txn) * 1. Decode the message type from txn->request * 2. Depending on the message type call the appropriate * NDMP message handler. When the handler returns, - * txn->response will hold the marshaled (encoded)NDMP response + * txn->response will hold the marshaled (encoded) NDMP response * 3. Enqueue the response into the response queue */ @@ -40,7 +40,7 @@ void xdr_decode_encode(struct client_txn *txn) ndmp_dispatch(message_type)(txn, request_stream); - enqueue(ctx->response_jobs, txn); + enqueue(ctx->reply_jobs, txn); } diff --git a/xdr/src/ndmp_xdr.h b/xdr/src/ndmp_xdr.h index 61966ae..5a5b616 100644 --- a/xdr/src/ndmp_xdr.h +++ b/xdr/src/ndmp_xdr.h @@ -12,6 +12,7 @@ #include #include +#include /* * xdr_decode_encode is the entry point diff --git a/xdr/src/ndmp_xdr_structs.h b/xdr/src/ndmp_xdr_structs.h index 2cd6671..f6c3fcd 100644 --- a/xdr/src/ndmp_xdr_structs.h +++ b/xdr/src/ndmp_xdr_structs.h @@ -253,6 +253,18 @@ typedef struct ndmp_config_get_server_info_reply ndmp_config_get_server_info_rep #define NDMP_BUTYPE_BACKUP_UTF8 0x0080 #define NDMP_BUTYPE_RECOVER_UTF8 0x0100 +struct ndmp_pval { + char *name; + char *value; +}; +typedef struct ndmp_pval ndmp_pval; + +struct ndmp_u_quad { + u_long high; + u_long low; +}; +typedef struct ndmp_u_quad ndmp_u_quad; + struct ndmp_butype_info { char *butype_name; struct { From 9b52076efa27edcdd1c8534583f1987d9046e5a3 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 18 Mar 2013 12:10:36 +0530 Subject: [PATCH 07/18] Changes: 1. A framework for NDMP message handler implementation has be set up. Two handlers - NDMP_NOTIFY_CONNECT and NDMP_CONNECT_OPEN have beem already implemented. Please see comments in ndmp/src/ndmp_connect.c for more information. More message handler implementations coming soon. 2. State machines for sessions have been implemented in the form of queues (in ndmp/src/ndmp_msg.c). 3. The old XDR folder has been renamed NDMP. Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils, ndmp. In each component the source code is in an src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. NDMP contains NDMP message handlers and session state machines. comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe (spinlock capability will be added in a future commit). utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. ndmp/src/ndmp_msg.c, ndmp/src/ndmp_msg.h Maintains three state queues for sessions (connection, data, mover). Is also responsible for unmarshalling the NDMP message headers from client requests and passing them to appropriate message handlers which deal with the rest of the message before sending a reply. ndmp/src/ndmp.x NDMP structures information (obtained from NDMP source). We use rpcgen to generate ndmp.h and ndmp_xdr.c, which provide functions for encoding and decoding. ndmp/src/ndmp_connect.c Message handlers for CONNECT interface. ndmp/src/ndmp_config.c Message handlers for CONFIG interface. Next steps (to be addressed in future commits): 1. Align code (Code seems to be aligned in local files, but is not in GitHub). 2. Implement more NDMP message handlers (config interface). --- comm/src/comm.c | 13 + comm/src/comm.h | 4 +- comm/src/makefile | 12 + comm/src/worker.c | 51 +- comm/src/worker.h | 1 + makefile | 10 + ndmp/src/files | 8 + ndmp/src/makefile | 25 + ndmp/src/ndmp.x | 1067 ++++++++++++++++++++++++++++++++++++++ ndmp/src/ndmp_config.c | 223 ++++++++ ndmp/src/ndmp_connect.c | 106 ++++ ndmp/src/ndmp_msg.c | 206 ++++++++ ndmp/src/ndmp_msg.h | 94 ++++ ndmp/src/test/makefile | 30 ++ ndmp/src/test/objs | 9 + ndmp/src/test/testndmp | Bin 0 -> 123439 bytes ndmp/src/test/testndmp.c | 21 + ndmp/src/test/testndmp.o | Bin 0 -> 6792 bytes utils/src/makefile | 14 + 19 files changed, 1871 insertions(+), 23 deletions(-) create mode 100644 comm/src/makefile create mode 100644 makefile create mode 100644 ndmp/src/files create mode 100644 ndmp/src/makefile create mode 100644 ndmp/src/ndmp.x create mode 100644 ndmp/src/ndmp_config.c create mode 100644 ndmp/src/ndmp_connect.c create mode 100644 ndmp/src/ndmp_msg.c create mode 100644 ndmp/src/ndmp_msg.h create mode 100644 ndmp/src/test/makefile create mode 100644 ndmp/src/test/objs create mode 100755 ndmp/src/test/testndmp create mode 100644 ndmp/src/test/testndmp.c create mode 100644 ndmp/src/test/testndmp.o create mode 100644 utils/src/makefile diff --git a/comm/src/comm.c b/comm/src/comm.c index 152b1b8..c457294 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -183,6 +183,7 @@ int accept_all_connections(int listener, fd_set *read_socks, { struct client_endpoint endpoint; struct session* new_session; + struct client_txn* txn; int num_new_sessions = 0; @@ -209,6 +210,17 @@ int accept_all_connections(int listener, fd_set *read_socks, printf("Connection request from %s at %d\n", inet_ntoa(endpoint.client.sin_addr), ntohs(endpoint.client.sin_port)); + + txn = (struct client_txn *) malloc(sizeof(struct client_txn)); + + /* + * Create a psuedo NDMP request for the tcp_connect request + * so that a NDMP_NOTIFY_CONNECTED response + */ + + txn->client_session = *new_session; + txn->request.is_tcp_connect = 0; + //enqueue(ctx->request_jobs, txn); num_new_sessions++; } // } while (endpoint.fd != -1); @@ -244,6 +256,7 @@ void handle_a_client_request(int fd, struct comm_context *ctx) txn->client_session = tmp; txn->request.length = recv(fd, txn->request.message, MAX_MESSAGE_SIZE, 0); + txn->request.is_tcp_connect = 0; if (txn->request.length == 0) { /* * Event on this socket indicated socket closure diff --git a/comm/src/comm.h b/comm/src/comm.h index a589204..8e5c584 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -31,11 +31,9 @@ struct client_endpoint { }; struct comm_message { - int message_id; - int seq_num; + int is_tcp_connect; char message[MAX_MESSAGE_SIZE]; int length; - int whence; }; struct session { diff --git a/comm/src/makefile b/comm/src/makefile new file mode 100644 index 0000000..41f4799 --- /dev/null +++ b/comm/src/makefile @@ -0,0 +1,12 @@ +CFLAGS = -g -I . -I ../../utils/src -DDEBUG + +all: comm.o worker.o + +comm.o: comm.c comm.h + gcc $(CFLAGS) -c comm.c + +worker.o: worker.h worker.c comm.h + gcc $(CFLAGS) -c worker.c + +clean: + rm *.o diff --git a/comm/src/worker.c b/comm/src/worker.c index ffd1b3b..d85b8fe 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -20,14 +20,14 @@ void create_worker_threads(int thread_pool_size) int i; if (threads == NULL) { threads = (pthread_t *)malloc((thread_pool_size+1)* - sizeof(pthread_t)); + sizeof(pthread_t)); for (i=0; imarshal_unmarshal(job); +#ifdef DEBUG + + if (job->request.is_tcp_connect != 1) { + + printf("Request message: \n"); + hexdump(job->request.message, job->request.length); + } +#endif + ctx->marshal_unmarshal(job); + /* - * Add response to response queue - */ - enqueue(ctx->response_jobs, job); + * Add response to response queue + */ + enqueue(ctx->reply_jobs, job); + printf("Processed a job \n"); // Process next job } @@ -76,23 +85,21 @@ void* run_job(void *context) pthread_yield(); // Let another thread run } } - return *ctx; + return ctx; } void *process_response(void *context) { int write_result; - struct comm_message response; - response->seq_num = 1; struct comm_context *ctx = (struct comm_context *)context; struct client_txn *job; while (1) { - + /* * Process the next job in response queue and send * response to client */ - job = (struct client_txn *)dequeue(ctx->response_jobs); + job = (struct client_txn *)dequeue(ctx->reply_jobs); if (job != NULL) { // Write message to client @@ -113,16 +120,20 @@ int write_message(struct client_txn *job) struct session tmp; struct comm_message reply; int fd, sent_bytes; + int len; tmp = job->client_session; reply = job->reply; fd = tmp.session_id; if (reply.length > 0) { - +#ifdef DEBUG + printf("Reply message:\n"); + hexdump(reply.message,reply.length); +#endif sent_bytes = send(fd,reply.message,reply.length,0); printf("Sent a %d byte response to (%s,%d) on sock %d\n", - sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), - ntohs(tmp.client_info.client.sin_port), fd); + sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), + ntohs(tmp.client_info.client.sin_port), fd); } return -1 * (sent_bytes != reply.length); } diff --git a/comm/src/worker.h b/comm/src/worker.h index 6a39e04..1bbd1d3 100644 --- a/comm/src/worker.h +++ b/comm/src/worker.h @@ -11,6 +11,7 @@ #define __H_WORKER__ #include +#include #define THREAD_POOL_SIZE 1 diff --git a/makefile b/makefile new file mode 100644 index 0000000..b3021fb --- /dev/null +++ b/makefile @@ -0,0 +1,10 @@ +all: + (cd comm/src; make) + (cd utils/src; make) + (cd ndmp/src; make) + +clean: + (cd comm/src; make clean) + (cd utils/src; make clean) + (cd ndmp/src; make clean) + diff --git a/ndmp/src/files b/ndmp/src/files new file mode 100644 index 0000000..16c8ae9 --- /dev/null +++ b/ndmp/src/files @@ -0,0 +1,8 @@ +makefile +ndmp_config.c +ndmp_connect.c +ndmp.h +ndmp_msg.c +ndmp_msg.h +ndmp.x +ndmp_xdr.c diff --git a/ndmp/src/makefile b/ndmp/src/makefile new file mode 100644 index 0000000..f83caad --- /dev/null +++ b/ndmp/src/makefile @@ -0,0 +1,25 @@ +ROOT=../.. +COM=$(ROOT)/comm +UTILS=$(ROOT)/utils +CFLAGS = -g -I. -I$(COM)/src -I$(UTILS)/src -DDEBUG +HEADERS = ndmp.h ndmp_msg.h + +all: ndmp_xdr.o ndmp_config.o ndmp_connect.o ndmp_msg.o + +ndmp.h: ndmp.x + rpcgen ndmp.x + +ndmp_xdr.o: ndmp.h + gcc $(CFLAGS) -c ndmp_xdr.c + +ndmp_config.o: ndmp_config.c $(HEADERS) + gcc $(CFLAGS) -c ndmp_config.c + +ndmp_connect.o: ndmp_connect.c $(HEADERS) + gcc $(CFLAGS) -c ndmp_connect.c + +ndmp_msg.o: ndmp_msg.c $(HEADERS) + gcc $(CFLAGS) -c ndmp_msg.c + +clean: + rm *.o ndmp.h ndmp_xdr.c diff --git a/ndmp/src/ndmp.x b/ndmp/src/ndmp.x new file mode 100644 index 0000000..700307c --- /dev/null +++ b/ndmp/src/ndmp.x @@ -0,0 +1,1067 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +/* -*- Mode: C -*- + * ndmp.x + * + * Description : NDMP protocol rpcgen file. + * + * Copyright (c) 1999 Intelliguard Software, Network Appliance. All Rights Reserved. + * + * $Id: ndmp.x,v 1.11 1998/05/26 03:52:12 tim Exp $ + */ + + +#define VER 3 +const NDMPVER = VER; +const NDMPPORT = 10000; + +struct ndmp_u_quad +{ + u_long high; + u_long low; +}; + +struct ndmp_pval +{ + string name<>; + string value<>; +}; + +enum ndmp_error +{ + NDMP_NO_ERR, /* No error */ + NDMP_NOT_SUPPORTED_ERR, /* Call is not supported */ + NDMP_DEVICE_BUSY_ERR, /* The device is in use */ + NDMP_DEVICE_OPENED_ERR, /* Another tape or scsi device + *is already open */ + NDMP_NOT_AUTHORIZED_ERR, /* connection has not been authorized */ + NDMP_PERMISSION_ERR, /* some sort of permission problem */ + NDMP_DEV_NOT_OPEN_ERR, /* SCSI device is not open */ + NDMP_IO_ERR, /* I/O error */ + NDMP_TIMEOUT_ERR, /* command timed out */ + NDMP_ILLEGAL_ARGS_ERR, /* illegal arguments in request */ + NDMP_NO_TAPE_LOADED_ERR, /* Cannot open because there is + * no tape loaded */ + NDMP_WRITE_PROTECT_ERR, /* tape cannot be open for write */ + NDMP_EOF_ERR, /* Command encountered EOF */ + NDMP_EOM_ERR, /* Command encountered EOM */ + NDMP_FILE_NOT_FOUND_ERR, /* File not found during restore */ + NDMP_BAD_FILE_ERR, /* The file descriptor is invalid */ + NDMP_NO_DEVICE_ERR, /* The device is not at that target */ + NDMP_NO_BUS_ERR, /* Invalid controller */ + NDMP_XDR_DECODE_ERR, /* Can't decode the request argument */ + NDMP_ILLEGAL_STATE_ERR, /* Call can't be performed at this state */ + NDMP_UNDEFINED_ERR, /* Undefined Error */ + NDMP_XDR_ENCODE_ERR, /* Can't encode the reply argument */ + NDMP_NO_MEM_ERR, /* no memory */ + NDMP_CONNECT_ERR /* Error connecting to another NDMP server */ + +}; + +enum ndmp_header_message_type +{ + NDMP_MESSAGE_REQUEST, + NDMP_MESSAGE_REPLY +}; + +enum ndmp_message +{ + NDMP_CONNECT_OPEN = 0x900, /* CONNECT INTERFACE */ + NDMP_CONNECT_CLIENT_AUTH = 0x901, + NDMP_CONNECT_CLOSE = 0x902, + NDMP_CONNECT_SERVER_AUTH = 0x903, + + NDMP_CONFIG_GET_HOST_INFO = 0x100, /* CONFIG INTERFACE */ + NDMP_CONFIG_GET_CONNECTION_TYPE = 0x102, /* NDMP_CONFIG_GET_MOVER_TYPE on v2 */ + NDMP_CONFIG_GET_AUTH_ATTR = 0x103, + NDMP_CONFIG_GET_BUTYPE_INFO = 0x104, /* new from v3 */ + NDMP_CONFIG_GET_FS_INFO = 0x105, /* new from v3 */ + NDMP_CONFIG_GET_TAPE_INFO = 0x106, /* new from v3 */ + NDMP_CONFIG_GET_SCSI_INFO = 0x107, /* new from v3 */ + NDMP_CONFIG_GET_SERVER_INFO =0x108, /* new from v3 */ + + NDMP_SCSI_OPEN = 0x200, /* SCSI INTERFACE */ + NDMP_SCSI_CLOSE = 0x201, + NDMP_SCSI_GET_STATE = 0x202, + NDMP_SCSI_SET_TARGET = 0x203, + NDMP_SCSI_RESET_DEVICE = 0x204, + NDMP_SCSI_RESET_BUS = 0x205, + NDMP_SCSI_EXECUTE_CDB = 0x206, + + NDMP_TAPE_OPEN = 0x300, /* TAPE INTERFACE */ + NDMP_TAPE_CLOSE = 0x301, + NDMP_TAPE_GET_STATE = 0x302, + NDMP_TAPE_MTIO = 0x303, + NDMP_TAPE_WRITE = 0x304, + NDMP_TAPE_READ = 0x305, + NDMP_TAPE_EXECUTE_CDB = 0x307, + + NDMP_DATA_GET_STATE = 0x400, /* DATA INTERFACE */ + NDMP_DATA_START_BACKUP = 0x401, + NDMP_DATA_START_RECOVER = 0x402, + NDMP_DATA_ABORT = 0x403, + NDMP_DATA_GET_ENV = 0x404, + NDMP_DATA_STOP = 0x407, + NDMP_DATA_LISTEN = 0x409, /* new from V3 */ + NDMP_DATA_CONNECT = 0x40a, /* new from V3 */ + + NDMP_NOTIFY_DATA_HALTED =0x501, /* NOTIFY INTERFACE */ + NDMP_NOTIFY_CONNECTED = 0x502, + NDMP_NOTIFY_MOVER_HALTED = 0x503, + NDMP_NOTIFY_MOVER_PAUSED = 0x504, + NDMP_NOTIFY_DATA_READ =0x505, + + NDMP_LOG_FILE = 0x602, /* LOGGING INTERFACE */ + NDMP_LOG_MESSAGE = 0x603, /* new from v3 */ + + NDMP_FH_ADD_FILE = 0x703, /* FILE HISTORY INTERFACE */ + NDMP_FH_ADD_DIR = 0x704, + NDMP_FH_ADD_NODE = 0x705, + + NDMP_MOVER_GET_STATE = 0xa00, /* MOVER INTERFACE */ + NDMP_MOVER_LISTEN = 0xa01, + NDMP_MOVER_CONTINUE = 0xa02, + NDMP_MOVER_ABORT = 0xa03, + NDMP_MOVER_STOP = 0xa04, + NDMP_MOVER_SET_WINDOW = 0xa05, + NDMP_MOVER_READ = 0xa06, + NDMP_MOVER_CLOSE =0xa07, + NDMP_MOVER_SET_RECORD_SIZE =0xa08, + NDMP_MOVER_CONNECT =0xa09, /* new from V3 */ + + + NDMP_VENDORS_BASE = 0xf000, /* Reserved for the vendor + * specific usage + * from 0xf000 to 0xfeff */ + + NDMP_RESERVED_BASE = 0xff00 /* Reserved for prototyping + * from 0xff00 to 0xffff */ +}; + +struct ndmp_header +{ + u_long sequence; /* monotonically increasing number */ + u_long time_stamp; /* time stamp of message */ + ndmp_header_message_type message_type; /* what type of message */ + enum ndmp_message message; /* message number */ + u_long reply_sequence; /* reply is in response to */ + ndmp_error error; /* communications errors */ +}; + +/**********************/ +/* CONNECT INTERFACE */ +/**********************/ + +/* NDMP_CONNECT_OPEN */ +struct ndmp_connect_open_request +{ + u_short protocol_version; /* the version of protocol supported */ +}; + +struct ndmp_connect_open_reply +{ + ndmp_error error; +}; + +/* NDMP_CONNECT_CLIENT_AUTH */ +enum ndmp_auth_type +{ + NDMP_AUTH_NONE, /* no password is required */ + NDMP_AUTH_TEXT, /* the clear text password */ + NDMP_AUTH_MD5 /* md5 */ +}; + +struct ndmp_auth_text +{ + string auth_id<>; + string auth_password<>; + +}; + +struct ndmp_auth_md5 +{ + string auth_id<>; + opaque auth_digest[16]; +}; + +union ndmp_auth_data switch (enum ndmp_auth_type auth_type) +{ + case NDMP_AUTH_NONE: + void; + case NDMP_AUTH_TEXT: + struct ndmp_auth_text auth_text; + case NDMP_AUTH_MD5: + struct ndmp_auth_md5 auth_md5; +}; + +struct ndmp_connect_client_auth_request +{ + ndmp_auth_data auth_data; +}; + +struct ndmp_connect_client_auth_reply +{ + ndmp_error error; +}; + + +/* NDMP_CONNECT_CLOSE */ +/* no request arguments */ +/* no reply arguments */ + +/* NDMP_CONNECT_SERVER_AUTH */ +union ndmp_auth_attr switch (enum ndmp_auth_type auth_type) +{ + case NDMP_AUTH_NONE: + void; + case NDMP_AUTH_TEXT: + void; + case NDMP_AUTH_MD5: + opaque challenge[64]; +}; + +struct ndmp_connect_server_auth_request +{ + ndmp_auth_attr client_attr; +}; + +struct ndmp_connect_server_auth_reply +{ + ndmp_error error; + ndmp_auth_data server_result; +}; + + +/********************/ +/* CONFIG INTERFACE */ +/********************/ + +/* NDMP_CONFIG_GET_HOST_INFO */ +/* no request arguments */ +struct ndmp_config_get_host_info_reply +{ + ndmp_error error; + string hostname<>; /* host name */ + string os_type<>; /* The operating system type (i.e. + * SOLARIS) */ + string os_vers<>; /* The version number of the OS (i.e. + * 2.5) */ + string hostid<>; +}; + +enum ndmp_addr_type +{ + NDMP_ADDR_LOCAL, + NDMP_ADDR_TCP, + NDMP_ADDR_FC, + NDMP_ADDR_IPC +}; + +/* NDMP_CONFIG_GET_CONNECTION_TYPE */ +/* no request arguments */ +struct ndmp_config_get_connection_type_reply +{ + ndmp_error error; + ndmp_addr_type addr_types<>; +}; + +/* NDMP_CONFIG_GET_AUTH_ATTR */ +struct ndmp_config_get_auth_attr_request +{ + ndmp_auth_type auth_type; +}; + +struct ndmp_config_get_auth_attr_reply +{ + ndmp_error error; + ndmp_auth_attr server_attr; +}; + +/* NDMP_CONFIG_GET_SERVER_INFO */ +/* no requset arguments */ +struct ndmp_config_get_server_info_reply +{ + ndmp_error error; + string vendor_name<>; + string product_name<>; + string revision_number<>; + ndmp_auth_type auth_type<>; +}; + +/* backup type attributes */ +const NDMP_BUTYPE_BACKUP_FILE_HISTORY = 0x0001; +const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; +const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; +const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; +const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; +const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; +const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; +const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; +const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; + +struct ndmp_butype_info +{ + string butype_name<>; + ndmp_pval default_env<>; + u_long attrs; +}; + +/* NDMP_CONFIG_GET_BUTYPE_INFO */ +/* no request arguments */ +struct ndmp_config_get_butype_info_reply +{ + ndmp_error error; + ndmp_butype_info butype_info<>; +}; + +/* invalid bit */ +const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; +const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; +const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; +const NDMP_FS_INFO_TOTAL_INODES_INVALID = 0x00000008; +const NDMP_FS_INFO_USED_INODES_INVALID = 0x00000010; + +struct ndmp_fs_info +{ + u_long invalid; + string fs_type<>; + string fs_logical_device<>; + string fs_physical_device<>; + ndmp_u_quad total_size; + ndmp_u_quad used_size; + ndmp_u_quad avail_size; + ndmp_u_quad total_inodes; + ndmp_u_quad used_inodes; + ndmp_pval fs_env<>; + string fs_status<>; +}; + +/* NDMP_CONFIG_GET_FS_INFO */ +/* no request arguments */ +struct ndmp_config_get_fs_info_reply +{ + ndmp_error error; + ndmp_fs_info fs_info<>; +}; + +/* NDMP_CONFIG_GET_TAPE_INFO */ +/* no request arguments */ +/* tape attributes */ +const NDMP_TAPE_ATTR_REWIND = 0x00000001; +const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; + +struct ndmp_device_capability +{ + string device<>; + u_long attr; + ndmp_pval capability<>; +}; + +struct ndmp_device_info +{ + string model<>; + ndmp_device_capability caplist<>; + +}; +struct ndmp_config_get_tape_info_reply +{ + ndmp_error error; + ndmp_device_info tape_info<>; + +}; + +/* NDMP_CONFIG_GET_SCSI_INFO */ +/* jukebox attributes */ +struct ndmp_config_get_scsi_info_reply +{ + ndmp_error error; + ndmp_device_info scsi_info<>; +}; + +/******************/ +/* SCSI INTERFACE */ +/******************/ + +/* NDMP_SCSI_OPEN */ +struct ndmp_scsi_open_request +{ + string device<>; +}; + +struct ndmp_scsi_open_reply +{ + ndmp_error error; +}; + +/* NDMP_SCSI_CLOSE */ +/* no request arguments */ +struct ndmp_scsi_close_reply +{ + ndmp_error error; +}; + +/* NDMP_SCSI_GET_STATE */ +/* no request arguments */ +struct ndmp_scsi_get_state_reply +{ + ndmp_error error; + short target_controller; + short target_id; + short target_lun; +}; + +/* NDMP_SCSI_SET_TARGET */ +struct ndmp_scsi_set_target_request +{ + string device<>; + u_short target_controller; + u_short target_id; + u_short target_lun; +}; + +struct ndmp_scsi_set_target_reply +{ + ndmp_error error; +}; + +/* NDMP_SCSI_RESET_DEVICE */ +/* no request arguments */ +struct ndmp_scsi_reset_device_reply +{ + ndmp_error error; +}; + +/* NDMP_SCSI_RESET_BUS */ +/* no request arguments */ +struct ndmp_scsi_reset_bus_reply +{ + ndmp_error error; +}; + +/* NDMP_SCSI_EXECUTE_CDB */ +const NDMP_SCSI_DATA_IN = 0x00000001; /* Expect data from SCSI device */ +const NDMP_SCSI_DATA_OUT = 0x00000002; /* Transfer data to SCSI device */ + +struct ndmp_execute_cdb_request +{ + u_long flags; + u_long timeout; + u_long datain_len; /* Set for expected datain */ + opaque cdb<>; + opaque dataout<>; +}; + +struct ndmp_execute_cdb_reply +{ + ndmp_error error; + u_char status; /* SCSI status bytes */ + u_long dataout_len; + opaque datain<>; /* SCSI datain */ + opaque ext_sense<>; /* Extended sense data */ +}; + +/******************/ +/* TAPE INTERFACE */ +/******************/ +/* NDMP_TAPE_OPEN */ +enum ndmp_tape_open_mode +{ + NDMP_TAPE_READ_MODE, + NDMP_TAPE_RDWR_MODE +}; + +struct ndmp_tape_open_request +{ + string device<>; + ndmp_tape_open_mode mode; +}; + +struct ndmp_tape_open_reply +{ + ndmp_error error; +}; + +/* NDMP_TAPE_CLOSE */ +/* no request arguments */ +struct ndmp_tape_close_reply +{ + ndmp_error error; +}; + +/*NDMP_TAPE_GET_STATE */ +/* no request arguments */ +const NDMP_TAPE_STATE_NOREWIND = 0x0008; /* non-rewind device */ +const NDMP_TAPE_STATE_WR_PROT = 0x0010; /* write-protected */ +const NDMP_TAPE_STATE_ERROR = 0x0020; /* media error */ +const NDMP_TAPE_STATE_UNLOAD = 0x0040; /* tape will be unloaded when + * the device is closed */ + +/* invalid bit */ +const NDMP_TAPE_STATE_FILE_NUM_INVALID = 0x00000001; +const NDMP_TAPE_STATE_SOFT_ERRORS_INVALID = 0x00000002; +const NDMP_TAPE_STATE_BLOCK_SIZE_INVALID = 0x00000004; +const NDMP_TAPE_STATE_BLOCKNO_INVALID = 0x00000008; +const NDMP_TAPE_STATE_TOTAL_SPACE_INVALID = 0x00000010; +const NDMP_TAPE_STATE_SPACE_REMAIN_INVALID = 0x00000020; +const NDMP_TAPE_STATE_PARTITION_INVALID = 0x00000040; + +struct ndmp_tape_get_state_reply +{ + u_long invalid; + ndmp_error error; + u_long flags; + u_long file_num; + u_long soft_errors; + u_long block_size; + u_long blockno; + ndmp_u_quad total_space; + ndmp_u_quad space_remain; + u_long partition; +}; + +/* NDMP_TAPE_MTIO */ +enum ndmp_tape_mtio_op +{ + NDMP_MTIO_FSF, + NDMP_MTIO_BSF, + NDMP_MTIO_FSR, + NDMP_MTIO_BSR, + NDMP_MTIO_REW, + NDMP_MTIO_EOF, + NDMP_MTIO_OFF +}; + +struct ndmp_tape_mtio_request +{ + ndmp_tape_mtio_op tape_op; + u_long count; +}; + +struct ndmp_tape_mtio_reply +{ + ndmp_error error; + u_long resid_count; +}; + +/* NDMP_TAPE_WRITE */ +struct ndmp_tape_write_request +{ + opaque data_out<>; +}; + +struct ndmp_tape_write_reply +{ + ndmp_error error; + u_long count; +}; + +/* NDMP_TAPE_READ */ +struct ndmp_tape_read_request +{ + u_long count; +}; + +struct ndmp_tape_read_reply +{ + ndmp_error error; + opaque data_in<>; +}; + + +/* NDMP_TAPE_EXECUTE_CDB */ +typedef ndmp_execute_cdb_request ndmp_tape_execute_cdb_request; +typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; + + +/********************************/ +/* MOVER INTERFACE */ +/********************************/ +/* NDMP_MOVER_GET_STATE */ +enum ndmp_mover_state +{ + NDMP_MOVER_STATE_IDLE, + NDMP_MOVER_STATE_LISTEN, + NDMP_MOVER_STATE_ACTIVE, + NDMP_MOVER_STATE_PAUSED, + NDMP_MOVER_STATE_HALTED +}; + +enum ndmp_mover_pause_reason +{ + NDMP_MOVER_PAUSE_NA, + NDMP_MOVER_PAUSE_EOM, + NDMP_MOVER_PAUSE_EOF, + NDMP_MOVER_PAUSE_SEEK, + NDMP_MOVER_PAUSE_MEDIA_ERROR, + NDMP_MOVER_PAUSE_EOW +}; + +enum ndmp_mover_halt_reason +{ + NDMP_MOVER_HALT_NA, + NDMP_MOVER_HALT_CONNECT_CLOSED, + NDMP_MOVER_HALT_ABORTED, + NDMP_MOVER_HALT_INTERNAL_ERROR, + NDMP_MOVER_HALT_CONNECT_ERROR +}; + +/* mover address */ +enum ndmp_mover_mode +{ + NDMP_MOVER_MODE_READ, /* read from data connection; write to tape */ + NDMP_MOVER_MODE_WRITE /* write to data connection; read from tape */ +}; + +struct ndmp_tcp_addr +{ + u_long ip_addr; + u_short port; +}; + +struct ndmp_fc_addr +{ + u_long loop_id; +}; + +struct ndmp_ipc_addr +{ + opaque comm_data<>; +}; +union ndmp_addr switch (ndmp_addr_type addr_type) +{ + case NDMP_ADDR_LOCAL: + void; + case NDMP_ADDR_TCP: + ndmp_tcp_addr tcp_addr; + case NDMP_ADDR_FC: + ndmp_fc_addr fc_addr; + case NDMP_ADDR_IPC: + ndmp_ipc_addr ipc_addr; + +}; + +/* no request arguments */ +struct ndmp_mover_get_state_reply +{ + ndmp_error error; + ndmp_mover_state state; + ndmp_mover_pause_reason pause_reason; + ndmp_mover_halt_reason halt_reason; + u_long record_size; + u_long record_num; + ndmp_u_quad data_written; + ndmp_u_quad seek_position; + ndmp_u_quad bytes_left_to_read; + ndmp_u_quad window_offset; + ndmp_u_quad window_length; + ndmp_addr data_connection_addr; +}; + +/* NDMP_MOVER_LISTEN */ +struct ndmp_mover_listen_request +{ + ndmp_mover_mode mode; + ndmp_addr_type addr_type; +}; + +struct ndmp_mover_listen_reply +{ + ndmp_error error; + ndmp_addr data_connection_addr; +}; + +/* NDMP_MOVER_CONNECT */ +struct ndmp_mover_connect_request +{ + ndmp_mover_mode mode; + ndmp_addr addr; +}; + +struct ndmp_mover_connect_reply +{ + ndmp_error error; +}; +/* NDMP_MOVER_SET_RECORD_SIZE */ +struct ndmp_mover_set_record_size_request +{ + u_long len; +}; + +struct ndmp_mover_set_record_size_reply +{ + ndmp_error error; +}; + +/* NDMP_MOVER_SET_WINDOW */ +struct ndmp_mover_set_window_request +{ + ndmp_u_quad offset; + ndmp_u_quad length; +}; + +struct ndmp_mover_set_window_reply +{ + ndmp_error error; +}; + +/* NDMP_MOVER_CONTINUE */ +/* no request arguments */ +struct ndmp_mover_continue_reply +{ + ndmp_error error; +}; + + +/* NDMP_MOVER_ABORT */ +/* no request arguments */ +struct ndmp_mover_abort_reply +{ + ndmp_error error; +}; + +/* NDMP_MOVER_STOP */ +/* no request arguments */ +struct ndmp_mover_stop_reply +{ + ndmp_error error; +}; + +/* NDMP_MOVER_READ */ +struct ndmp_mover_read_request +{ + ndmp_u_quad offset; + ndmp_u_quad length; +}; + +struct ndmp_mover_read_reply +{ + ndmp_error error; +}; + +/* NDMP_MOVER_CLOSE */ +/* no request arguments */ +struct ndmp_mover_close_reply +{ + ndmp_error error; +}; + +/********************************/ +/* DATA INTERFACE */ +/********************************/ +/* NDMP_DATA_GET_STATE */ +/* no request arguments */ +enum ndmp_data_operation +{ + NDMP_DATA_OP_NOACTION, + NDMP_DATA_OP_BACKUP, + NDMP_DATA_OP_RESTORE +}; + +enum ndmp_data_state +{ + NDMP_DATA_STATE_IDLE, + NDMP_DATA_STATE_ACTIVE, + NDMP_DATA_STATE_HALTED, + NDMP_DATA_STATE_LISTEN, + NDMP_DATA_STATE_CONNECTED +}; + +enum ndmp_data_halt_reason +{ + NDMP_DATA_HALT_NA, + NDMP_DATA_HALT_SUCCESSFUL, + NDMP_DATA_HALT_ABORTED, + NDMP_DATA_HALT_INTERNAL_ERROR, + NDMP_DATA_HALT_CONNECT_ERROR +}; + +/* invalid bit */ +const NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID = 0x00000001; +const NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID = 0x00000002; + +struct ndmp_data_get_state_reply +{ + u_long invalid; + ndmp_error error; + ndmp_data_operation operation; + ndmp_data_state state; + ndmp_data_halt_reason halt_reason; + ndmp_u_quad bytes_processed; + ndmp_u_quad est_bytes_remain; + u_long est_time_remain; + ndmp_addr data_connection_addr; + ndmp_u_quad read_offset; + ndmp_u_quad read_length; +}; + +/* NDMP_DATA_START_BACKUP */ +struct ndmp_data_start_backup_request +{ + string bu_type<>; /* backup method to use */ + ndmp_pval env<>; /* Parameters that may modify backup */ +}; + +struct ndmp_data_start_backup_reply +{ + ndmp_error error; +}; + +/* NDMP_DATA_START_RECOVER */ +struct ndmp_name +{ + string original_path<>; + string destination_dir<>; + string new_name<>; /* Direct access restore only */ + string other_name<>; /* Direct access restore only */ + ndmp_u_quad node; /* Direct access restore only */ + ndmp_u_quad fh_info; /* Direct access restore only */ +}; + +struct ndmp_data_start_recover_request +{ + ndmp_pval env<>; + ndmp_name nlist<>; + string bu_type<>; +}; + +struct ndmp_data_start_recover_reply +{ + ndmp_error error; +}; + +/* NDMP_DATA_ABORT */ +/* no request arguments */ +struct ndmp_data_abort_reply +{ + ndmp_error error; +}; + +/* NDMP_DATA_STOP */ +/* no request arguments */ +struct ndmp_data_stop_reply +{ + ndmp_error error; +}; + +/* NDMP_DATA_GET_ENV */ +/* no request arguments */ +struct ndmp_data_get_env_reply +{ + ndmp_error error; + ndmp_pval env<>; +}; + +/* NDMP_DATA_LISTEN */ +struct ndmp_data_listen_request +{ + ndmp_addr_type addr_type; +}; + +struct ndmp_data_listen_reply +{ + ndmp_error error; + ndmp_addr data_connection_addr; +}; + +/* NDMP_DATA_CONNECT */ +struct ndmp_data_connect_request +{ + ndmp_addr addr; +}; +struct ndmp_data_connect_reply +{ + ndmp_error error; +}; + +/****************************************/ +/* NOTIFY INTERFACE */ +/****************************************/ +/* NDMP_NOTIFY_DATA_HALTED */ +struct ndmp_notify_data_halted_request +{ + ndmp_data_halt_reason reason; + string text_reason<>; +}; + +/* NDMP_NOTIFY_CONNECTED */ +enum ndmp_connect_reason +{ + NDMP_CONNECTED, /* Connect sucessfully */ + NDMP_SHUTDOWN, /* Connection shutdown */ + NDMP_REFUSED /* reach the maximum number of connections */ +}; + +struct ndmp_notify_connected_request +{ + ndmp_connect_reason reason; + u_short protocol_version; + string text_reason<>; +}; + +/* NDMP_NOTIFY_MOVER_PAUSED */ +struct ndmp_notify_mover_paused_request +{ + ndmp_mover_pause_reason reason; + ndmp_u_quad seek_position; +}; +/* No reply */ + +/* NDMP_NOTIFY_MOVER_HALTED */ +struct ndmp_notify_mover_halted_request +{ + ndmp_mover_halt_reason reason; + string text_reason<>; +}; +/* No reply */ + +/* NDMP_NOTIFY_DATA_READ */ +struct ndmp_notify_data_read_request +{ + ndmp_u_quad offset; + ndmp_u_quad length; +}; +/* No reply */ + +/********************************/ +/* LOG INTERFACE */ +/********************************/ +/* NDMP_LOG_MESSAGE */ +enum ndmp_log_type +{ + NDMP_LOG_NORMAL, + NDMP_LOG_DEBUG, + NDMP_LOG_ERROR, + NDMP_LOG_WARNING +}; + + +struct ndmp_log_message_request +{ + ndmp_log_type log_type; + u_long message_id; + string entry<>; +}; +/* No reply */ + +/* NDMP_LOG_FILE */ +struct ndmp_log_file_request +{ + string name<>; + ndmp_error error; +}; +/* No reply */ + + +/********************************/ +/* File History INTERFACE */ +/********************************/ +/* NDMP_FH_ADD_FILE */ +enum ndmp_fs_type +{ + NDMP_FS_UNIX, /* UNIX */ + NDMP_FS_NT, /* NT */ + NDMP_FS_OTHER +}; + +typedef string ndmp_path<>; +struct ndmp_nt_path +{ + ndmp_path nt_path; + ndmp_path dos_path; +}; + +union ndmp_file_name switch (ndmp_fs_type fs_type) +{ + case NDMP_FS_UNIX: + ndmp_path unix_name; + case NDMP_FS_NT: + ndmp_nt_path nt_name; + default: + ndmp_path other_name; +}; + +enum ndmp_file_type +{ + NDMP_FILE_DIR, + NDMP_FILE_FIFO, + NDMP_FILE_CSPEC, + NDMP_FILE_BSPEC, + NDMP_FILE_REG, + NDMP_FILE_SLINK, + NDMP_FILE_SOCK, + NDMP_FILE_REGISTRY, + NDMP_FILE_OTHER +}; + +/* invalid bit */ +const NDMP_FILE_STAT_ATIME_INVALID = 0x00000001; +const NDMP_FILE_STAT_CTIME_INVALID = 0x00000002; +const NDMP_FILE_STAT_GROUP_INVALID = 0x00000004; + +struct ndmp_file_stat +{ + u_long invalid; + ndmp_fs_type fs_type; + ndmp_file_type ftype; + u_long mtime; + u_long atime; + u_long ctime; + u_long owner; /* uid for UNIX, owner for NT */ + u_long group; /* gid for UNIX, NA for NT */ + u_long fattr; /* mode for UNIX, fattr for NT */ + ndmp_u_quad size; + u_long links; +}; + + +/* one file could have both UNIX and NT name and attributes */ +struct ndmp_file +{ + ndmp_file_name names<>; + ndmp_file_stat stats<>; + ndmp_u_quad node; /* used for the direct access */ + ndmp_u_quad fh_info; /* used for the direct access */ +}; + +struct ndmp_fh_add_file_request +{ + ndmp_file files<>; +}; + +/* No reply */ +/* NDMP_FH_ADD_DIR */ + +struct ndmp_dir +{ + ndmp_file_name names<>; + ndmp_u_quad node; + ndmp_u_quad parent; +}; + +struct ndmp_fh_add_dir_request +{ + ndmp_dir dirs<>; +}; +/* No reply */ + +/* NDMP_FH_ADD_NODE */ +struct ndmp_node +{ + ndmp_file_stat stats<>; + ndmp_u_quad node; + ndmp_u_quad fh_info; +}; + +struct ndmp_fh_add_node_request +{ + ndmp_node nodes<>; +}; +/* No reply */ + diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c new file mode 100644 index 0000000..8263cfe --- /dev/null +++ b/ndmp/src/ndmp_config.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include +#include + +/* + * Each of the functions below take a client_txn and an XDR request stream as + * parameters. The client_txn structure is defined in comm.h and stores + * encoded requests and replies. + * + * By the time control reaches any of the below functions the message type is + * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. + * In each of the functions below we examine the structure that comes after + * the NDMP header. We then create the appropriate full NDMP reply message + * (including header) based on the client's request. Finally, we XDR encode + * (marshal) this reply message into txn. + * + * In summary, each function in this layer has 3 parts: + * 1. Decode rest of request message if present (apart from header) + * 2. Create appropriate message reply (including header) + * 3. Encode reply message and add to txn + * + */ + +void ndmp_config_get_host_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_HOST_INFO + * + * no request arguments + * + * struct ndmp_config_get_host_info_reply + * { + * ndmp_error error; + * string hostname<>; + * string os_type<>; + * string os_vers<>; + * string hostid<>; + * }; + */ +} + +void ndmp_config_get_connection_type(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_CONNECTION_TYPE + * + * no request arguments + * + * enum ndmp_addr_type + * { + * NDMP_ADDR_LOCAL, + * NDMP_ADDR_TCP, + * NDMP_ADDR_FC, + * NDMP_ADDR_IPC + * }; + * + * struct ndmp_config_get_connection_type_reply + * { + * ndmp_error error; + * ndmp_addr_type addr_types<>; + * }; + * + */ +} + +void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* /* NDMP_CONFIG_GET_AUTH_ATTR + * + * struct ndmp_config_get_auth_attr_request + * { + * ndmp_auth_type auth_type; + * }; + * + * struct ndmp_config_get_auth_attr_reply + * { + * ndmp_error error; + * ndmp_auth_attr server_attr; + * }; + */ + +} + +void ndmp_config_get_butype_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_BUTYPE_INFO + * + * No request arguments + * + * backup type attributes + * const NDMP_BTYPE_BACKUP_FILE_HISTORY = 0x0001; + * const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; + * const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; + * const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; + * const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; + * const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; + * const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; + * const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; + * const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; + * + * struct ndmp_butype_info + * { + * string butype_name <>; + * ndmp_pval default_env <>; + * u_long attrs; + * }; + * struct ndmp_config_get_butype_attr_reply + * { + * ndmp_error error; + * ndmp_butype_info butype_info <>; + * }; + */ + +} + +void ndmp_config_get_fs_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* /* NDMP_CONFIG_GET_FS_INFO + * + * No request arguments + * + * const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; + * const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; + * const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; + * const NDMP_FS_INFO_TOTOAL_INODES_INVALID = 0x00000008; + * const NDMP_FS_INFO_USED_INNODES_INVALID = 0x00000010; + * + * struct ndmp_fs_info + * { + * u_long invalid; /* invalid bit + * string fs_type <>; + * string fs_logical_device <>; + * string fs_physical_device <>; + * ndmp_u_quad total_size; + * ndmp_u_quad used_size; + * ndmp_u_quad avail_size; + * ndmp_u_quad total_inodes; + * ndmp_u_quad used_inodes; + * ndmp_pval fs_env <>; + * string fs_status<>; + * }; + * + * struct ndmp_config_get_fs_info_reply + * { + * ndmp_error error; + * ndmp_fs_info fs_info <>; + * }; + */ + +} + +void ndmp_config_get_tape_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_TAPE_INFO + * + * tape attributes + * + * const NDMP_TAPE_ATTR_REWIND = 0x00000001; + * const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; + * + * No request arguments + * + * struct ndmp_device_capability + * { + * string device <>; + * u_long attr; + * ndmp_pval capability <>; + * }; + * + * struct ndmp_device_info + * { + * string model <>; + * ndmp_device_capability caplist <>; + * }; + * + * struct ndmp_config_get_tape_info_reply + * { + * ndmp_error error; + * ndmp_device_info tape_info <>; + * }; + */ + +} + +void ndmp_config_get_scsi_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_SCSI_INFO + * + * No request arguments + * + * no SCSI attributes + * + * struct ndmp_config_get_scsi_info_reply + * { + * ndmp_error error; + * ndmp_device_info scsi_info <>; + * }; + */ + +} + +void ndmp_config_get_server_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONFIG_GET_SERVER_INFO + * + * no request arguments + * + * struct ndmp_config_get_server_info_reply + * { + * ndmp_error error; + * string vendor_name<>; + * string product_name<>; + * string revision_number<>; + * ndmp_auth_type auth_type<>; + * }; + */ +} diff --git a/ndmp/src/ndmp_connect.c b/ndmp/src/ndmp_connect.c new file mode 100644 index 0000000..fdc2edd --- /dev/null +++ b/ndmp/src/ndmp_connect.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include +#include +#include + +/* + * Each of the functions below take a client_txn and an XDR request stream as + * parameters. The client_txn structure is defined in comm.h and stores + * encoded requests and replies. + * + * By the time control reaches any of the below functions the message type is + * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. + * In each of the functions below we examine the structure that comes after + * the NDMP header. We then create the appropriate full NDMP reply message + * (including header) based on the client's request. Finally, we XDR encode + * (marshal) this reply message into txn. + * + * In summary, each function in this layer has 3 parts: + * 1. Decode rest of request message if present (apart from header) + * 2. Create appropriate message reply (including header) + * 3. Encode reply message and add to txn + * + */ + + +void ndmp_connect_open(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_CONNECT_OPEN + * + * struct ndmp_connect_open_request + * { + * u_short protocol_version; + * }; + * + * struct ndmp_connect_open_reply + * { + * ndmp_error error; + * }; + * + */ + + struct ndmp_connect_open_request request; + struct ndmp_header reply_header; + struct ndmp_connect_open_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + xdr_ndmp_connect_open_request(request_stream, &request); + + session_info = get_session_info(txn->client_session.session_id); + + /* + * There could be concurrent sessions for the + * same client. Since this fuction updates shared data, + * it needs to be thread-safe. + */ + + enter_critical_section(session_info->s_lock); + + if (session_info->connection_state != LISTEN) + reply.error = NDMP_ILLEGAL_STATE_ERR; + else if (request.protocol_version >= 1 && request.protocol_version <= 3) + reply.error = NDMP_NO_ERR; + else if (request.protocol_version > 3) + reply.error = NDMP_ILLEGAL_ARGS_ERR; + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_connect_open_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_connect_open_reply(&reply_stream, &reply); + session_info->connection_state = CONNECTED; + /* TBD: What about other states? */ + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_connect_open_reply, &reply); + exit_critical_section(session_info->s_lock); +} + + +void ndmp_connect_close(struct client_txn *txn, + struct ndmp_header header, + XDR* request_stream) +{ + /* NDMP_CONNECT_CLOSE */ + /* no request arguments */ + /* no reply message */ +} + diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c new file mode 100644 index 0000000..7ea434d --- /dev/null +++ b/ndmp/src/ndmp_msg.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +int session_info_cmp (void *id, void *session); + +/* + * xdr_decode_encode is the entry point + * and callback method for the comm layer + * This is the first upcall made by a worker + * thread. + * + */ + +void xdr_decode_encode(struct client_txn *txn) +{ + /* + * 1. Decode the message type from txn->request + * 2. Depending on the message type call the appropriate + * NDMP message handler. When the handler returns, + * txn->response will hold the marshaled (encoded) NDMP response + * 3. Enqueue the response into the response queue + */ + + XDR request_stream, stream_len; + int message_type; + struct ndmp_header header; + char *buf, mesg_len[4]; + int len; + if (txn->request.is_tcp_connect == 1) { + header.message = 0xf001; + } + else { + xdrmem_create(&request_stream, txn->request.message+4, txn->request.length-4, + XDR_DECODE); + /* + * Read the ndmp header + */ + + xdr_ndmp_header(&request_stream, &header); + } + + ndmp_dispatch(header.message)(txn, header, &request_stream); + + buf = (char *)malloc(txn->reply.length+4); + memcpy(buf+4,txn->reply.message,txn->reply.length); + len = txn->reply.length | (1<<31); + xdrmem_create(&stream_len,mesg_len,4, XDR_ENCODE); + xdr_int(&stream_len, &len); + memcpy(buf,mesg_len,4); + memcpy(txn->reply.message, buf, txn->reply.length+4); + txn->reply.length +=4; + free(buf); +} + +ndmp_message_handler ndmp_dispatch(int message) { + + switch (message) { + case 0xf001: + return ndmp_accept_notify; + case 0x900: + return ndmp_connect_open; + case 0x902: + return ndmp_connect_close; + case 0x100: + return ndmp_config_get_host_info; + case 0x102: + return ndmp_config_get_connection_type; + case 0x103: + return ndmp_config_get_auth_attr; + case 0x104: + return ndmp_config_get_butype_info; + case 0x105: + return ndmp_config_get_fs_info; + case 0x106: + return ndmp_config_get_tape_info; + case 0x107: + return ndmp_config_get_scsi_info; + case 0x108: + return ndmp_config_get_server_info; + default: + return ndmp_error_message; + } +} + +void ndmp_error_message(struct client_txn *txn, + struct ndmp_header header, + XDR* requeststream) +{ + +} + +void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* request_stream) +{ + struct ndmp_notify_connected_request reply; + struct ndmp_header reply_header; + XDR reply_stream; + + header.sequence = 0; + header.message = 0x0502; + reply.reason = NDMP_CONNECTED; + reply.protocol_version = 3; + reply.text_reason = ""; + + set_header(header, &reply_header, NDMP_NO_ERR); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, + &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_notify_connected_request, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, + XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + xdr_ndmp_notify_connected_request(&reply_stream, &reply); +} + + +int get_next_seq_number() { + + static int sequence_number = 1; + + return sequence_number++; +} + +void set_header(ndmp_header req, ndmp_header *reply, ndmp_error err) +{ + + reply->sequence = get_next_seq_number(); + reply->time_stamp = (u_long) time(NULL); + reply->message_type = NDMP_MESSAGE_REPLY; + reply->message = req.message; + reply->reply_sequence = req.sequence; + reply->error = err; +} + + +struct ndmp_session_info* get_session_info(int session_id) { + + static struct queue_hdr *session_info_queue = NULL; + struct ndmp_session_info *retval; + struct lock *s_lock = get_lock(); + + /* + * This functon returns the ndmp_session_info + * struct. The ndmp_session_info structs are in + * a queue, keyed by session_id. The states are + * owned and managed by the caller(s). The queue + * does not manage them. The state updates must + * occur in a thread-safe manner. Hence the struct + * has a lock. + * + */ + enter_critical_section(s_lock); + if (session_info_queue == NULL) { + session_info_queue = init_queue(); + } + + /* + * Since we create a new sessions + * in this function, it needs to be + * thread-safe + */ + + retval = get_elem(session_info_queue, (void *)&session_id, + session_info_cmp); + if (retval == NULL) { + + /* + * This must be a new session + * set the the session states to LISTEN + */ + + retval = (struct ndmp_session_info*) malloc( + sizeof(struct ndmp_session_info)); + retval->session_id = session_id; + retval->connection_state = LISTEN; + retval->data_state = LISTEN; + retval->mover_state = LISTEN; + retval->s_lock = get_lock(); + enqueue(session_info_queue, retval); + } + exit_critical_section(s_lock); + return retval; +} + +int session_info_cmp (void *id, void *session) +{ + int session_id = *(int *) id; + int queue_elem_session_id = + ((struct ndmp_session_info *)session)->session_id; + + return session_id == queue_elem_session_id; +} + diff --git a/ndmp/src/ndmp_msg.h b/ndmp/src/ndmp_msg.h new file mode 100644 index 0000000..46e104a --- /dev/null +++ b/ndmp/src/ndmp_msg.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef __H__NDMP_XDR__ +#define __H__NDMP_XDR__ + +#include +#include +#include +#include + +enum ndmp_state {IDLE, LISTEN, CONNECTED, ACTIVE, HALTED}; +struct ndmp_session_info { + int session_id; + enum ndmp_state connection_state; + enum ndmp_state data_state; + enum ndmp_state mover_state; + struct lock *s_lock; /* for thread-safe updates to session states */ +}; + +/* + * xdr_decode_encode is the entry point + * and callback method for the comm layer + * This is the first upcall made by a worker + * thread. + * + */ + +void xdr_decode_encode(struct client_txn *txn); + +/* + * Each NDMP message will have a message handler that is + * responsible for decoding(unmarshaling) the NDMP XDR request + * and invoking the appropriate NDMP action + */ + +typedef void (*ndmp_message_handler)(struct client_txn *txn, + ndmp_header header, + XDR* request_stream); + +/* + * ndmp_dispatch determines the message handler for a given + * NDMP message type + */ + +ndmp_message_handler ndmp_dispatch(int message_type); + +/* + * get_next_seq_number returns the next number in + * sequence for messages + */ +int get_next_seq_number(); + +/* + * set_header sets up the fields in the header + * some fields of reply header depend + * on request header + */ + + void set_header(struct ndmp_header request, + struct ndmp_header *reply, ndmp_error err); +/* + * + * struct_ndmp_session_info* get_session_info(int session_id) + * returns the ndmp_session_info* that holds the session information (states) + * for session_id + */ + +struct ndmp_session_info* get_session_info(int session_id); + + +/* + * + * The various NDMP message handlers + */ +void ndmp_accept_notify(struct client_txn *txn, struct ndmp_header, XDR*); +void ndmp_connect_open(struct client_txn *txn, struct ndmp_header, XDR* request_stream); +void ndmp_connect_close(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_host_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_connection_type(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_auth_attr(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_butype_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_fs_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_tape_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_scsi_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_config_get_server_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_error_message(struct client_txn *, struct ndmp_header, XDR *); // For wrong message type +#endif diff --git a/ndmp/src/test/makefile b/ndmp/src/test/makefile new file mode 100644 index 0000000..cf808c0 --- /dev/null +++ b/ndmp/src/test/makefile @@ -0,0 +1,30 @@ + # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + # This file is part of glfs-ndmp. + # This file is licensed to you under your choice of the GNU Lesser + # General Public License, version 3 or any later version (LGPLv3 or + # later), or the GNU General Public License, version 2 (GPLv2), in all + # cases as published by the Free Software Foundation. + + +ROOT = ../../.. +SRC = testndmp.c +CFLAGS = -g -I $(ROOT)/comm/src -I $(ROOT)/ndmp/src -I $(ROOT)/utils/src -DDEBUG +LIBS = -lpthread +OBJS = $(ROOT)/ndmp/src/ndmp_connect.o \ + $(ROOT)/ndmp/src/ndmp_msg.o \ + $(ROOT)/ndmp/src/ndmp_config.o \ + $(ROOT)/ndmp/src/ndmp_xdr.o \ + $(ROOT)/comm/src/comm.o \ + $(ROOT)/comm/src/worker.o \ + $(ROOT)/utils/src/locks.o \ + $(ROOT)/utils/src/hexdump.o \ + $(ROOT)/utils/src/queue.o + +all: testndmp + +testndmp: testndmp.c + gcc $(CFLAGS) -c testndmp.c + gcc $(CFLAGS) -o testndmp testndmp.o $(OBJS) $(LIBS) + +clean: + rm *.o testndmp diff --git a/ndmp/src/test/objs b/ndmp/src/test/objs new file mode 100644 index 0000000..3125da9 --- /dev/null +++ b/ndmp/src/test/objs @@ -0,0 +1,9 @@ +./ndmp/src/ndmp_connect.o +./ndmp/src/ndmp_msg.o +./ndmp/src/ndmp_config.o +./ndmp/src/ndmp_xdr.o +./comm/src/comm.o +./comm/src/worker.o +./utils/src/locks.o +./utils/src/hexdump.o +./utils/src/queue.o diff --git a/ndmp/src/test/testndmp b/ndmp/src/test/testndmp new file mode 100755 index 0000000000000000000000000000000000000000..ac05a9b426f3e7316140c4e893bedfd28c3fb72c GIT binary patch literal 123439 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⪼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�(v~(S!3)aRf+HYk%pI z1xps1qj1z|fcm74B@31=Ff=%tP*`wM5=7ekg^&K$0URGyx@h5od5$@wMb1%CXXkd% zQAQaY39rvQ!67Ad#t4$?T*$NPw2;RB{>I%n`wd4KRcxtVwXv!^tkEr!Ub~@YHBRuw zQKa>i4e5qet8wbIecVVI=j=2!r<*f_I3@{O-^{sA>Rd3jd(A-VXhiEMP4StW!x)@& z6PyCuf&-;+Ocxx8kAR(s5j5tI)3*NB)>LZkhN{)&=>??=N*AkRPkQvZZ95_d`ywaF zRFyMy_#@7+%7(d24OF&VOq_8;$5r(W4$z6G;RJM?ikx<&Hs;CEGx~(7uyL4uh~vzR zf#huY(CAdr=r}++G%IxUv{l*Q@KRlPb|a1?4P2{ihCKjQpX_I!vL~&mjsaE&)COEq zU^#?raG(RlLnPvuP*ZYE2~+#HNuyQggDHOw(AiwN+(v63myVXmypv~#B~e+}N9!7T zT{Jq)Gkhwzt^sg58>+W&V3=%&I%tlM%E~?6YPb`$+Hl}dSD4;9Ge{1j>g+)gdj@(N z!eJ z9XOnbysPcy#H+{|ZsCzdHP_HbM!wTwfmS!L`@BAK4!sVCkTrK)oNmK0jzIwz1+I9f zb2m-Jm4|~9AEj@|V55qz283LV>6uQ)01nOyN7&dq8GBQ(_OvzpXNP;FtYc6C>8 zPkR`r9-t1!GUc_L!hJR8G{~VWqsN=tR%#pwcX$q)bZ=iHdQP}ZR9(yAR9(XsbibVA zw2g%o(dGn5?wrFMC6?=W6AMAM3R2s-O+KpO!bj%nY}Bw3uF*Rs5>Kd7gpUEGQwD=F zsCdX7lhm9&OlHHL{K;!4y^b+uV{>kF>yUV|XhnDpla1Z^LX{cHIVLym-{v~hmvYXq z<`spW2k8X)VM=1nQ#=dg%ndxRfu7Q4b|JJR|jXe(L#}qhg9*KwpQ0z-x~j`s^yOA z>D-E#(TZnXMa{=58Y&)gDSBb1I|Y1~=}qe?Eyz^2NA4_)xum&ocTmmw){qJkYo74d5%&>IStQL#O^>j$0{qwV6MeYgdC7ahr$Mh z)`N5x4i5}t(IXtK?697d(-jTMG27dtM$w#rMm=OAkrSPBEX)b9yzCDjd5D82Y4i^l z(OST(zhfEtIhWHAt1eFK13v0q+HROb8%;Xx zMK!LVy~C?vt?LfmO{n0-fMYF6RqWHP6vw{dR%OZ!VqNsGV@(Q0HPn(_9r|p{@y@)J{;+~69omd z=;?5E+D5r9yGOV=!YA$yefD&u?0ny-@*k!ba5v2f4OL0| zzTHsMnkF=T(-aUcsd!wpW})5k^!iPYi)^Lp!Wji#DD$C2U23H9Lr3ylVI$N&HU literal 0 HcmV?d00001 diff --git a/ndmp/src/test/testndmp.c b/ndmp/src/test/testndmp.c new file mode 100644 index 0000000..b4163da --- /dev/null +++ b/ndmp/src/test/testndmp.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +main() +{ + struct comm_context *ctx = comm_context(); + ctx->marshal_unmarshal = xdr_decode_encode; + comm_listen(ctx); +} + diff --git a/ndmp/src/test/testndmp.o b/ndmp/src/test/testndmp.o new file mode 100644 index 0000000000000000000000000000000000000000..bd9dde834e7d0f46ae1ab1c98b593a7f09b94e39 GIT binary patch literal 6792 zcmbtYU2GKB6}~gOX2-0(UfY=10jwoXf+_YcU}G%O5`#rCDop|{0tGdb@$Ptc?A_Vz z%xo~uLn_hyAk>IdRgfx$@(?AZQlnOBRHRB(t4N8OhenmE_N6~+n@CZbM$H>-Q0Y1M zp1V6fSzg*JcJ4Xf`9JsGxnrI>a{P;?VF*18aZt25jS8`lZqsv;oD)N0K%82*`2NC$ zkFqxq`v4yc7mwUrxCFnqkrR@<__h@N>P<0`6vC7OONQwbON#Mf8kU^Ql$?@kveaa3 zP_izZ63H&lkA!JSE@_!cD!Hurg)5+<)E`9B93yT{ah6C~KHw_aAta^cxcSgskf5@B zE`D%nXTvlRDLCF@b#870dq?oq{UQry{>q?cjQJ#HR91fezpFHHCQ@Koed z8!bPE!gLuPCqT95Fc3Q^=L+U&QfE{XR0WC5)4GC0ADTh!s<>=&(`#Ck9CE>#ZcB1A z3d}KV3tCH0x#Y;dTIzQz1=X447E+frCAXrQIi~7OZd3IRgR5o0Wrw@AO+z$EZrIx< zr?G7kO*tE3k0|n6LqN(5lBwrU04<}WF7E=eT}$dOFSbN~yDbwS#rJYj(Nt#d&qz)! zTj~Qe!aCEF5c(BhWK&Zr-X?47uK|*V);0_c@p_j^!WyL|6&WxSmSt^ECA8u_N=9a5 zC@{xVJnLSRCC0v)RjW7*vcAIr-KL1c){a9hN8{@p?ZoWBkqSAUwI{AFP@dh zq|LEmm3INT#Mrg0YNxgLY0ynsm*AN-uE4V&AAn$BwPmcSe*&${r!h*)^*$6pzm#l7 zacZHh{feWovnu%IhV}M(m zTeuM2cNuMqjcp4!Y=&`c5dHLQ7smz*;J+8dR@-4lhU?Pd`lK4PF*{`J=t0B&E--`! z zJYhe;STE8xQWSgK0@@URhNoeCn(2k7yec3)qtFb4g69{j&5~PKot?2~rYEbO-&~z6 z`_00l7lk69FQ|Xb$g75hFer++)jFo&yO9UKwo$QOt4SLXxnbm&YK?pmQ)@((z;#N| z`Gy%|o$p|YZ!wfCN2tdhQ->upL{u6!1 zh2Q`1XQm0&+IGo_98q&tmr9}Vn>E|5y0uUQZlii$gq3;_^2BM53^Hg*KwJYQE~*P4;L3ZQKl>rL>4IROc#s|Y$(uj~siw4-7JVc#vb zqJ{iW9hY&F&Vk4b_F6dft}hLcZPCA_sjqq${y>wXjL@p`lUu4)u}cidyiFkYc4J3 zy0CIBYOu6U*%dNTXm2xg1MEm~MI3$TRBk>uouA21#rJ4?2dKpjh4w*vKyMe>xCZPY z$U$!!+$&HBXrcfp+peGU-9Q)N`Ac=c1IwL%wwmWwOth^Sv9E zK>@*hc)k`ni!eulnk$+L+^Un82O}?!WqvV)myAS9?qahHbwYFUigp$k@oW$WRjku= z0>>}A>#gDKI^#4C{-~!+J@@kE_ znHw(yh_kbZ&k*GSc=~e>ePi{cyTF#vj!ik_BX}sDpi{ z_-81--e(ve|CHqMzX2Hf)Oi9a$0)5^hHWezU(c67yOaF{eOB!ve|pk(dj1aCYq_3J z$3M$7*g^L?VXe;y(mg}=voTvFb^RKC8Hi5(Yjo&eHfFE;+7B3Ok#v2T;=eAr_CwdL z5#)L9D0>cr!T1pw;CmfDyj%I}__(J!#h<0~_j!=V2ag|@#c9+_icfCGF-<2r?pVyD zQznRa>M-JT$h2dc6M{D1XK=oHN+BUn7E=Z`A$NQyy!W%9)bG0kPK&{$3H3+eIV=kf0E(fBmN@8e@y&UhF8e{b%yUF{0)X1bhO`OxX$}G48K5r@NZZg zy8l_i|DoU({toerpFc8O=daI)?myl| za*&4nlR|((D^j{!+JHyWtKf&-XDfePO!yhJop5glbJjw8%6aN^)Um^ch zhTFuiG5mhY|2c-234fL0ZxQ}F!#||B?=t*9r2hwoKTG-_GW;mvcIz zdiODWocvEQ{1WLOX1G4*4>SCy6!&Wk{~h5g4AVksp&jdC;6vmy(SP*Z0=|;kYi^HyY@>74i7jlD?z4 R|BuiJ2FG&}Rk_6T`7cl6s`LN= literal 0 HcmV?d00001 diff --git a/utils/src/makefile b/utils/src/makefile new file mode 100644 index 0000000..5d0975f --- /dev/null +++ b/utils/src/makefile @@ -0,0 +1,14 @@ +CFLAGS = -g -I . +all: queue.o locks.o hexdump.o + +queue.o: queue.h queue.c locks.c + gcc $(CFLAGS) -c queue.c + +locks.o: locks.h locks.c + gcc $(CFLAGS) -c locks.c + +hexdump.o: hexdump.c hexdump.h + gcc $(CFLAGS) -c hexdump.c + +clean: + rm *.o From 9de81b215bc89f1c51a93d64858d54dcb2b548f5 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 18 Mar 2013 12:20:27 +0530 Subject: [PATCH 08/18] Changes: 1. A framework for NDMP message handler implementation has be set up. Two handlers - NDMP_NOTIFY_CONNECT and NDMP_CONNECT_OPEN have been already implemented. These message handlers were tested with NDMP the toolkit's client and are working. Please see comments in ndmp/src/ndmp_connect.c for more information. More message handler implementations coming soon. 2. State machines for sessions have been implemented in the form of queues (in ndmp/src/ndmp_msg.c). 3. The old XDR folder has been renamed NDMP. 4. The old XDR folder has been deleted. Overall structure: The NDMP server is split into different components which are subdirectories of ndmp - currently comm, utils, ndmp. In each component the source code is in an src directory. comm is reponsible for actual client-server communication, utils provides thread-safe queues and hex dumps. NDMP contains NDMP message handlers and session state machines. comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients (using select() system call). New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe (spinlock capability will be added in a future commit). utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. ndmp/src/ndmp_msg.c, ndmp/src/ndmp_msg.h Maintains three state queues for sessions (connection, data, mover). Is also responsible for unmarshalling the NDMP message headers from client requests and passing them to appropriate message handlers which deal with the rest of the message before sending a reply. ndmp/src/ndmp.x NDMP structures information (obtained from NDMP source). We use rpcgen to generate ndmp.h and ndmp_xdr.c, which provide functions for encoding and decoding. ndmp/src/ndmp_connect.c Message handlers for CONNECT interface. ndmp/src/ndmp_config.c Message handlers for CONFIG interface. Next steps (to be addressed in future commits): 1. Align code (Code seems to be aligned in local files, but is not in GitHub). 2. Implement more NDMP message handlers (config interface). --- xdr/src/ndmp_config.c | 222 --------- xdr/src/ndmp_connect.c | 55 -- xdr/src/ndmp_xdr.c | 79 --- xdr/src/ndmp_xdr.h | 58 --- xdr/src/ndmp_xdr_structs.h | 993 ------------------------------------- 5 files changed, 1407 deletions(-) delete mode 100644 xdr/src/ndmp_config.c delete mode 100644 xdr/src/ndmp_connect.c delete mode 100644 xdr/src/ndmp_xdr.c delete mode 100644 xdr/src/ndmp_xdr.h delete mode 100644 xdr/src/ndmp_xdr_structs.h diff --git a/xdr/src/ndmp_config.c b/xdr/src/ndmp_config.c deleted file mode 100644 index 8f224ee..0000000 --- a/xdr/src/ndmp_config.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - * This file is part of glfs-ndmp. - * This file is licensed to you under your choice of the GNU Lesser - * General Public License, version 3 or any later version (LGPLv3 or - * later), or the GNU General Public License, version 2 (GPLv2), in all - * cases as published by the Free Software Foundation. - */ - -#include - -/* - * Each of the functions below take a client_txn and an XDR request stream as - * parameters. The client_txn structure is defined in comm.h and stores - * encoded requests and replies. - * - * By the time control reaches any of the below functions the message type is - * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. - * In each of the functions below we examine the structure that comes after - * the NDMP header. We then create the appropriate full NDMP reply message - * (including header) based on the client's request. Finally, we XDR encode - * (marshal) this reply message into txn. - * - * In summary, each function in this layer has 3 parts: - * 1. Decode rest of request message if present (apart from header) - * 2. Create appropriate message reply (including header) - * 3. Encode reply message and add to txn - * - */ - -void ndmp_config_get_host_info(struct client_txn *, XDR*) -{ - /* NDMP_CONFIG_GET_HOST_INFO - * - * no request arguments - * - * struct ndmp_config_get_host_info_reply - * { - * ndmp_error error; - * string hostname<>; - * string os_type<>; - * string os_vers<>; - * string hostid<>; - * }; - */ -} - -void ndmp_config_get_connection_type(struct client_txn *, XDR* ) -{ - /* NDMP_CONFIG_GET_CONNECTION_TYPE - * - * no request arguments - * - * enum ndmp_addr_type - * { - * NDMP_ADDR_LOCAL, - * NDMP_ADDR_TCP, - * NDMP_ADDR_FC, - * NDMP_ADDR_IPC - * }; - * - * struct ndmp_config_get_connection_type_reply - * { - * ndmp_error error; - * ndmp_addr_type addr_types<>; - * }; - * - */ -} - -void ndmp_config_get_auth_attr(struct client_txn *, XDR* ) -{ - /* /* NDMP_CONFIG_GET_AUTH_ATTR - * - * struct ndmp_config_get_auth_attr_request - * { - * ndmp_auth_type auth_type; - * }; - * - * struct ndmp_config_get_auth_attr_reply - * { - * ndmp_error error; - * ndmp_auth_attr server_attr; - * }; - */ - -} - -void ndmp_config_get_butype_info(struct client_txn *, XDR* ) -{ - /* NDMP_CONFIG_GET_BUTYPE_INFO - * - * No request arguments - * - * backup type attributes - * const NDMP_BTYPE_BACKUP_FILE_HISTORY = 0x0001; - * const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; - * const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; - * const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; - * const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; - * const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; - * const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; - * const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; - * const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; - * - * struct ndmp_butype_info - * { - * string butype_name <>; - * ndmp_pval default_env <>; - * u_long attrs; - * }; - * struct ndmp_config_get_butype_attr_reply - * { - * ndmp_error error; - * ndmp_butype_info butype_info <>; - * }; - */ - -} - -void ndmp_config_get_fs_info(struct client_txn *, XDR* ) -{ - /* /* NDMP_CONFIG_GET_FS_INFO - * - * No request arguments - * - * const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; - * const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; - * const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; - * const NDMP_FS_INFO_TOTOAL_INODES_INVALID = 0x00000008; - * const NDMP_FS_INFO_USED_INNODES_INVALID = 0x00000010; - * - * struct ndmp_fs_info - * { - * u_long invalid; /* invalid bit - * string fs_type <>; - * string fs_logical_device <>; - * string fs_physical_device <>; - * ndmp_u_quad total_size; - * ndmp_u_quad used_size; - * ndmp_u_quad avail_size; - * ndmp_u_quad total_inodes; - * ndmp_u_quad used_inodes; - * ndmp_pval fs_env <>; - * string fs_status<>; - * }; - * - * struct ndmp_config_get_fs_info_reply - * { - * ndmp_error error; - * ndmp_fs_info fs_info <>; - * }; - */ - -} - -void ndmp_config_get_tape_info(struct client_txn *, XDR* ) -{ - /* NDMP_CONFIG_GET_TAPE_INFO - * - * tape attributes - * - * const NDMP_TAPE_ATTR_REWIND = 0x00000001; - * const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; - * - * No request arguments - * - * struct ndmp_device_capability - * { - * string device <>; - * u_long attr; - * ndmp_pval capability <>; - * }; - * - * struct ndmp_device_info - * { - * string model <>; - * ndmp_device_capability caplist <>; - * }; - * - * struct ndmp_config_get_tape_info_reply - * { - * ndmp_error error; - * ndmp_device_info tape_info <>; - * }; - */ - -} - -void ndmp_config_get_scsi_info(struct client_txn *, XDR* ) -{ - /* NDMP_CONFIG_GET_SCSI_INFO - * - * No request arguments - * - * no SCSI attributes - * - * struct ndmp_config_get_scsi_info_reply - * { - * ndmp_error error; - * ndmp_device_info scsi_info <>; - * }; - */ - -} - -void ndmp_config_get_server_info(struct client_txn *, XDR* ) -{ - /* NDMP_CONFIG_GET_SERVER_INFO - * - * no request arguments - * - * struct ndmp_config_get_server_info_reply - * { - * ndmp_error error; - * string vendor_name<>; - * string product_name<>; - * string revision_number<>; - * ndmp_auth_type auth_type<>; - * }; - */ -} diff --git a/xdr/src/ndmp_connect.c b/xdr/src/ndmp_connect.c deleted file mode 100644 index d8527d1..0000000 --- a/xdr/src/ndmp_connect.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - * This file is part of glfs-ndmp. - * This file is licensed to you under your choice of the GNU Lesser - * General Public License, version 3 or any later version (LGPLv3 or - * later), or the GNU General Public License, version 2 (GPLv2), in all - * cases as published by the Free Software Foundation. - */ - -#include - -/* - * Each of the functions below take a client_txn and an XDR request stream as - * parameters. The client_txn structure is defined in comm.h and stores - * encoded requests and replies. - * - * By the time control reaches any of the below functions the message type is - * already known - the header is decoded in xdr_encode_decode in ndmp_xdr.c. - * In each of the functions below we examine the structure that comes after - * the NDMP header. We then create the appropriate full NDMP reply message - * (including header) based on the client's request. Finally, we XDR encode - * (marshal) this reply message into txn. - * - * In summary, each function in this layer has 3 parts: - * 1. Decode rest of request message if present (apart from header) - * 2. Create appropriate message reply (including header) - * 3. Encode reply message and add to txn - * - */ - - -void ndmp_connect_open(struct client_txn *txn, XDR* request_stream) -{ - /* NDMP_CONNECT_OPEN - * - * struct ndmp_connect_open_request - * { - * u_short protocol_version; - * }; - * - * struct ndmp_connect_open_reply - * { - * ndmp_error error; - * }; - * - */ -} - - -void ndmp_connect_close(struct client_txn *, XDR* request_stream) -{ - /* NDMP_CONNECT_CLOSE */ - /* no request arguments */ - /* no reply message */ -} diff --git a/xdr/src/ndmp_xdr.c b/xdr/src/ndmp_xdr.c deleted file mode 100644 index 1fb25a3..0000000 --- a/xdr/src/ndmp_xdr.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - * This file is part of glfs-ndmp. - * This file is licensed to you under your choice of the GNU Lesser - * General Public License, version 3 or any later version (LGPLv3 or - * later), or the GNU General Public License, version 2 (GPLv2), in all - * cases as published by the Free Software Foundation. - */ - -#include -/* - * xdr_decode_encode is the entry point - * and callback method for the comm layer - * This is the first upcall made by a worker - * thread. - * - */ - -void xdr_decode_encode(struct client_txn *txn) -{ - /* - * 1. Decode the message type from txn->request - * 2. Depending on the message type call the appropriate - * NDMP message handler. When the handler returns, - * txn->response will hold the marshaled (encoded) NDMP response - * 3. Enqueue the response into the response queue - */ - - XDR *request_stream = (XDR *) malloc(sizeof(XDR)); - int message_type; - struct comm_context *ctx; - - xdrmem_create(request_stream, txn->request.message, txn->request.length, - XDR_DECODE); - /* - * Get the message type - */ - - // message_type = ....; - - ndmp_dispatch(message_type)(txn, request_stream); - - enqueue(ctx->reply_jobs, txn); - -} - -ndmp_message_handler ndmp_dispatch(int message_type) { - - switch (message_type) { - case 0x900: - return ndmp_connect_open; - case 0x902: - return ndmp_connect_close; - case 0x100: - return ndmp_config_get_host_info; - case 0x102: - return ndmp_config_get_connection_type; - case 0x103: - return ndmp_config_get_auth_attr; - case 0x104: - return ndmp_config_get_butype_info; - case 0x105: - return ndmp_config_get_fs_info; - case 0x106: - return ndmp_config_get_tape_info; - case 0x107: - return ndmp_config_get_scsi_info; - case 0x108: - return ndmp_config_get_server_info; - default: - return ndmp_error_message; - } -} - -void ndmp_error_message(struct client_txn *, XDR*) -{ - -} - diff --git a/xdr/src/ndmp_xdr.h b/xdr/src/ndmp_xdr.h deleted file mode 100644 index 5a5b616..0000000 --- a/xdr/src/ndmp_xdr.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - * This file is part of glfs-ndmp. - * This file is licensed to you under your choice of the GNU Lesser - * General Public License, version 3 or any later version (LGPLv3 or - * later), or the GNU General Public License, version 2 (GPLv2), in all - * cases as published by the Free Software Foundation. - */ - -#ifndef __H__NDMP_XDR__ -#define __H__NDMP_XDR__ - -#include -#include -#include - -/* - * xdr_decode_encode is the entry point - * and callback method for the comm layer - * This is the first upcall made by a worker - * thread. - * - */ - -void xdr_decode_encode(struct client_txn *txn); - -/* - * Each NDMP message will have a message handler that is - * responsible for decoding(unmarshaling) the NDMP XDR request - * and invoking the appropriate NDMP action - */ - -typedef void (*ndmp_message_handler)(struct client_txn *txn, - XDR* request_stream); - -/* - * ndmp_dispatch determines the message handler for a given - * NDMP message type - */ - -ndmp_message_handler ndmp_dispatch(int message_type); - -/* - * - * The various NDMP message handlers - */ -void ndmp_connect_open(struct client_txn *txn, XDR* request_stream); -void ndmp_connect_close(struct client_txn *, XDR*); -void ndmp_config_get_host_info(struct client_txn *, XDR*); -void ndmp_config_get_connection_type(struct client_txn *, XDR*); -void ndmp_config_get_auth_attr(struct client_txn *, XDR*); -void ndmp_config_get_butype_info(struct client_txn *, XDR*); -void ndmp_config_get_fs_info(struct client_txn *, XDR*); -void ndmp_config_get_tape_info(struct client_txn *, XDR*); -void ndmp_config_get_scsi_info(struct client_txn *, XDR*); -void ndmp_config_get_server_info(struct client_txn *, XDR*); -void ndmp_error_message(struct client *, XDR *); // For wrong message type -#endif diff --git a/xdr/src/ndmp_xdr_structs.h b/xdr/src/ndmp_xdr_structs.h deleted file mode 100644 index f6c3fcd..0000000 --- a/xdr/src/ndmp_xdr_structs.h +++ /dev/null @@ -1,993 +0,0 @@ -/* - * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - * This file is part of glfs-ndmp. - * This file is licensed to you under your choice of the GNU Lesser - * General Public License, version 3 or any later version (LGPLv3 or - * later), or the GNU General Public License, version 2 (GPLv2), in all - * cases as published by the Free Software Foundation. - */ - -#ifndef __H_NDMP__ -#define __H_NDMP__ - -/* - * Type definitions based on NDMP V3 spec - */ - -enum ndmp_error { - NDMP_NO_ERR = 0, - NDMP_NOT_SUPPORTED_ERR = 1, - NDMP_DEVICE_BUSY_ERR = 2, - NDMP_DEVICE_OPENED_ERR = 3, - NDMP_NOT_AUTHORIZED_ERR = 4, - NDMP_PERMISSION_ERR = 5, - NDMP_DEV_NOT_OPEN_ERR = 6, - NDMP_IO_ERR = 7, - NDMP_TIMEOUT_ERR = 8, - NDMP_ILLEGAL_ARGS_ERR = 9, - NDMP_NO_TAPE_LOADED_ERR = 10, - NDMP_WRITE_PROTECT_ERR = 11, - NDMP_EOF_ERR = 12, - NDMP_EOM_ERR = 13, - NDMP_FILE_NOT_FOUND_ERR = 14, - NDMP_BAD_FILE_ERR = 15, - NDMP_NO_DEVICE_ERR = 16, - NDMP_NO_BUS_ERR = 17, - NDMP_XDR_DECODE_ERR = 18, - NDMP_ILLEGAL_STATE_ERR = 19, - NDMP_UNDEFINED_ERR = 20, - NDMP_XDR_ENCODE_ERR = 21, - NDMP_NO_MEM_ERR = 22, - NDMP_CONNECT_ERR = 23, -}; - -typedef enum ndmp_error ndmp_error; - -enum ndmp_header_message_type { - NDMP_MESSAGE_REQUEST = 0, NDMP_MESSAGE_REPLY = 1, -}; -typedef enum ndmp_header_message_type ndmp_header_message_type; - -enum ndmp_message { - NDMP_CONNECT_OPEN = 0x900, - NDMP_CONNECT_CLIENT_AUTH = 0x901, - NDMP_CONNECT_CLOSE = 0x902, - NDMP_CONNECT_SERVER_AUTH = 0x903, - NDMP_CONFIG_GET_HOST_INFO = 0x100, - NDMP_CONFIG_GET_CONNECTION_TYPE = 0x102, - NDMP_CONFIG_GET_AUTH_ATTR = 0x103, - NDMP_CONFIG_GET_BUTYPE_INFO = 0x104, - NDMP_CONFIG_GET_FS_INFO = 0x105, - NDMP_CONFIG_GET_TAPE_INFO = 0x106, - NDMP_CONFIG_GET_SCSI_INFO = 0x107, - NDMP_CONFIG_GET_SERVER_INFO = 0x108, - NDMP_SCSI_OPEN = 0x200, - NDMP_SCSI_CLOSE = 0x201, - NDMP_SCSI_GET_STATE = 0x202, - NDMP_SCSI_SET_TARGET = 0x203, - NDMP_SCSI_RESET_DEVICE = 0x204, - NDMP_SCSI_RESET_BUS = 0x205, - NDMP_SCSI_EXECUTE_CDB = 0x206, - NDMP_TAPE_OPEN = 0x300, - NDMP_TAPE_CLOSE = 0x301, - NDMP_TAPE_GET_STATE = 0x302, - NDMP_TAPE_MTIO = 0x303, - NDMP_TAPE_WRITE = 0x304, - NDMP_TAPE_READ = 0x305, - NDMP_TAPE_EXECUTE_CDB = 0x307, - NDMP_DATA_GET_STATE = 0x400, - NDMP_DATA_START_BACKUP = 0x401, - NDMP_DATA_START_RECOVER = 0x402, - NDMP_DATA_ABORT = 0x403, - NDMP_DATA_GET_ENV = 0x404, - NDMP_DATA_STOP = 0x407, - NDMP_DATA_LISTEN = 0x409, - NDMP_DATA_CONNECT = 0x40a, - NDMP_NOTIFY_DATA_HALTED = 0x501, - NDMP_NOTIFY_CONNECTED = 0x502, - NDMP_NOTIFY_MOVER_HALTED = 0x503, - NDMP_NOTIFY_MOVER_PAUSED = 0x504, - NDMP_NOTIFY_DATA_READ = 0x505, - NDMP_LOG_FILE = 0x602, - NDMP_LOG_MESSAGE = 0x603, - NDMP_FH_ADD_FILE = 0x703, - NDMP_FH_ADD_DIR = 0x704, - NDMP_FH_ADD_NODE = 0x705, - NDMP_MOVER_GET_STATE = 0xa00, - NDMP_MOVER_LISTEN = 0xa01, - NDMP_MOVER_CONTINUE = 0xa02, - NDMP_MOVER_ABORT = 0xa03, - NDMP_MOVER_STOP = 0xa04, - NDMP_MOVER_SET_WINDOW = 0xa05, - NDMP_MOVER_READ = 0xa06, - NDMP_MOVER_CLOSE = 0xa07, - NDMP_MOVER_SET_RECORD_SIZE = 0xa08, - NDMP_MOVER_CONNECT = 0xa09, - NDMP_VENDORS_BASE = 0xf000, - NDMP_RESERVED_BASE = 0xff00, -}; - -typedef enum ndmp_message ndmp_message; - -struct ndmp_header { - u_long sequence; - u_long time_stamp; - ndmp_header_message_type message_type; - enum ndmp_message message; - u_long reply_sequence; - ndmp_error error; -}; - -typedef struct ndmp_header ndmp_header; - -struct ndmp_connect_open_request { - u_short protocol_version; -}; -typedef struct ndmp_connect_open_request ndmp_connect_open_request; - -struct ndmp_connect_open_reply { - ndmp_error error; -}; -typedef struct ndmp_connect_open_reply ndmp_connect_open_reply; - -enum ndmp_auth_type { - NDMP_AUTH_NONE = 0, NDMP_AUTH_TEXT = 1, NDMP_AUTH_MD5 = 2, -}; -typedef enum ndmp_auth_type ndmp_auth_type; - -struct ndmp_auth_text { - char *auth_id; - char *auth_password; -}; -typedef struct ndmp_auth_text ndmp_auth_text; - -struct ndmp_auth_md5 { - char *auth_id; - char auth_digest[16]; -}; -typedef struct ndmp_auth_md5 ndmp_auth_md5; - -struct ndmp_auth_data { - ndmp_auth_type auth_type; - union { - struct ndmp_auth_text auth_text; - struct ndmp_auth_md5 auth_md5; - } ndmp_auth_data_u; -}; - -typedef struct ndmp_auth_data ndmp_auth_data; - -struct ndmp_connect_client_auth_request { - ndmp_auth_data auth_data; -}; - -typedef struct ndmp_connect_client_auth_request ndmp_connect_client_auth_request; - -struct ndmp_connect_client_auth_reply { - ndmp_error error; -}; - -typedef struct ndmp_connect_client_auth_reply ndmp_connect_client_auth_reply; - -struct ndmp_auth_attr { - ndmp_auth_type auth_type; - union { - char challenge[64]; - } ndmp_auth_attr_u; -}; - -typedef struct ndmp_auth_attr ndmp_auth_attr; - -struct ndmp_connect_server_auth_request { - ndmp_auth_attr client_attr; -}; - -typedef struct ndmp_connect_server_auth_request ndmp_connect_server_auth_request; - -struct ndmp_connect_server_auth_reply { - ndmp_error error; - ndmp_auth_data server_result; -}; - -typedef struct ndmp_connect_server_auth_reply ndmp_connect_server_auth_reply; - -struct ndmp_config_get_host_info_reply { - ndmp_error error; - char *hostname; - char *os_type; - char *os_vers; - char *hostid; -}; -typedef struct ndmp_config_get_host_info_reply ndmp_config_get_host_info_reply; - -enum ndmp_addr_type { - NDMP_ADDR_LOCAL = 0, - NDMP_ADDR_TCP = 1, - NDMP_ADDR_FC = 2, - NDMP_ADDR_IPC = 3, -}; -typedef enum ndmp_addr_type ndmp_addr_type; - -struct ndmp_config_get_connection_type_reply { - ndmp_error error; - struct { - u_int addr_types_len; - ndmp_addr_type *addr_types_val; - } addr_types; -}; -typedef struct ndmp_config_get_connection_type_reply ndmp_config_get_connection_type_reply; - -struct ndmp_config_get_auth_attr_request { - ndmp_auth_type auth_type; -}; - -typedef struct ndmp_config_get_auth_attr_request ndmp_config_get_auth_attr_request; - -struct ndmp_config_get_auth_attr_reply { - ndmp_error error; - ndmp_auth_attr server_attr; -}; - -typedef struct ndmp_config_get_auth_attr_reply ndmp_config_get_auth_attr_reply; - -struct ndmp_config_get_server_info_reply { - ndmp_error error; - char *vendor_name; - char *product_name; - char *revision_number; - struct { - u_int auth_type_len; - ndmp_auth_type *auth_type_val; - } auth_type; -}; - -typedef struct ndmp_config_get_server_info_reply ndmp_config_get_server_info_reply; - -#define NDMP_BUTYPE_BACKUP_FILE_HISTORY 0x0001 -#define NDMP_BUTYPE_BACKUP_FILELIST 0x0002 -#define NDMP_BUTYPE_RECOVER_FILELIST 0x0004 -#define NDMP_BUTYPE_BACKUP_DIRECT 0x0008 -#define NDMP_BUTYPE_RECOVER_DIRECT 0x0010 -#define NDMP_BUTYPE_BACKUP_INCREMENTAL 0x0020 -#define NDMP_BUTYPE_RECOVER_INCREMENTAL 0x0040 -#define NDMP_BUTYPE_BACKUP_UTF8 0x0080 -#define NDMP_BUTYPE_RECOVER_UTF8 0x0100 - -struct ndmp_pval { - char *name; - char *value; -}; -typedef struct ndmp_pval ndmp_pval; - -struct ndmp_u_quad { - u_long high; - u_long low; -}; -typedef struct ndmp_u_quad ndmp_u_quad; - -struct ndmp_butype_info { - char *butype_name; - struct { - u_int default_env_len; - ndmp_pval *default_env_val; - } default_env; - u_long attrs; -}; -typedef struct ndmp_butype_info ndmp_butype_info; - -struct ndmp_config_get_butype_info_reply { - ndmp_error error; - struct { - u_int butype_info_len; - ndmp_butype_info *butype_info_val; - } butype_info; -}; -typedef struct ndmp_config_get_butype_info_reply ndmp_config_get_butype_info_reply; -#define NDMP_FS_INFO_TOTAL_SIZE_INVALID 0x00000001 -#define NDMP_FS_INFO_USED_SIZE_INVALID 0x00000002 -#define NDMP_FS_INFO_AVAIL_SIZE_INVALID 0x00000004 -#define NDMP_FS_INFO_TOTAL_INODES_INVALID 0x00000008 -#define NDMP_FS_INFO_USED_INODES_INVALID 0x00000010 - -struct ndmp_fs_info { - u_long invalid; - char *fs_type; - char *fs_logical_device; - char *fs_physical_device; - ndmp_u_quad total_size; - ndmp_u_quad used_size; - ndmp_u_quad avail_size; - ndmp_u_quad total_inodes; - ndmp_u_quad used_inodes; - struct { - u_int fs_env_len; - ndmp_pval *fs_env_val; - } fs_env; - char *fs_status; -}; -typedef struct ndmp_fs_info ndmp_fs_info; - -struct ndmp_config_get_fs_info_reply { - ndmp_error error; - struct { - u_int fs_info_len; - ndmp_fs_info *fs_info_val; - } fs_info; -}; -typedef struct ndmp_config_get_fs_info_reply ndmp_config_get_fs_info_reply; -#define NDMP_TAPE_ATTR_REWIND 0x00000001 -#define NDMP_TAPE_ATTR_UNLOAD 0x00000002 - -struct ndmp_device_capability { - char *device; - u_long attr; - struct { - u_int capability_len; - ndmp_pval *capability_val; - } capability; -}; -typedef struct ndmp_device_capability ndmp_device_capability; - -struct ndmp_device_info { - char *model; - struct { - u_int caplist_len; - ndmp_device_capability *caplist_val; - } caplist; -}; -typedef struct ndmp_device_info ndmp_device_info; - -struct ndmp_config_get_tape_info_reply { - ndmp_error error; - struct { - u_int tape_info_len; - ndmp_device_info *tape_info_val; - } tape_info; -}; -typedef struct ndmp_config_get_tape_info_reply ndmp_config_get_tape_info_reply; - -struct ndmp_config_get_scsi_info_reply { - ndmp_error error; - struct { - u_int scsi_info_len; - ndmp_device_info *scsi_info_val; - } scsi_info; -}; -typedef struct ndmp_config_get_scsi_info_reply ndmp_config_get_scsi_info_reply; - -struct ndmp_scsi_open_request { - char *device; -}; -typedef struct ndmp_scsi_open_request ndmp_scsi_open_request; - -struct ndmp_scsi_open_reply { - ndmp_error error; -}; -typedef struct ndmp_scsi_open_reply ndmp_scsi_open_reply; - -struct ndmp_scsi_close_reply { - ndmp_error error; -}; -typedef struct ndmp_scsi_close_reply ndmp_scsi_close_reply; - -struct ndmp_scsi_get_state_reply { - ndmp_error error; - short target_controller; - short target_id; - short target_lun; -}; -typedef struct ndmp_scsi_get_state_reply ndmp_scsi_get_state_reply; - -struct ndmp_scsi_set_target_request { - char *device; - u_short target_controller; - u_short target_id; - u_short target_lun; -}; -typedef struct ndmp_scsi_set_target_request ndmp_scsi_set_target_request; - -struct ndmp_scsi_set_target_reply { - ndmp_error error; -}; -typedef struct ndmp_scsi_set_target_reply ndmp_scsi_set_target_reply; - -struct ndmp_scsi_reset_device_reply { - ndmp_error error; -}; -typedef struct ndmp_scsi_reset_device_reply ndmp_scsi_reset_device_reply; - -struct ndmp_scsi_reset_bus_reply { - ndmp_error error; -}; -typedef struct ndmp_scsi_reset_bus_reply ndmp_scsi_reset_bus_reply; -#define NDMP_SCSI_DATA_IN 0x00000001 -#define NDMP_SCSI_DATA_OUT 0x00000002 - -struct ndmp_execute_cdb_request { - u_long flags; - u_long timeout; - u_long datain_len; - struct { - u_int cdb_len; - char *cdb_val; - } cdb; - struct { - u_int dataout_len; - char *dataout_val; - } dataout; -}; -typedef struct ndmp_execute_cdb_request ndmp_execute_cdb_request; - -struct ndmp_execute_cdb_reply { - ndmp_error error; - u_char status; - u_long dataout_len; - struct { - u_int datain_len; - char *datain_val; - } datain; - struct { - u_int ext_sense_len; - char *ext_sense_val; - } ext_sense; -}; -typedef struct ndmp_execute_cdb_reply ndmp_execute_cdb_reply; - -enum ndmp_tape_open_mode { - NDMP_TAPE_READ_MODE = 0, NDMP_TAPE_RDWR_MODE = 1, -}; -typedef enum ndmp_tape_open_mode ndmp_tape_open_mode; - -struct ndmp_tape_open_request { - char *device; - ndmp_tape_open_mode mode; -}; -typedef struct ndmp_tape_open_request ndmp_tape_open_request; - -struct ndmp_tape_open_reply { - ndmp_error error; -}; -typedef struct ndmp_tape_open_reply ndmp_tape_open_reply; - -struct ndmp_tape_close_reply { - ndmp_error error; -}; -typedef struct ndmp_tape_close_reply ndmp_tape_close_reply; -#define NDMP_TAPE_STATE_NOREWIND 0x0008 -#define NDMP_TAPE_STATE_WR_PROT 0x0010 -#define NDMP_TAPE_STATE_ERROR 0x0020 -#define NDMP_TAPE_STATE_UNLOAD 0x0040 -#define NDMP_TAPE_STATE_FILE_NUM_INVALID 0x00000001 -#define NDMP_TAPE_STATE_SOFT_ERRORS_INVALID 0x00000002 -#define NDMP_TAPE_STATE_BLOCK_SIZE_INVALID 0x00000004 -#define NDMP_TAPE_STATE_BLOCKNO_INVALID 0x00000008 -#define NDMP_TAPE_STATE_TOTAL_SPACE_INVALID 0x00000010 -#define NDMP_TAPE_STATE_SPACE_REMAIN_INVALID 0x00000020 -#define NDMP_TAPE_STATE_PARTITION_INVALID 0x00000040 - -struct ndmp_tape_get_state_reply { - u_long invalid; - ndmp_error error; - u_long flags; - u_long file_num; - u_long soft_errors; - u_long block_size; - u_long blockno; - ndmp_u_quad total_space; - ndmp_u_quad space_remain; - u_long partition; -}; -typedef struct ndmp_tape_get_state_reply ndmp_tape_get_state_reply; - -enum ndmp_tape_mtio_op { - NDMP_MTIO_FSF = 0, - NDMP_MTIO_BSF = 1, - NDMP_MTIO_FSR = 2, - NDMP_MTIO_BSR = 3, - NDMP_MTIO_REW = 4, - NDMP_MTIO_EOF = 5, - NDMP_MTIO_OFF = 6, -}; -typedef enum ndmp_tape_mtio_op ndmp_tape_mtio_op; - -struct ndmp_tape_mtio_request { - ndmp_tape_mtio_op tape_op; - u_long count; -}; -typedef struct ndmp_tape_mtio_request ndmp_tape_mtio_request; - -struct ndmp_tape_mtio_reply { - ndmp_error error; - u_long resid_count; -}; -typedef struct ndmp_tape_mtio_reply ndmp_tape_mtio_reply; - -struct ndmp_tape_write_request { - struct { - u_int data_out_len; - char *data_out_val; - } data_out; -}; -typedef struct ndmp_tape_write_request ndmp_tape_write_request; - -struct ndmp_tape_write_reply { - ndmp_error error; - u_long count; -}; -typedef struct ndmp_tape_write_reply ndmp_tape_write_reply; - -struct ndmp_tape_read_request { - u_long count; -}; -typedef struct ndmp_tape_read_request ndmp_tape_read_request; - -struct ndmp_tape_read_reply { - ndmp_error error; - struct { - u_int data_in_len; - char *data_in_val; - } data_in; -}; -typedef struct ndmp_tape_read_reply ndmp_tape_read_reply; - -typedef ndmp_execute_cdb_request ndmp_tape_execute_cdb_request; - -typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; - -enum ndmp_mover_state { - NDMP_MOVER_STATE_IDLE = 0, - NDMP_MOVER_STATE_LISTEN = 1, - NDMP_MOVER_STATE_ACTIVE = 2, - NDMP_MOVER_STATE_PAUSED = 3, - NDMP_MOVER_STATE_HALTED = 4, -}; -typedef enum ndmp_mover_state ndmp_mover_state; - -enum ndmp_mover_pause_reason { - NDMP_MOVER_PAUSE_NA = 0, - NDMP_MOVER_PAUSE_EOM = 1, - NDMP_MOVER_PAUSE_EOF = 2, - NDMP_MOVER_PAUSE_SEEK = 3, - NDMP_MOVER_PAUSE_MEDIA_ERROR = 4, - NDMP_MOVER_PAUSE_EOW = 5, -}; -typedef enum ndmp_mover_pause_reason ndmp_mover_pause_reason; - -enum ndmp_mover_halt_reason { - NDMP_MOVER_HALT_NA = 0, - NDMP_MOVER_HALT_CONNECT_CLOSED = 1, - NDMP_MOVER_HALT_ABORTED = 2, - NDMP_MOVER_HALT_INTERNAL_ERROR = 3, - NDMP_MOVER_HALT_CONNECT_ERROR = 4, -}; -typedef enum ndmp_mover_halt_reason ndmp_mover_halt_reason; - -enum ndmp_mover_mode { - NDMP_MOVER_MODE_READ = 0, NDMP_MOVER_MODE_WRITE = 1, -}; -typedef enum ndmp_mover_mode ndmp_mover_mode; - -struct ndmp_tcp_addr { - u_long ip_addr; - u_short port; -}; -typedef struct ndmp_tcp_addr ndmp_tcp_addr; - -struct ndmp_fc_addr { - u_long loop_id; -}; -typedef struct ndmp_fc_addr ndmp_fc_addr; - -struct ndmp_ipc_addr { - struct { - u_int comm_data_len; - char *comm_data_val; - } comm_data; -}; -typedef struct ndmp_ipc_addr ndmp_ipc_addr; - -struct ndmp_addr { - ndmp_addr_type addr_type; - union { - ndmp_tcp_addr tcp_addr; - ndmp_fc_addr fc_addr; - ndmp_ipc_addr ipc_addr; - } ndmp_addr_u; -}; - -typedef struct ndmp_addr ndmp_addr; - -struct ndmp_mover_get_state_reply { - ndmp_error error; - ndmp_mover_state state; - ndmp_mover_pause_reason pause_reason; - ndmp_mover_halt_reason halt_reason; - u_long record_size; - u_long record_num; - ndmp_u_quad data_written; - ndmp_u_quad seek_position; - ndmp_u_quad bytes_left_to_read; - ndmp_u_quad window_offset; - ndmp_u_quad window_length; - ndmp_addr data_connection_addr; -}; - -typedef struct ndmp_mover_get_state_reply ndmp_mover_get_state_reply; - -struct ndmp_mover_listen_request { - ndmp_mover_mode mode; - ndmp_addr_type addr_type; -}; - -typedef struct ndmp_mover_listen_request ndmp_mover_listen_request; - -struct ndmp_mover_listen_reply { - ndmp_error error; - ndmp_addr data_connection_addr; -}; - -typedef struct ndmp_mover_listen_reply ndmp_mover_listen_reply; - -struct ndmp_mover_connect_request { - ndmp_mover_mode mode; - ndmp_addr addr; -}; - -typedef struct ndmp_mover_connect_request ndmp_mover_connect_request; - -struct ndmp_mover_connect_reply { - ndmp_error error; -}; - -typedef struct ndmp_mover_connect_reply ndmp_mover_connect_reply; - -struct ndmp_mover_set_record_size_request { - u_long len; -}; - -typedef struct ndmp_mover_set_record_size_request ndmp_mover_set_record_size_request; - -struct ndmp_mover_set_record_size_reply { - ndmp_error error; -}; - -typedef struct ndmp_mover_set_record_size_reply ndmp_mover_set_record_size_reply; - -struct ndmp_mover_set_window_request { - ndmp_u_quad offset; - ndmp_u_quad length; -}; - -typedef struct ndmp_mover_set_window_request ndmp_mover_set_window_request; - -struct ndmp_mover_set_window_reply { - ndmp_error error; -}; - -typedef struct ndmp_mover_set_window_reply ndmp_mover_set_window_reply; - -struct ndmp_mover_continue_reply { - ndmp_error error; -}; -typedef struct ndmp_mover_continue_reply ndmp_mover_continue_reply; - -struct ndmp_mover_abort_reply { - ndmp_error error; -}; -typedef struct ndmp_mover_abort_reply ndmp_mover_abort_reply; - -struct ndmp_mover_stop_reply { - ndmp_error error; -}; -typedef struct ndmp_mover_stop_reply ndmp_mover_stop_reply; - -struct ndmp_mover_read_request { - ndmp_u_quad offset; - ndmp_u_quad length; -}; -typedef struct ndmp_mover_read_request ndmp_mover_read_request; - -struct ndmp_mover_read_reply { - ndmp_error error; -}; -typedef struct ndmp_mover_read_reply ndmp_mover_read_reply; - -struct ndmp_mover_close_reply { - ndmp_error error; -}; -typedef struct ndmp_mover_close_reply ndmp_mover_close_reply; - -enum ndmp_data_operation { - NDMP_DATA_OP_NOACTION = 0, - NDMP_DATA_OP_BACKUP = 1, - NDMP_DATA_OP_RESTORE = 2, -}; -typedef enum ndmp_data_operation ndmp_data_operation; - -enum ndmp_data_state { - NDMP_DATA_STATE_IDLE = 0, - NDMP_DATA_STATE_ACTIVE = 1, - NDMP_DATA_STATE_HALTED = 2, - NDMP_DATA_STATE_LISTEN = 3, - NDMP_DATA_STATE_CONNECTED = 4, -}; -typedef enum ndmp_data_state ndmp_data_state; - -enum ndmp_data_halt_reason { - NDMP_DATA_HALT_NA = 0, - NDMP_DATA_HALT_SUCCESSFUL = 1, - NDMP_DATA_HALT_ABORTED = 2, - NDMP_DATA_HALT_INTERNAL_ERROR = 3, - NDMP_DATA_HALT_CONNECT_ERROR = 4, -}; -typedef enum ndmp_data_halt_reason ndmp_data_halt_reason; -#define NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID 0x00000001 -#define NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID 0x00000002 - -struct ndmp_data_get_state_reply { - u_long invalid; - ndmp_error error; - ndmp_data_operation operation; - ndmp_data_state state; - ndmp_data_halt_reason halt_reason; - ndmp_u_quad bytes_processed; - ndmp_u_quad est_bytes_remain; - u_long est_time_remain; - ndmp_addr data_connection_addr; - ndmp_u_quad read_offset; - ndmp_u_quad read_length; -}; -typedef struct ndmp_data_get_state_reply ndmp_data_get_state_reply; - -struct ndmp_data_start_backup_request { - char *bu_type; - struct { - u_int env_len; - ndmp_pval *env_val; - } env; -}; -typedef struct ndmp_data_start_backup_request ndmp_data_start_backup_request; - -struct ndmp_data_start_backup_reply { - ndmp_error error; -}; -typedef struct ndmp_data_start_backup_reply ndmp_data_start_backup_reply; - -struct ndmp_name { - char *original_path; - char *destination_dir; - char *new_name; - char *other_name; - ndmp_u_quad node; - ndmp_u_quad fh_info; -}; -typedef struct ndmp_name ndmp_name; - -struct ndmp_data_start_recover_request { - struct { - u_int env_len; - ndmp_pval *env_val; - } env; - struct { - u_int nlist_len; - ndmp_name *nlist_val; - } nlist; - char *bu_type; -}; -typedef struct ndmp_data_start_recover_request ndmp_data_start_recover_request; - -struct ndmp_data_start_recover_reply { - ndmp_error error; -}; -typedef struct ndmp_data_start_recover_reply ndmp_data_start_recover_reply; - -struct ndmp_data_abort_reply { - ndmp_error error; -}; -typedef struct ndmp_data_abort_reply ndmp_data_abort_reply; - -struct ndmp_data_stop_reply { - ndmp_error error; -}; -typedef struct ndmp_data_stop_reply ndmp_data_stop_reply; - -struct ndmp_data_get_env_reply { - ndmp_error error; - struct { - u_int env_len; - ndmp_pval *env_val; - } env; -}; -typedef struct ndmp_data_get_env_reply ndmp_data_get_env_reply; - -struct ndmp_data_listen_request { - ndmp_addr_type addr_type; -}; -typedef struct ndmp_data_listen_request ndmp_data_listen_request; - -struct ndmp_data_listen_reply { - ndmp_error error; - ndmp_addr data_connection_addr; -}; -typedef struct ndmp_data_listen_reply ndmp_data_listen_reply; - -struct ndmp_data_connect_request { - ndmp_addr addr; -}; -typedef struct ndmp_data_connect_request ndmp_data_connect_request; - -struct ndmp_data_connect_reply { - ndmp_error error; -}; -typedef struct ndmp_data_connect_reply ndmp_data_connect_reply; - -struct ndmp_notify_data_halted_request { - ndmp_data_halt_reason reason; - char *text_reason; -}; -typedef struct ndmp_notify_data_halted_request ndmp_notify_data_halted_request; - -enum ndmp_connect_reason { - NDMP_CONNECTED = 0, NDMP_SHUTDOWN = 1, NDMP_REFUSED = 2, -}; -typedef enum ndmp_connect_reason ndmp_connect_reason; - -struct ndmp_notify_connected_request { - ndmp_connect_reason reason; - u_short protocol_version; - char *text_reason; -}; -typedef struct ndmp_notify_connected_request ndmp_notify_connected_request; - -struct ndmp_notify_mover_paused_request { - ndmp_mover_pause_reason reason; - ndmp_u_quad seek_position; -}; -typedef struct ndmp_notify_mover_paused_request ndmp_notify_mover_paused_request; - -struct ndmp_notify_mover_halted_request { - ndmp_mover_halt_reason reason; - char *text_reason; -}; -typedef struct ndmp_notify_mover_halted_request ndmp_notify_mover_halted_request; - -struct ndmp_notify_data_read_request { - ndmp_u_quad offset; - ndmp_u_quad length; -}; -typedef struct ndmp_notify_data_read_request ndmp_notify_data_read_request; - -enum ndmp_log_type { - NDMP_LOG_NORMAL = 0, - NDMP_LOG_DEBUG = 1, - NDMP_LOG_ERROR = 2, - NDMP_LOG_WARNING = 3, -}; -typedef enum ndmp_log_type ndmp_log_type; - -struct ndmp_log_message_request { - ndmp_log_type log_type; - u_long message_id; - char *entry; -}; -typedef struct ndmp_log_message_request ndmp_log_message_request; - -struct ndmp_log_file_request { - char *name; - ndmp_error error; -}; -typedef struct ndmp_log_file_request ndmp_log_file_request; - -enum ndmp_fs_type { - NDMP_FS_UNIX = 0, NDMP_FS_NT = 1, NDMP_FS_OTHER = 2, -}; -typedef enum ndmp_fs_type ndmp_fs_type; - -typedef char *ndmp_path; - -struct ndmp_nt_path { - ndmp_path nt_path; - ndmp_path dos_path; -}; -typedef struct ndmp_nt_path ndmp_nt_path; - -struct ndmp_file_name { - ndmp_fs_type fs_type; - union { - ndmp_path unix_name; - ndmp_nt_path nt_name; - ndmp_path other_name; - } ndmp_file_name_u; -}; -typedef struct ndmp_file_name ndmp_file_name; - -enum ndmp_file_type { - NDMP_FILE_DIR = 0, - NDMP_FILE_FIFO = 1, - NDMP_FILE_CSPEC = 2, - NDMP_FILE_BSPEC = 3, - NDMP_FILE_REG = 4, - NDMP_FILE_SLINK = 5, - NDMP_FILE_SOCK = 6, - NDMP_FILE_REGISTRY = 7, - NDMP_FILE_OTHER = 8, -}; -typedef enum ndmp_file_type ndmp_file_type; -#define NDMP_FILE_STAT_ATIME_INVALID 0x00000001 -#define NDMP_FILE_STAT_CTIME_INVALID 0x00000002 -#define NDMP_FILE_STAT_GROUP_INVALID 0x00000004 - -struct ndmp_file_stat { - u_long invalid; - ndmp_fs_type fs_type; - ndmp_file_type ftype; - u_long mtime; - u_long atime; - u_long ctime; - u_long owner; - u_long group; - u_long fattr; - ndmp_u_quad size; - u_long links; -}; -typedef struct ndmp_file_stat ndmp_file_stat; - -struct ndmp_file { - struct { - u_int names_len; - ndmp_file_name *names_val; - } names; - struct { - u_int stats_len; - ndmp_file_stat *stats_val; - } stats; - ndmp_u_quad node; - ndmp_u_quad fh_info; -}; -typedef struct ndmp_file ndmp_file; - -struct ndmp_fh_add_file_request { - struct { - u_int files_len; - ndmp_file *files_val; - } files; -}; -typedef struct ndmp_fh_add_file_request ndmp_fh_add_file_request; - -struct ndmp_dir { - struct { - u_int names_len; - ndmp_file_name *names_val; - } names; - ndmp_u_quad node; - ndmp_u_quad parent; -}; -typedef struct ndmp_dir ndmp_dir; - -struct ndmp_fh_add_dir_request { - struct { - u_int dirs_len; - ndmp_dir *dirs_val; - } dirs; -}; -typedef struct ndmp_fh_add_dir_request ndmp_fh_add_dir_request; - -struct ndmp_node { - struct { - u_int stats_len; - ndmp_file_stat *stats_val; - } stats; - ndmp_u_quad node; - ndmp_u_quad fh_info; -}; -typedef struct ndmp_node ndmp_node; - -struct ndmp_fh_add_node_request { - struct { - u_int nodes_len; - ndmp_node *nodes_val; - } nodes; -}; -typedef struct ndmp_fh_add_node_request ndmp_fh_add_node_request; - -#endif From 44fe4422bcf91209f79483f5eb42cf7add8355ca Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 19 Mar 2013 16:26:52 +0530 Subject: [PATCH 09/18] Finished implementing connect and part of config. --- ndmp/src/ndmp_config.c | 147 ++++++++++++++++++++++++++++++++++++++++ ndmp/src/ndmp_connect.c | 27 ++++++++ ndmp/src/ndmp_msg.c | 9 +++ ndmp/src/test/testndmp | Bin 123439 -> 125019 bytes 4 files changed, 183 insertions(+) diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c index 8263cfe..3cdc608 100644 --- a/ndmp/src/ndmp_config.c +++ b/ndmp/src/ndmp_config.c @@ -9,6 +9,9 @@ #include #include +#include +#include +#include /* * Each of the functions below take a client_txn and an XDR request stream as @@ -44,6 +47,46 @@ void ndmp_config_get_host_info(struct client_txn *txn, struct ndmp_header header * string hostid<>; * }; */ + + struct ndmp_header reply_header; + struct ndmp_config_get_host_info_reply reply; + char hostname[32]; + struct utsname os_info; + XDR reply_stream; + + reply.error = NDMP_NO_ERR; + + if (gethostname(hostname,32) != -1) + reply.hostname = hostname; + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + + if (uname(&os_info) != -1){ + reply.os_type = os_info.sysname; + reply.os_vers = os_info.version; + } + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + + reply.hostid = "1"; + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_host_info_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_host_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_host_info_reply, &reply); } void ndmp_config_get_connection_type(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -67,6 +110,36 @@ void ndmp_config_get_connection_type(struct client_txn *txn, struct ndmp_header * }; * */ + + struct ndmp_header reply_header; + struct ndmp_config_get_connection_type_reply reply; + enum ndmp_addr_type addr_types[2] = {NDMP_ADDR_LOCAL, NDMP_ADDR_TCP}; + XDR reply_stream; + + reply.addr_types.addr_types_len = 2; + reply.addr_types.addr_types_val = addr_types; + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_connection_type_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_connection_type_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_connection_type_reply, + &reply); + } void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -84,6 +157,48 @@ void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header * ndmp_auth_attr server_attr; * }; */ + + struct ndmp_header reply_header; + struct ndmp_config_get_auth_attr_request request; + struct ndmp_config_get_auth_attr_reply reply; + XDR reply_stream; + + + xdr_ndmp_config_get_auth_attr_request(request_stream, &request); + + switch (request.auth_type) { + case NDMP_AUTH_NONE: + reply.server_attr.auth_type = NDMP_AUTH_NONE; + strcpy(reply.server_attr.ndmp_auth_attr_u.challenge, + ""); /* No challenge */ + reply.error = NDMP_NO_ERR; + break; + case NDMP_AUTH_TEXT: + case NDMP_AUTH_MD5: + default: + reply.error = NDMP_NOT_SUPPORTED_ERR; + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_auth_attr_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_auth_attr_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_auth_attr_reply, + &reply); + } @@ -220,4 +335,36 @@ void ndmp_config_get_server_info(struct client_txn *txn, struct ndmp_header head * ndmp_auth_type auth_type<>; * }; */ + + struct ndmp_header reply_header; + struct ndmp_config_get_server_info_reply reply; + enum ndmp_auth_type auth_types[1] = {NDMP_AUTH_NONE}; + XDR reply_stream; + + reply.vendor_name = "Red Hat, Inc."; + reply.product_name = "NDMP Server"; + reply.revision_number = "0.1"; + reply.auth_type.auth_type_len = 1; + reply.auth_type.auth_type_val = auth_types; + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_server_info_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_server_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_server_info_reply, + &reply); } diff --git a/ndmp/src/ndmp_connect.c b/ndmp/src/ndmp_connect.c index fdc2edd..dc6524f 100644 --- a/ndmp/src/ndmp_connect.c +++ b/ndmp/src/ndmp_connect.c @@ -102,5 +102,32 @@ void ndmp_connect_close(struct client_txn *txn, /* NDMP_CONNECT_CLOSE */ /* no request arguments */ /* no reply message */ + + struct ndmp_header reply_header; + struct ndmp_session_info *session_info; + XDR reply_stream; + + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); + + /* + * States set as per Figure 8 in NDMP V3 spec. + */ + + session_info->connection_state = HALTED; + session_info->data_state = HALTED; + session_info->mover_state = HALTED; + set_header(header, &reply_header, 0); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + exit_critical_section(session_info->s_lock); } diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index 7ea434d..210a014 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -97,6 +97,15 @@ void ndmp_error_message(struct client_txn *txn, XDR* requeststream) { + struct ndmp_header reply_header; + XDR reply_stream; + set_header(header, &reply_header, NDMP_NOT_SUPPORTED_ERR); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, + &reply_header); + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, + XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); } void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* request_stream) diff --git a/ndmp/src/test/testndmp b/ndmp/src/test/testndmp index ac05a9b426f3e7316140c4e893bedfd28c3fb72c..b2373e5587f264b18269bb25a226acd2dbb98556 100755 GIT binary patch delta 41963 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 Date: Mon, 25 Mar 2013 16:35:58 +0530 Subject: [PATCH 10/18] Fixed few bugs, connect and config complete. --- comm/src/comm.c | 10 +- comm/src/comm.h | 4 + comm/src/worker.c | 19 +- ndmp/src/ndmp_config.c | 417 ++++++++++++++++++++++++++++++++++++++- ndmp/src/ndmp_connect.c | 10 +- ndmp/src/ndmp_msg.c | 143 ++++++++++++-- ndmp/src/ndmp_msg.h | 24 +++ ndmp/src/test/makefile | 3 +- ndmp/src/test/testndmp.c | 2 + utils/src/hexdump.c | 2 +- 10 files changed, 595 insertions(+), 39 deletions(-) diff --git a/comm/src/comm.c b/comm/src/comm.c index c457294..93e606b 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -214,13 +214,13 @@ int accept_all_connections(int listener, fd_set *read_socks, txn = (struct client_txn *) malloc(sizeof(struct client_txn)); /* - * Create a psuedo NDMP request for the tcp_connect request - * so that a NDMP_NOTIFY_CONNECTED response + * Create a pseudo NDMP request for the tcp_connect request + * so that a NDMP_NOTIFY_CONNECTED request can be sent to client */ txn->client_session = *new_session; - txn->request.is_tcp_connect = 0; - //enqueue(ctx->request_jobs, txn); + txn->request.is_tcp_connect = 1; + enqueue(ctx->request_jobs, txn); num_new_sessions++; } // } while (endpoint.fd != -1); @@ -263,7 +263,9 @@ void handle_a_client_request(int fd, struct comm_context *ctx) */ close(fd); remove_elem(ctx->sessions, &tmp, session_comparator); + ctx->terminate_session(fd);/* mark this session as terminated */ free(txn); + printf("Detected socket closure\n"); return; } diff --git a/comm/src/comm.h b/comm/src/comm.h index 8e5c584..0a49c3e 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -48,8 +48,12 @@ struct client_txn { }; typedef void (*message_handler) (struct client_txn *); +typedef int (*session_callback)(struct client_txn *); +typedef void (*session_close)(int session_id); struct comm_context { message_handler marshal_unmarshal; + session_callback cleanup_session; + session_close terminate_session; struct queue_hdr *sessions; struct queue_hdr *request_jobs; struct queue_hdr *reply_jobs; diff --git a/comm/src/worker.c b/comm/src/worker.c index d85b8fe..33bf90f 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -14,6 +14,7 @@ static pthread_t* threads = NULL; static int num_threads; void* run_job(void *context); void* process_response(void *context); +extern int session_comparator(void *target, void *elem); void create_worker_threads(int thread_pool_size) { @@ -71,12 +72,6 @@ void* run_job(void *context) } #endif ctx->marshal_unmarshal(job); - - /* - * Add response to response queue - */ - enqueue(ctx->reply_jobs, job); - printf("Processed a job \n"); // Process next job } @@ -93,6 +88,7 @@ void *process_response(void *context) int write_result; struct comm_context *ctx = (struct comm_context *)context; struct client_txn *job; + struct session client_session; while (1) { /* @@ -103,9 +99,14 @@ void *process_response(void *context) if (job != NULL) { // Write message to client - write_result = write_message(job); - if (write_result == -1) - printf("Write message error\n"); + client_session = job->client_session; + if (get_elem(ctx->sessions, &client_session, + session_comparator) != NULL) { + /* session still valid */ + write_result = write_message(job); + if (write_result == -1) + printf("Write message error\n"); + } free(job); } else diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c index 3cdc608..6dc6170 100644 --- a/ndmp/src/ndmp_config.c +++ b/ndmp/src/ndmp_config.c @@ -12,6 +12,17 @@ #include #include #include +#include +#include +#include + +char *get_name(char *value, char *curr, char** saveptr); +char *get_value(char *value, char *curr, char** saveptr, int one_word); +struct ndmp_config_get_scsi_info_reply* alloc_scsi_info(); +void get_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info); +void free_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info); + +static char *fs_mount = "/"; /* change later */ /* * Each of the functions below take a client_txn and an XDR request stream as @@ -32,7 +43,8 @@ * */ -void ndmp_config_get_host_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +void ndmp_config_get_host_info(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) { /* NDMP_CONFIG_GET_HOST_INFO * @@ -75,7 +87,8 @@ void ndmp_config_get_host_info(struct client_txn *txn, struct ndmp_header header txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_host_info_reply, &reply); + xdr_ndmp_config_get_host_info_reply, + &reply); xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); @@ -202,7 +215,8 @@ void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header } -void ndmp_config_get_butype_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +void ndmp_config_get_butype_info(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) { /* NDMP_CONFIG_GET_BUTYPE_INFO * @@ -232,6 +246,48 @@ void ndmp_config_get_butype_info(struct client_txn *txn, struct ndmp_header head * }; */ + struct ndmp_config_get_butype_info_reply reply; + struct ndmp_butype_info *bu_type_info; + ndmp_header reply_header; + XDR reply_stream; + int i; + int bu_types[] = {NDMP_BUTYPE_BACKUP_FILELIST, NDMP_BUTYPE_BACKUP_DIRECT, + NDMP_BUTYPE_BACKUP_INCREMENTAL, NDMP_BUTYPE_BACKUP_UTF8}; + int num_attrs = 4; + reply.error = NDMP_NO_ERR; + reply.butype_info.butype_info_len = 3*num_attrs; + bu_type_info = (struct ndmp_butype_info *) + malloc(reply.butype_info.butype_info_len*sizeof(struct ndmp_butype_info)); + + for (i=0; i<3*num_attrs; i+=3) { + bu_type_info[i].butype_name = "dump"; + bu_type_info[i].attrs = bu_types[i/3]; + bu_type_info[i].default_env.default_env_len = 0; + bu_type_info[i+1].butype_name = "tar"; + bu_type_info[i+1].attrs = bu_types[i/3]; + bu_type_info[i+1].default_env.default_env_len = 0; + bu_type_info[i+2].butype_name = "cpio"; + bu_type_info[i+2].attrs = bu_types[i/3]; + bu_type_info[i+2].default_env.default_env_len = 0; + } + reply.butype_info.butype_info_val = bu_type_info; + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_butype_info_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + xdr_ndmp_config_get_butype_info_reply(&reply_stream, &reply); + + free(bu_type_info); + + } void ndmp_config_get_fs_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -267,7 +323,76 @@ void ndmp_config_get_fs_info(struct client_txn *txn, struct ndmp_header header, * ndmp_fs_info fs_info <>; * }; */ + + + struct statvfs statvfsbuf; + struct ndmp_header reply_header; + struct ndmp_config_get_fs_info_reply reply; + struct ndmp_fs_info *fs_info; + int rc; + XDR reply_stream; + rc = statvfs(fs_mount, &statvfsbuf); + if (rc == -1) + reply.error = NDMP_NOT_SUPPORTED_ERR; + else + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + + if (rc != -1) { + reply.fs_info.fs_info_len = 1; + reply.fs_info.fs_info_val = (struct ndmp_fs_info *) + malloc(sizeof(struct ndmp_fs_info)); + fs_info = reply.fs_info.fs_info_val; + fs_info->invalid = 0; + fs_info->fs_type = "glusterfs"; + fs_info->fs_logical_device = + (char *)malloc(strlen(fs_mount)*sizeof(char)); + strcpy(fs_info->fs_logical_device, fs_mount); + fs_info->fs_physical_device = + (char *)malloc(strlen(fs_mount)*sizeof(char)); + strcpy(fs_info->fs_physical_device, fs_mount); + + fs_info->total_size.low = + statvfsbuf.f_blocks*statvfsbuf.f_frsize/1024; + fs_info->total_size.high = 0; + fs_info->avail_size.low = + statvfsbuf.f_bavail*statvfsbuf.f_frsize/1024; + fs_info->avail_size.high = 0; + fs_info->used_size.low = fs_info->total_size.low - + statvfsbuf.f_bfree*statvfsbuf.f_frsize/1024; + fs_info->used_size.high = 0; + fs_info->total_inodes.low = statvfsbuf.f_files; + fs_info->total_inodes.high = 0; + fs_info->used_inodes.low = statvfsbuf.f_files - + statvfsbuf.f_ffree; + + fs_info->used_inodes.high = 0; + fs_info->fs_env.fs_env_len = 0; + fs_info->fs_status = "up"; + } + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_fs_info_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_fs_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_fs_info_reply, + &reply); + + free(fs_info->fs_logical_device); + free(fs_info->fs_physical_device); } void ndmp_config_get_tape_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -301,9 +426,53 @@ void ndmp_config_get_tape_info(struct client_txn *txn, struct ndmp_header header * }; */ + struct ndmp_header reply_header; + struct ndmp_config_get_tape_info_reply reply; + XDR reply_stream; + + ndmp_device_info tapeInfo; + ndmp_device_capability devCap; + ndmp_pval pval; + + reply.error = NDMP_NO_ERR; + reply.tape_info.tape_info_len = 1; + reply.tape_info.tape_info_val = &tapeInfo; + + tapeInfo.model = "HP MSL6000 Tape"; + tapeInfo.caplist.caplist_len = 1; + tapeInfo.caplist.caplist_val = &devCap; + + devCap.device = "/dev/tape0"; + devCap.attr = NDMP_TAPE_ATTR_REWIND; + devCap.capability.capability_len = 1; + devCap.capability.capability_val = &pval; + + pval.name = "TAPE_SIZE"; + pval.value = "1GB"; + + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_tape_info_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_tape_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_tape_info_reply, + &reply); } -void ndmp_config_get_scsi_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +void ndmp_config_get_scsi_info(struct client_txn *txn, + struct ndmp_header header, + XDR* request_stream) { /* NDMP_CONFIG_GET_SCSI_INFO * @@ -317,7 +486,52 @@ void ndmp_config_get_scsi_info(struct client_txn *txn, struct ndmp_header header * ndmp_device_info scsi_info <>; * }; */ + XDR reply_stream; + struct ndmp_header reply_header; + struct ndmp_config_get_scsi_info_reply reply; + struct ndmp_config_get_scsi_info_reply *scsi_info = + alloc_scsi_info(); + + + get_scsi_info(scsi_info); + + /* + * Check if there are any scsi devices + */ + if (scsi_info->scsi_info.scsi_info_len > 0) { + /* + * There is device info to be sent + */ + reply.error = NDMP_NO_ERR; + reply.scsi_info.scsi_info_len = + scsi_info->scsi_info.scsi_info_len; + reply.scsi_info.scsi_info_val = + scsi_info->scsi_info.scsi_info_val; + } + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_scsi_info_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_scsi_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_scsi_info_reply, + &reply); + + + free_scsi_info(scsi_info); } void ndmp_config_get_server_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -368,3 +582,198 @@ void ndmp_config_get_server_info(struct client_txn *txn, struct ndmp_header head xdr_ndmp_config_get_server_info_reply, &reply); } + +void get_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info ) +{ + /* + * This function reads scsi information from /proc/scsi/scsi + */ + + FILE *scsi = fopen("/proc/scsi/scsi", "r"); + char *data; + char *s; + char *name; + char *value; + char *saveptr; + int i, j,k; + struct ndmp_device_info *device_info; + struct ndmp_device_capability *device_capability; + struct ndmp_pval *pval; + char *model, *device; + data = (char *)malloc(80*sizeof(char)); + name = (char *)malloc(80*sizeof(char)); + value = (char *)malloc(80*sizeof(char)); + device = (char *) malloc(80*sizeof(char)); + + fgets(data, 80, scsi); // read and ignore first line + if (scsi != NULL) { + i = -1; + j = 0; + while(fgets(data,80, scsi) != NULL) { + // strtok_r is reentrant + s = strtok_r(data, " ", &saveptr); + if (strcmp(s,"Host:") == 0) { + /* + * New scsi device + */ + i++; + scsi_info->scsi_info.scsi_info_len = i+1; /* number of devices */ + device_info = scsi_info->scsi_info.scsi_info_val+i; + j = 0; + } + do { + strcpy(name, ""); + strcpy(value,""); + s = get_name(name, s, &saveptr); + + if (strcmp(s, "Type:") == 0) { + s = get_value(value, s, &saveptr,1); + } + else { + s = get_value(value, s, &saveptr,0); + } + + if (value[strlen(value)-1] == '\n') + value[strlen(value)-1] = '\0'; + + pval = device_info->caplist.caplist_val->capability.capability_val+j; + strcpy(pval->name, name); + strcpy(pval->value, value); + if (strcmp(name, "Model:") == 0) + strcpy(device_info->model, value); + if (strcmp(name, "Type:")==0) { + strcpy(device_info->caplist.caplist_val->device, value); + } + device_info->caplist.caplist_val->attr = j; + j++; + device_info->caplist.caplist_val->capability.capability_len = j; + device_info->caplist.caplist_len = 1; + }while(s!=NULL); + printf ("\n"); + } + } + free(data); + free(name); + free(value); + free(device); +} + + +char * get_name(char* name, char *curr, char** saveptr) +{ + + while(curr!= NULL && curr[strlen(curr)-1] != ':') { + if(strcmp(name,"") == 0) + strcpy(name, curr); + else + sprintf(name,"%s %s", name, curr); + curr = strtok_r(NULL, " ", saveptr); + } + if (strcmp(name, "") == 0) + strcpy(name, curr); + else + sprintf(name, "%s %s", name, curr); + return name; +} + +char *get_value(char *value, char *curr, char** saveptr, int one_word) +{ + + curr = strtok_r(NULL, " ", saveptr); + if (!one_word) { + while(curr!=NULL && curr[strlen(curr)-1] != ':') { + if(strcmp(value, "") == 0) + strcpy(value,curr); + else + sprintf(value,"%s %s",value, curr); + curr = strtok_r(NULL, " ", saveptr); + } + } + else { + strcpy(value,curr); + curr = strtok_r(NULL, " ", saveptr); + } + return curr; +} + +struct ndmp_config_get_scsi_info_reply* alloc_scsi_info() { + /* + * Allocation approach: + * ndmp_config_get_scsi_info_reply has many nmpd_device_info structs + * one for each device + * Each ndmp_device_info has a ndmp_device_capabilty struct, which + * has a number of properties ndmp_pval structs. + * + * Assumptions: We will assume a max of 32 scsi devices + * which is plenty. + * We will assume max of 16 name-value properties for each + * device, which should also be plenty. + * These assumptions simplify getting scsi information + * and setting them in struct ndmp_config_get_scsi_info_repy + * especially having to set info_len attribute and capability_len + * attributes. It would require a two pass traversal of scsi device + * info, otherwise. + */ + + int max_number_of_devices = 32; + int max_number_of_properties = 16; + int str_size = 32; + int i,j; + + struct ndmp_config_get_scsi_info_reply* retval; + struct ndmp_device_capability device_capability; + struct ndmp_device_info *device; + struct ndmp_pval *pval; + retval = malloc(sizeof(struct ndmp_config_get_scsi_info_reply)); + + retval->scsi_info.scsi_info_val = (struct ndmp_device_info *) + malloc(max_number_of_devices* + sizeof(struct ndmp_device_info)); + + for (i=0; iscsi_info.scsi_info_val+i; + device->model = malloc(str_size*sizeof(char)); + device->caplist.caplist_val = (struct ndmp_device_capability *) + malloc(sizeof(struct ndmp_device_capability)); + device->caplist.caplist_val->capability.capability_val = (struct ndmp_pval *) + malloc(max_number_of_properties*sizeof(struct ndmp_pval)); + device->caplist.caplist_val->device = (char *) + malloc(str_size*sizeof(char)); + + for (j=0; jcaplist.caplist_val->capability.capability_val+j; + pval->name = (char *) malloc(str_size*sizeof(char)); + pval->value = (char *)malloc(str_size*sizeof(char)); + } + } + return retval; +} + +void free_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info) { + /* + * Frees space held in scsi_info as per assumption + * in alloc_scsi_info + */ + + int max_number_of_devices = 32; + int max_number_of_properties = 16; + int i,j; + + struct ndmp_device_capability *device_capability; + struct ndmp_device_info *device; + struct ndmp_pval *pval; + + for (i=0; iscsi_info.scsi_info_val+i; + free(device->model); + device_capability = device->caplist.caplist_val; + for (j=0; jcapability.capability_val[j].name); + free(device_capability->capability.capability_val[j].value); + } + free(device_capability->device); + free(device_capability); + } + free(scsi_info->scsi_info.scsi_info_val); + free(scsi_info); +} diff --git a/ndmp/src/ndmp_connect.c b/ndmp/src/ndmp_connect.c index dc6524f..f1eab8e 100644 --- a/ndmp/src/ndmp_connect.c +++ b/ndmp/src/ndmp_connect.c @@ -120,13 +120,13 @@ void ndmp_connect_close(struct client_txn *txn, session_info->mover_state = HALTED; set_header(header, &reply_header, 0); - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); + //txn->reply.length = xdr_sizeof((xdrproc_t) + // xdr_ndmp_header, &reply_header); - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); + //xdrmem_create(&reply_stream, + //txn->reply.message, txn->reply.length,XDR_ENCODE); - xdr_ndmp_header(&reply_stream, &reply_header); + //xdr_ndmp_header(&reply_stream, &reply_header); exit_critical_section(session_info->s_lock); } diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index 210a014..b2a0245 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -11,8 +11,11 @@ #include #include #include -int session_info_cmp (void *id, void *session); +int session_info_cmp (void *id, void *session); +int job_cmp(void *target, void*elem); +void add_job_to_session(struct client_txn *txn); +struct queue_hdr* get_session_queue() ; /* * xdr_decode_encode is the entry point * and callback method for the comm layer @@ -36,6 +39,7 @@ void xdr_decode_encode(struct client_txn *txn) struct ndmp_header header; char *buf, mesg_len[4]; int len; + struct comm_context *ctx = comm_context(); if (txn->request.is_tcp_connect == 1) { header.message = 0xf001; } @@ -48,7 +52,11 @@ void xdr_decode_encode(struct client_txn *txn) xdr_ndmp_header(&request_stream, &header); } - + /* + * Add job to session's job queue + */ + + add_job_to_session(txn); ndmp_dispatch(header.message)(txn, header, &request_stream); buf = (char *)malloc(txn->reply.length+4); @@ -58,7 +66,19 @@ void xdr_decode_encode(struct client_txn *txn) xdr_int(&stream_len, &len); memcpy(buf,mesg_len,4); memcpy(txn->reply.message, buf, txn->reply.length+4); - txn->reply.length +=4; + txn->reply.length +=4; + if (cleanup_session(txn) == 1) { + free(txn); /* client terminated. Don't send response */ + } + else { + /* + * It is possible that at this point in time + * or later before the response is sent the client + * terminates. comm layer needs to check again for + * client termination, before sending the response + */ + enqueue(ctx->reply_jobs, txn); + } free(buf); } @@ -114,13 +134,17 @@ void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* struct ndmp_header reply_header; XDR reply_stream; - header.sequence = 0; - header.message = 0x0502; reply.reason = NDMP_CONNECTED; reply.protocol_version = 3; - reply.text_reason = ""; + reply.text_reason = "Successful connection"; - set_header(header, &reply_header, NDMP_NO_ERR); + reply_header.sequence = get_next_seq_number(); + reply_header.time_stamp = (u_long) time(NULL); + reply_header.message_type = NDMP_MESSAGE_REQUEST; + reply_header.message = NDMP_NOTIFY_CONNECTED; + reply_header.reply_sequence = 0; + reply_header.error = NDMP_NO_ERR; + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); @@ -155,9 +179,30 @@ void set_header(ndmp_header req, ndmp_header *reply, ndmp_error err) } -struct ndmp_session_info* get_session_info(int session_id) { +/* + * get_session_queue can be called from + * different threads concurrently. + * Needs to be thread-safe. + */ +struct queue_hdr* get_session_queue() +{ static struct queue_hdr *session_info_queue = NULL; + struct lock *s_lock = get_lock(); + enter_critical_section(s_lock); + + if (session_info_queue == NULL) { + session_info_queue = init_queue(); + } + exit_critical_section(s_lock); + + return session_info_queue; +} + +struct ndmp_session_info* get_session_info(int session_id) { + + + struct queue_hdr* session_queue; struct ndmp_session_info *retval; struct lock *s_lock = get_lock(); @@ -172,9 +217,8 @@ struct ndmp_session_info* get_session_info(int session_id) { * */ enter_critical_section(s_lock); - if (session_info_queue == NULL) { - session_info_queue = init_queue(); - } + + session_queue = get_session_queue(); /* * Since we create a new sessions @@ -182,7 +226,7 @@ struct ndmp_session_info* get_session_info(int session_id) { * thread-safe */ - retval = get_elem(session_info_queue, (void *)&session_id, + retval = get_elem(session_queue, (void *)&session_id, session_info_cmp); if (retval == NULL) { @@ -198,7 +242,9 @@ struct ndmp_session_info* get_session_info(int session_id) { retval->data_state = LISTEN; retval->mover_state = LISTEN; retval->s_lock = get_lock(); - enqueue(session_info_queue, retval); + retval->jobs = init_queue(); + retval->is_terminated = 0; + enqueue(session_queue, retval); } exit_critical_section(s_lock); return retval; @@ -212,4 +258,73 @@ int session_info_cmp (void *id, void *session) return session_id == queue_elem_session_id; } - + +/* + * Each NDMP request (job) that is handled is added + * to an outstanding jobs queue till it is processed + * and completed. + */ + +void add_job_to_session(struct client_txn *txn) +{ + struct ndmp_session_info *session; + + session = get_session_info(txn->client_session.session_id); + enqueue(session->jobs, txn); +} +/* + * Each session will have outstanding jobs held in + * a queue; one queue element for each request in + * a thread. cleanup_session is a callback method that + * the comm layer will call back on the worker thread + * after it has sent the response. + * We remove the client_txn (txn) from the session job + * queue. + * + * If all jobs are done and the session is terminated, + * we remove the session from the session queue. + * + */ + +int cleanup_session(struct client_txn *txn) +{ + struct ndmp_session_info *session; + struct queue_hdr *session_queue; + + session = get_session_info(txn->client_session.session_id); + remove_elem(session->jobs, txn, job_cmp); + if (session->is_terminated) { + /* + * If all jobs are done, remove session + */ + if (num_elems(session->jobs) == 0) { + session_queue = get_session_queue(); + remove_elem(session_queue, + &session->session_id, + session_info_cmp); + free(session); + } + return 1; /* session terminated */ + } + return 0; /* session active */ +} + +int job_cmp(void *target, void *elem) +{ + return target == elem; +} + +/* + * terminate_session is called to indicate the + * termination of client - socket close event at comm layer + * When a session is marked for termination, results/responses for + * outstanding jobs are not sent back to comm layer. + */ + +void terminate_session(int session_id) +{ + struct ndmp_session_info *session; + + session = get_session_info(session_id); + session->is_terminated = 1; +} diff --git a/ndmp/src/ndmp_msg.h b/ndmp/src/ndmp_msg.h index 46e104a..fcaa62c 100644 --- a/ndmp/src/ndmp_msg.h +++ b/ndmp/src/ndmp_msg.h @@ -14,6 +14,7 @@ #include #include #include +#include enum ndmp_state {IDLE, LISTEN, CONNECTED, ACTIVE, HALTED}; struct ndmp_session_info { @@ -22,6 +23,8 @@ struct ndmp_session_info { enum ndmp_state data_state; enum ndmp_state mover_state; struct lock *s_lock; /* for thread-safe updates to session states */ + struct queue_hdr *jobs; /* outstanding client requests */ + int is_terminated; }; /* @@ -51,10 +54,31 @@ typedef void (*ndmp_message_handler)(struct client_txn *txn, ndmp_message_handler ndmp_dispatch(int message_type); + +/* + * Each session will have outstanding jobs held in + * a queue; one queue element for each request in + * a thread. We remove the client_txn (txn) from + * the session job queue. + */ + +int cleanup_session(struct client_txn *txn); + +/* + * terminate_session is called to indicate the + * termination of client - socket close event at comm layer + * When a session is marked for termination, results/responses for + * outstanding jobs are not sent back to comm layer. + */ + +void terminate_session(int session_id); + /* * get_next_seq_number returns the next number in * sequence for messages */ + + int get_next_seq_number(); /* diff --git a/ndmp/src/test/makefile b/ndmp/src/test/makefile index cf808c0..88b6db9 100644 --- a/ndmp/src/test/makefile +++ b/ndmp/src/test/makefile @@ -20,9 +20,8 @@ OBJS = $(ROOT)/ndmp/src/ndmp_connect.o \ $(ROOT)/utils/src/hexdump.o \ $(ROOT)/utils/src/queue.o -all: testndmp -testndmp: testndmp.c +testndmp: gcc $(CFLAGS) -c testndmp.c gcc $(CFLAGS) -o testndmp testndmp.o $(OBJS) $(LIBS) diff --git a/ndmp/src/test/testndmp.c b/ndmp/src/test/testndmp.c index b4163da..6846793 100644 --- a/ndmp/src/test/testndmp.c +++ b/ndmp/src/test/testndmp.c @@ -16,6 +16,8 @@ main() { struct comm_context *ctx = comm_context(); ctx->marshal_unmarshal = xdr_decode_encode; + ctx->cleanup_session = cleanup_session; + ctx->terminate_session = terminate_session; comm_listen(ctx); } diff --git a/utils/src/hexdump.c b/utils/src/hexdump.c index 1ea1392..f0affc4 100644 --- a/utils/src/hexdump.c +++ b/utils/src/hexdump.c @@ -15,7 +15,7 @@ void hexdump(void *buffer, unsigned int size) int i, j; for (i = 0; i < size; i += 16) { - printf("%08x ", i); + printf("%04x ", i); dump_hex(buf, i, size); dump_ascii(buf, i, size); } From 6476c8d1a3ebe2492ec7aeed7bf0cf6210102dc6 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 26 Mar 2013 11:42:41 +0530 Subject: [PATCH 11/18] Connect and config complete, code alignment complete. --- ndmp/src/ndmp_connect.c | 14 ++------------ ndmp/src/ndmp_msg.c | 25 ++++++++++++++----------- ndmp/src/test/testndmp | Bin 125019 -> 0 bytes ndmp/src/test/testndmp.o | Bin 6792 -> 0 bytes 4 files changed, 16 insertions(+), 23 deletions(-) delete mode 100755 ndmp/src/test/testndmp delete mode 100644 ndmp/src/test/testndmp.o diff --git a/ndmp/src/ndmp_connect.c b/ndmp/src/ndmp_connect.c index f1eab8e..c861fb7 100644 --- a/ndmp/src/ndmp_connect.c +++ b/ndmp/src/ndmp_connect.c @@ -103,9 +103,7 @@ void ndmp_connect_close(struct client_txn *txn, /* no request arguments */ /* no reply message */ - struct ndmp_header reply_header; struct ndmp_session_info *session_info; - XDR reply_stream; session_info = get_session_info(txn->client_session.session_id); @@ -115,19 +113,11 @@ void ndmp_connect_close(struct client_txn *txn, * States set as per Figure 8 in NDMP V3 spec. */ - session_info->connection_state = HALTED; + session_info->connection_state = HALTED; // No state diagram for connect? session_info->data_state = HALTED; session_info->mover_state = HALTED; - set_header(header, &reply_header, 0); + txn->reply.length = 0; // No reply to be sent - //txn->reply.length = xdr_sizeof((xdrproc_t) - // xdr_ndmp_header, &reply_header); - - //xdrmem_create(&reply_stream, - //txn->reply.message, txn->reply.length,XDR_ENCODE); - - //xdr_ndmp_header(&reply_stream, &reply_header); exit_critical_section(session_info->s_lock); } - diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index b2a0245..38af683 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -59,15 +59,7 @@ void xdr_decode_encode(struct client_txn *txn) add_job_to_session(txn); ndmp_dispatch(header.message)(txn, header, &request_stream); - buf = (char *)malloc(txn->reply.length+4); - memcpy(buf+4,txn->reply.message,txn->reply.length); - len = txn->reply.length | (1<<31); - xdrmem_create(&stream_len,mesg_len,4, XDR_ENCODE); - xdr_int(&stream_len, &len); - memcpy(buf,mesg_len,4); - memcpy(txn->reply.message, buf, txn->reply.length+4); - txn->reply.length +=4; - if (cleanup_session(txn) == 1) { + if (cleanup_session(txn) == 1 || txn->reply.length == 0) { free(txn); /* client terminated. Don't send response */ } else { @@ -77,9 +69,19 @@ void xdr_decode_encode(struct client_txn *txn) * terminates. comm layer needs to check again for * client termination, before sending the response */ + + buf = (char *)malloc(txn->reply.length+4); + memcpy(buf+4,txn->reply.message,txn->reply.length); + len = txn->reply.length | (1<<31); + xdrmem_create(&stream_len,mesg_len,4, XDR_ENCODE); + xdr_int(&stream_len, &len); + memcpy(buf,mesg_len,4); + memcpy(txn->reply.message, buf, txn->reply.length+4); + txn->reply.length +=4; enqueue(ctx->reply_jobs, txn); + free(buf); } - free(buf); + } ndmp_message_handler ndmp_dispatch(int message) { @@ -136,7 +138,7 @@ void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* reply.reason = NDMP_CONNECTED; reply.protocol_version = 3; - reply.text_reason = "Successful connection"; + reply.text_reason = ""; reply_header.sequence = get_next_seq_number(); reply_header.time_stamp = (u_long) time(NULL); @@ -145,6 +147,7 @@ void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* reply_header.reply_sequence = 0; reply_header.error = NDMP_NO_ERR; + //set_header(header, &reply_header, NDMP_NO_ERR); txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); diff --git a/ndmp/src/test/testndmp b/ndmp/src/test/testndmp deleted file mode 100755 index b2373e5587f264b18269bb25a226acd2dbb98556..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125019 zcmeFadw3K@_6FSDGnwuVGfWr)DhCgAg4RG$1IeDAyn;1SE+!1Og$- z7^9%5=&Fk@x?a#9yWWDL1VlkaK}E$oDy)g%E-I_2xcT0z+6Vmn5l3=yA6 zNLv1s?5dc=>lL#^6EG$&Y}n75ybW!>;ozg5NBU#yIl>w*m0cRG`PtBFD#uToI^m># z$4{HoYuePZ%4>RE)BmJiC-v)HKBISEG4Bj0LfSLW9VJw*Df*jI$k~#jzekGx)hXnkoudEs6#WmR=zlH6 zxbsr8l$Cq@6(6#b)8^dFm||EU!E)Tf}o2lP?=Klo={3i_QOJe(hPN>7?1<9Krj}Qf z&Kf*ze0h0kxl&$QHc7Fl#$G$MbXu}Cy|SY8nz2*MrdBAkN+(|BP|5yjGbUc4jGs8M zbY_Jzd16_`GzUKsBUY3u6Q|86FLgR4Q)QW88$0&0=`+g4mRF3QRWWuf^_)lzPg1U# zG;3`6lo_)slyZnKtx!s@!RS*eW|U16pXJKbveJsNWfe2VD>ExA%9V<#(@T}Hlr-^* zu@k3UF?RC!snDddV&atXvnXzQ>GZLdLen_$GR$~d>BI^#RHZf8#PQRhm*^@jtDLS( zmK?V^u(FhLS6-xodG*cPs*8ERsp>xR$M!?bnJw& zlwMvjsdSdmX>27_mFkV1F?0Ntm8HsMr4>_Vlvk9E$8;vog!l?M>iAi+#$T&civF=< zX(-ET)5lLO6Ut1uwgSrti%gj&KFgKKvr0>qGl!ma`rxsBd-v^qqH}$MbJeGxbJ-6b zqv70?|Lso=Cu;IqJLsBi=1hn0r!0w)QUjvJbC>@Vh39w_|0{E*nmn<8V<&!8jQJ=a z@%(8&b!vzwwTZ#lw{*#!IJVQ2_EtMn;QdNht1abej=UYWj-wcH*5`^V`C;!9ragUK z{mSBTqNU^0Qc1K8S3l=%|75uOofHqqELXpsOOYq)>bFuZA*#^T@6NZ1T>aF^{^{@P zclJ7vF;_nf>-@xB{pn6G@inSxcb{Vy^1o^)gN~CU*qbx z*P7@mS3hIB{jUH$ECV!&mte&&Ss&vI9P2fGvS5m$dlSN|$ked&@20XMn&b6ovfUH$IFbGxg*i;I4TtG}zOztPp7=jz|<>W{km_q+PLx%w6B z{GhLOcl8^t{(M(|hO588)t}|+XHIDUL|y$y*`0ueuKq$-f03*I7*~IPS3l2U`zPk= zKhEw1jJx`Ky8268{k>fMqh0;IUH#)+{l~ldr?~oyT>Ud${e4{h@#;NB<6uOL#&`Jf z+c>CLy}@|dCTTwLv8t%j++!s^!+9}Wu|0+8rX9`r>G2@jD%)E{`yRF#nwlC!`!=>A zTWMM)+BdPyP}Hv=^jq`tu?I_zjMEgOuyRp4hwC`b?Tehh|v~OcOpY2tm zeG}WYl@2Y>1=b$HD!qQDQt7AH7RKK`Sz^D+n2@@U&gC#Y9@g*-$o;d3-7EZD@s7#Rw!OHh-tW7bIL={rJG<*D9bMf1wWGGi>x!4hYllH-umCVC zo)}ty6&V)gMFuVkd69*SB3?wLiq9a})W1;>Q=t9wxa@lcOP^S8DV|tdfc*VQnht>%1ahHk$K11`7vEx7@VR$IKarlB$) z`eBNK$wK-NcWAkdF+U^j?*9Kn$$uTdv_3j!ePZh&iYAw1%SZ^Fzk#a@XA;gaf6sEE z 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 e^dL7=BQ$|qCBO9oRy8jG diff --git a/ndmp/src/test/testndmp.o b/ndmp/src/test/testndmp.o deleted file mode 100644 index bd9dde834e7d0f46ae1ab1c98b593a7f09b94e39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6792 zcmbtYU2GKB6}~gOX2-0(UfY=10jwoXf+_YcU}G%O5`#rCDop|{0tGdb@$Ptc?A_Vz z%xo~uLn_hyAk>IdRgfx$@(?AZQlnOBRHRB(t4N8OhenmE_N6~+n@CZbM$H>-Q0Y1M zp1V6fSzg*JcJ4Xf`9JsGxnrI>a{P;?VF*18aZt25jS8`lZqsv;oD)N0K%82*`2NC$ zkFqxq`v4yc7mwUrxCFnqkrR@<__h@N>P<0`6vC7OONQwbON#Mf8kU^Ql$?@kveaa3 zP_izZ63H&lkA!JSE@_!cD!Hurg)5+<)E`9B93yT{ah6C~KHw_aAta^cxcSgskf5@B zE`D%nXTvlRDLCF@b#870dq?oq{UQry{>q?cjQJ#HR91fezpFHHCQ@Koed z8!bPE!gLuPCqT95Fc3Q^=L+U&QfE{XR0WC5)4GC0ADTh!s<>=&(`#Ck9CE>#ZcB1A z3d}KV3tCH0x#Y;dTIzQz1=X447E+frCAXrQIi~7OZd3IRgR5o0Wrw@AO+z$EZrIx< zr?G7kO*tE3k0|n6LqN(5lBwrU04<}WF7E=eT}$dOFSbN~yDbwS#rJYj(Nt#d&qz)! zTj~Qe!aCEF5c(BhWK&Zr-X?47uK|*V);0_c@p_j^!WyL|6&WxSmSt^ECA8u_N=9a5 zC@{xVJnLSRCC0v)RjW7*vcAIr-KL1c){a9hN8{@p?ZoWBkqSAUwI{AFP@dh zq|LEmm3INT#Mrg0YNxgLY0ynsm*AN-uE4V&AAn$BwPmcSe*&${r!h*)^*$6pzm#l7 zacZHh{feWovnu%IhV}M(m zTeuM2cNuMqjcp4!Y=&`c5dHLQ7smz*;J+8dR@-4lhU?Pd`lK4PF*{`J=t0B&E--`! z zJYhe;STE8xQWSgK0@@URhNoeCn(2k7yec3)qtFb4g69{j&5~PKot?2~rYEbO-&~z6 z`_00l7lk69FQ|Xb$g75hFer++)jFo&yO9UKwo$QOt4SLXxnbm&YK?pmQ)@((z;#N| z`Gy%|o$p|YZ!wfCN2tdhQ->upL{u6!1 zh2Q`1XQm0&+IGo_98q&tmr9}Vn>E|5y0uUQZlii$gq3;_^2BM53^Hg*KwJYQE~*P4;L3ZQKl>rL>4IROc#s|Y$(uj~siw4-7JVc#vb zqJ{iW9hY&F&Vk4b_F6dft}hLcZPCA_sjqq${y>wXjL@p`lUu4)u}cidyiFkYc4J3 zy0CIBYOu6U*%dNTXm2xg1MEm~MI3$TRBk>uouA21#rJ4?2dKpjh4w*vKyMe>xCZPY z$U$!!+$&HBXrcfp+peGU-9Q)N`Ac=c1IwL%wwmWwOth^Sv9E zK>@*hc)k`ni!eulnk$+L+^Un82O}?!WqvV)myAS9?qahHbwYFUigp$k@oW$WRjku= z0>>}A>#gDKI^#4C{-~!+J@@kE_ znHw(yh_kbZ&k*GSc=~e>ePi{cyTF#vj!ik_BX}sDpi{ z_-81--e(ve|CHqMzX2Hf)Oi9a$0)5^hHWezU(c67yOaF{eOB!ve|pk(dj1aCYq_3J z$3M$7*g^L?VXe;y(mg}=voTvFb^RKC8Hi5(Yjo&eHfFE;+7B3Ok#v2T;=eAr_CwdL z5#)L9D0>cr!T1pw;CmfDyj%I}__(J!#h<0~_j!=V2ag|@#c9+_icfCGF-<2r?pVyD zQznRa>M-JT$h2dc6M{D1XK=oHN+BUn7E=Z`A$NQyy!W%9)bG0kPK&{$3H3+eIV=kf0E(fBmN@8e@y&UhF8e{b%yUF{0)X1bhO`OxX$}G48K5r@NZZg zy8l_i|DoU({toerpFc8O=daI)?myl| za*&4nlR|((D^j{!+JHyWtKf&-XDfePO!yhJop5glbJjw8%6aN^)Um^ch zhTFuiG5mhY|2c-234fL0ZxQ}F!#||B?=t*9r2hwoKTG-_GW;mvcIz zdiODWocvEQ{1WLOX1G4*4>SCy6!&Wk{~h5g4AVksp&jdC;6vmy(SP*Z0=|;kYi^HyY@>74i7jlD?z4 R|BuiJ2FG&}Rk_6T`7cl6s`LN= From 1699484d23f5cbc0d4018b8d6a329122700d4173 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 26 Mar 2013 12:42:24 +0530 Subject: [PATCH 12/18] Test commit - setting tabs to 8 spaces. --- ndmp/src/ndmp_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index 38af683..532ed85 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -138,7 +138,7 @@ void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* reply.reason = NDMP_CONNECTED; reply.protocol_version = 3; - reply.text_reason = ""; + reply.text_reason = "SUCCESSFUL CONNECTION"; reply_header.sequence = get_next_seq_number(); reply_header.time_stamp = (u_long) time(NULL); From efeb74f684755d7684be9effc38a7c0c5bd2e002 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Tue, 26 Mar 2013 12:55:26 +0530 Subject: [PATCH 13/18] Test commit - setting tabs to 8 spaces --- comm/src/comm.c | 366 ++++++------ comm/src/comm.h | 36 +- comm/src/worker.c | 190 +++---- ndmp/src/ndmp.x | 914 ++++++++++++++--------------- ndmp/src/ndmp_config.c | 1200 +++++++++++++++++++-------------------- ndmp/src/ndmp_connect.c | 148 ++--- ndmp/src/ndmp_msg.c | 430 +++++++------- ndmp/src/ndmp_msg.h | 20 +- utils/src/hexdump.c | 56 +- utils/src/locks.c | 16 +- utils/src/locks.h | 2 +- utils/src/queue.c | 198 +++---- utils/src/queue.h | 12 +- 13 files changed, 1794 insertions(+), 1794 deletions(-) diff --git a/comm/src/comm.c b/comm/src/comm.c index 93e606b..7cc4e0f 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -24,14 +24,14 @@ void handle_a_client_request(int fd, struct comm_context *ctx); struct comm_context* comm_context() { - static struct comm_context *retval = NULL; - if (retval == NULL ) { - retval = calloc(1, sizeof(struct comm_context)); - retval->sessions = init_queue(); - retval->request_jobs = init_queue(); - retval->reply_jobs = init_queue(); - } - return retval; + static struct comm_context *retval = NULL; + if (retval == NULL ) { + retval = calloc(1, sizeof(struct comm_context)); + retval->sessions = init_queue(); + retval->request_jobs = init_queue(); + retval->reply_jobs = init_queue(); + } + return retval; } /* @@ -49,48 +49,48 @@ struct comm_context* comm_context() int create_listener(int port) { - int retval; /* return the socket the listener should listen on */ - struct sockaddr_in listener; - int reuse = 1; + int retval; /* return the socket the listener should listen on */ + struct sockaddr_in listener; + int reuse = 1; - listener.sin_family = AF_INET; - listener.sin_addr.s_addr = INADDR_ANY; - listener.sin_port = htons(port); + listener.sin_family = AF_INET; + listener.sin_addr.s_addr = INADDR_ANY; + listener.sin_port = htons(port); - /* now create a socket and bind to listener */ - retval = socket(AF_INET, SOCK_STREAM, 0); + /* now create a socket and bind to listener */ + retval = socket(AF_INET, SOCK_STREAM, 0); - setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); - fcntl(retval, F_SETFL, O_NONBLOCK); - if (bind(retval, (struct sockaddr *) &listener, - sizeof(struct sockaddr_in)) == -1) - errExit("Error:bind"); + setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); + fcntl(retval, F_SETFL, O_NONBLOCK); + if (bind(retval, (struct sockaddr *) &listener, + sizeof(struct sockaddr_in)) == -1) + errExit("Error:bind"); - return retval; + return retval; } struct client_endpoint accept_connection(int listener) { - struct sockaddr_in client; - socklen_t len; - int sockfd; - struct client_endpoint retval; - - retval.fd = -1; - printf("Accepting new connection ..\n"); - sockfd = accept(listener, (struct sockaddr *) &client, &len); - if (sockfd < 0) { - printf("Oops! Cannot accept new connection :( \n"); - return retval; - } - - fcntl(sockfd, F_SETFL, O_NONBLOCK); - retval.client = client; - retval.fd = sockfd; - - printf("Accepted new connection ..\n"); - return retval; + struct sockaddr_in client; + socklen_t len; + int sockfd; + struct client_endpoint retval; + + retval.fd = -1; + printf("Accepting new connection ..\n"); + sockfd = accept(listener, (struct sockaddr *) &client, &len); + if (sockfd < 0) { + printf("Oops! Cannot accept new connection :( \n"); + return retval; + } + + fcntl(sockfd, F_SETFL, O_NONBLOCK); + retval.client = client; + retval.fd = sockfd; + + printf("Accepted new connection ..\n"); + return retval; } /* @@ -100,16 +100,16 @@ struct client_endpoint accept_connection(int listener) void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) { - struct session **active_sessions; - int n, i; - FD_ZERO(fds); - FD_SET(listener, fds); - - active_sessions = (struct session **) get_all_elems(ctx->sessions); - n = num_elems(ctx->sessions); - for (i = 0; i < n; i++) { - FD_SET(active_sessions[i]->session_id, fds); - } + struct session **active_sessions; + int n, i; + FD_ZERO(fds); + FD_SET(listener, fds); + + active_sessions = (struct session **) get_all_elems(ctx->sessions); + n = num_elems(ctx->sessions); + for (i = 0; i < n; i++) { + FD_SET(active_sessions[i]->session_id, fds); + } } /* @@ -130,113 +130,113 @@ void set_fd_flags(fd_set *fds, int listener, struct comm_context *ctx) void comm_listen(struct comm_context *ctx) { - fd_set read_socks; - int listener = create_listener(LISTEN_PORT); - struct client_endpoint endpoint; - struct client_endpoint *temp; - int ready; - int new_connections; - - FD_ZERO(&read_socks); - - listener = create_listener(LISTEN_PORT); - listen(listener, NUM_SESSIONS); - - printf("Listening on port %d....\n", LISTEN_PORT); - /* - * add listening socket to read_socks - * for multiplexing listening as well - */ - FD_SET(listener, &read_socks); - ctx->maxfds = listener; - - /* Create Worker Threads */ - create_worker_threads(THREAD_POOL_SIZE); - /* when the listener wakes up create a session */ - - for (;;) { - printf("Wait on select \n"); - set_fd_flags(&read_socks, listener, ctx); - ready = select((ctx->maxfds) + 1, &read_socks, NULL, NULL, - NULL ); - printf("Woke up from select \n"); - if (ready != -1) { - if (FD_ISSET(listener, &read_socks)) { - new_connections = accept_all_connections( - listener, &read_socks, ctx); - printf("%d new connection(s) \n", - new_connections); - } else { - /* - * Some client session is active - */ - handle_client_requests(&read_socks, ctx); - } - } - - } + fd_set read_socks; + int listener = create_listener(LISTEN_PORT); + struct client_endpoint endpoint; + struct client_endpoint *temp; + int ready; + int new_connections; + + FD_ZERO(&read_socks); + + listener = create_listener(LISTEN_PORT); + listen(listener, NUM_SESSIONS); + + printf("Listening on port %d....\n", LISTEN_PORT); + /* + * add listening socket to read_socks + * for multiplexing listening as well + */ + FD_SET(listener, &read_socks); + ctx->maxfds = listener; + + /* Create Worker Threads */ + create_worker_threads(THREAD_POOL_SIZE); + /* when the listener wakes up create a session */ + + for (;;) { + printf("Wait on select \n"); + set_fd_flags(&read_socks, listener, ctx); + ready = select((ctx->maxfds) + 1, &read_socks, NULL, NULL, + NULL ); + printf("Woke up from select \n"); + if (ready != -1) { + if (FD_ISSET(listener, &read_socks)) { + new_connections = accept_all_connections( + listener, &read_socks, ctx); + printf("%d new connection(s) \n", + new_connections); + } else { + /* + * Some client session is active + */ + handle_client_requests(&read_socks, ctx); + } + } + + } } int accept_all_connections(int listener, fd_set *read_socks, - struct comm_context *ctx) + struct comm_context *ctx) { - struct client_endpoint endpoint; - struct session* new_session; - struct client_txn* txn; - - int num_new_sessions = 0; - - // do { - endpoint = accept_connection(listener); - if (endpoint.fd != -1) { - /* - * Add new connection to session queue - * in comm_context - */ - - new_session = (struct session*) malloc(sizeof(struct session)); - new_session->session_id = endpoint.fd; - new_session->client_info = endpoint; - enqueue(ctx->sessions, new_session); - /* - * add to select list of sockets - */ - FD_SET(endpoint.fd, read_socks); - if (endpoint.fd > ctx->maxfds) { - ctx->maxfds = endpoint.fd; - } - - printf("Connection request from %s at %d\n", - inet_ntoa(endpoint.client.sin_addr), - ntohs(endpoint.client.sin_port)); - - txn = (struct client_txn *) malloc(sizeof(struct client_txn)); - - /* - * Create a pseudo NDMP request for the tcp_connect request - * so that a NDMP_NOTIFY_CONNECTED request can be sent to client - */ - - txn->client_session = *new_session; - txn->request.is_tcp_connect = 1; - enqueue(ctx->request_jobs, txn); - num_new_sessions++; - } - // } while (endpoint.fd != -1); - - return num_new_sessions; + struct client_endpoint endpoint; + struct session* new_session; + struct client_txn* txn; + + int num_new_sessions = 0; + + // do { + endpoint = accept_connection(listener); + if (endpoint.fd != -1) { + /* + * Add new connection to session queue + * in comm_context + */ + + new_session = (struct session*) malloc(sizeof(struct session)); + new_session->session_id = endpoint.fd; + new_session->client_info = endpoint; + enqueue(ctx->sessions, new_session); + /* + * add to select list of sockets + */ + FD_SET(endpoint.fd, read_socks); + if (endpoint.fd > ctx->maxfds) { + ctx->maxfds = endpoint.fd; + } + + printf("Connection request from %s at %d\n", + inet_ntoa(endpoint.client.sin_addr), + ntohs(endpoint.client.sin_port)); + + txn = (struct client_txn *) malloc(sizeof(struct client_txn)); + + /* + * Create a pseudo NDMP request for the tcp_connect request + * so that a NDMP_NOTIFY_CONNECTED request can be sent to client + */ + + txn->client_session = *new_session; + txn->request.is_tcp_connect = 1; + enqueue(ctx->request_jobs, txn); + num_new_sessions++; + } + // } while (endpoint.fd != -1); + + return num_new_sessions; } void handle_client_requests(fd_set *read_socks, struct comm_context *ctx) { - int i; - for (i = 0; i <= ctx->maxfds; i++) { - printf("Checking for event on sock %d\n", i); - if (FD_ISSET(i,read_socks)) { - handle_a_client_request(i, ctx); - } - } + int i; + for (i = 0; i <= ctx->maxfds; i++) { + printf("Checking for event on sock %d\n", i); + if (FD_ISSET(i,read_socks)) { + handle_a_client_request(i, ctx); + } + } } /* @@ -245,48 +245,48 @@ void handle_client_requests(fd_set *read_socks, struct comm_context *ctx) void handle_a_client_request(int fd, struct comm_context *ctx) { - struct session tmp; - tmp.session_id = fd; - struct client_txn* txn; - int n; - - txn = (struct client_txn *) malloc(sizeof(struct client_txn)); - tmp = *(struct session *) get_elem(ctx->sessions, &tmp, - session_comparator); - txn->client_session = tmp; - txn->request.length = recv(fd, txn->request.message, MAX_MESSAGE_SIZE, - 0); - txn->request.is_tcp_connect = 0; - if (txn->request.length == 0) { - /* - * Event on this socket indicated socket closure - */ - close(fd); - remove_elem(ctx->sessions, &tmp, session_comparator); - ctx->terminate_session(fd);/* mark this session as terminated */ - free(txn); - - printf("Detected socket closure\n"); - return; - } - enqueue(ctx->request_jobs, txn); - printf("\tcreated a new job on %d [%d bytes]\n", fd, - txn->request.length); + struct session tmp; + tmp.session_id = fd; + struct client_txn* txn; + int n; + + txn = (struct client_txn *) malloc(sizeof(struct client_txn)); + tmp = *(struct session *) get_elem(ctx->sessions, &tmp, + session_comparator); + txn->client_session = tmp; + txn->request.length = recv(fd, txn->request.message, MAX_MESSAGE_SIZE, + 0); + txn->request.is_tcp_connect = 0; + if (txn->request.length == 0) { + /* + * Event on this socket indicated socket closure + */ + close(fd); + remove_elem(ctx->sessions, &tmp, session_comparator); + ctx->terminate_session(fd);/* mark this session as terminated */ + free(txn); + + printf("Detected socket closure\n"); + return; + } + enqueue(ctx->request_jobs, txn); + printf("\tcreated a new job on %d [%d bytes]\n", fd, + txn->request.length); } int session_comparator(void *target, void *elem) { - int target_id; - int elem_id; + int target_id; + int elem_id; - target_id = ((struct session *) target)->session_id; - elem_id = ((struct session *) elem)->session_id; + target_id = ((struct session *) target)->session_id; + elem_id = ((struct session *) elem)->session_id; - return elem_id == target_id; + return elem_id == target_id; } int errExit(char *s) { - fprintf(stderr, "%s\n", s); - exit(-1); + fprintf(stderr, "%s\n", s); + exit(-1); } diff --git a/comm/src/comm.h b/comm/src/comm.h index 0a49c3e..0110837 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -26,40 +26,40 @@ struct client_endpoint { - struct sockaddr_in client; - int fd; + struct sockaddr_in client; + int fd; }; struct comm_message { - int is_tcp_connect; - char message[MAX_MESSAGE_SIZE]; - int length; + int is_tcp_connect; + char message[MAX_MESSAGE_SIZE]; + int length; }; struct session { - int session_id; - struct client_endpoint client_info; + int session_id; + struct client_endpoint client_info; }; struct client_txn { - struct session client_session; - struct comm_message request; - struct comm_message reply; + struct session client_session; + struct comm_message request; + struct comm_message reply; }; typedef void (*message_handler) (struct client_txn *); typedef int (*session_callback)(struct client_txn *); typedef void (*session_close)(int session_id); struct comm_context { - message_handler marshal_unmarshal; - session_callback cleanup_session; - session_close terminate_session; - struct queue_hdr *sessions; - struct queue_hdr *request_jobs; - struct queue_hdr *reply_jobs; - int maxfds; + message_handler marshal_unmarshal; + session_callback cleanup_session; + session_close terminate_session; + struct queue_hdr *sessions; + struct queue_hdr *request_jobs; + struct queue_hdr *reply_jobs; + int maxfds; }; - + struct comm_context* comm_context(); /* creates/returns comm_context struct */ void comm_listen(struct comm_context *); /* listens for messages */ #endif diff --git a/comm/src/worker.c b/comm/src/worker.c index 33bf90f..b930995 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -18,123 +18,123 @@ extern int session_comparator(void *target, void *elem); void create_worker_threads(int thread_pool_size) { - int i; - if (threads == NULL) { - threads = (pthread_t *)malloc((thread_pool_size+1)* - sizeof(pthread_t)); - for (i=0; irequest_jobs); - - if (job != NULL) { - - /* - * Make the up call - */ - + struct comm_context *ctx = (struct comm_context *)context; + struct client_txn *job; + while (1) { + + /* + * Get the next job in queue and make + * an upcall on XDR service. + */ + job = (struct client_txn *)dequeue(ctx->request_jobs); + + if (job != NULL) { + + /* + * Make the up call + */ + #ifdef DEBUG - if (job->request.is_tcp_connect != 1) { + if (job->request.is_tcp_connect != 1) { - printf("Request message: \n"); + printf("Request message: \n"); - hexdump(job->request.message, job->request.length); - } + hexdump(job->request.message, job->request.length); + } #endif - ctx->marshal_unmarshal(job); - printf("Processed a job \n"); - // Process next job - } - else { -// printf("Job Queue Empty: Will wait for job\n"); - pthread_yield(); // Let another thread run - } - } - return ctx; + ctx->marshal_unmarshal(job); + printf("Processed a job \n"); + // Process next job + } + else { +// printf("Job Queue Empty: Will wait for job\n"); + pthread_yield(); // Let another thread run + } + } + return ctx; } void *process_response(void *context) { - int write_result; - struct comm_context *ctx = (struct comm_context *)context; - struct client_txn *job; - struct session client_session; - while (1) { - - /* - * Process the next job in response queue and send - * response to client - */ - job = (struct client_txn *)dequeue(ctx->reply_jobs); - - if (job != NULL) { - // Write message to client - client_session = job->client_session; - if (get_elem(ctx->sessions, &client_session, - session_comparator) != NULL) { - /* session still valid */ - write_result = write_message(job); - if (write_result == -1) - printf("Write message error\n"); - } - free(job); - } - else - pthread_yield(); - - } - return ctx; + int write_result; + struct comm_context *ctx = (struct comm_context *)context; + struct client_txn *job; + struct session client_session; + while (1) { + + /* + * Process the next job in response queue and send + * response to client + */ + job = (struct client_txn *)dequeue(ctx->reply_jobs); + + if (job != NULL) { + // Write message to client + client_session = job->client_session; + if (get_elem(ctx->sessions, &client_session, + session_comparator) != NULL) { + /* session still valid */ + write_result = write_message(job); + if (write_result == -1) + printf("Write message error\n"); + } + free(job); + } + else + pthread_yield(); + + } + return ctx; } int write_message(struct client_txn *job) { - struct session tmp; - struct comm_message reply; - int fd, sent_bytes; - int len; - tmp = job->client_session; - reply = job->reply; - fd = tmp.session_id; - if (reply.length > 0) { + struct session tmp; + struct comm_message reply; + int fd, sent_bytes; + int len; + tmp = job->client_session; + reply = job->reply; + fd = tmp.session_id; + if (reply.length > 0) { #ifdef DEBUG - printf("Reply message:\n"); - hexdump(reply.message,reply.length); + printf("Reply message:\n"); + hexdump(reply.message,reply.length); #endif - sent_bytes = send(fd,reply.message,reply.length,0); - - printf("Sent a %d byte response to (%s,%d) on sock %d\n", - sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), - ntohs(tmp.client_info.client.sin_port), fd); - } - return -1 * (sent_bytes != reply.length); + sent_bytes = send(fd,reply.message,reply.length,0); + + printf("Sent a %d byte response to (%s,%d) on sock %d\n", + sent_bytes, inet_ntoa(tmp.client_info.client.sin_addr), + ntohs(tmp.client_info.client.sin_port), fd); + } + return -1 * (sent_bytes != reply.length); } diff --git a/ndmp/src/ndmp.x b/ndmp/src/ndmp.x index 700307c..7649c79 100644 --- a/ndmp/src/ndmp.x +++ b/ndmp/src/ndmp.x @@ -7,10 +7,10 @@ * cases as published by the Free Software Foundation. */ -/* -*- Mode: C -*- +/* -*- Mode: C -*- * ndmp.x * - * Description : NDMP protocol rpcgen file. + * Description : NDMP protocol rpcgen file. * * Copyright (c) 1999 Intelliguard Software, Network Appliance. All Rights Reserved. * @@ -24,135 +24,135 @@ const NDMPPORT = 10000; struct ndmp_u_quad { - u_long high; - u_long low; + u_long high; + u_long low; }; struct ndmp_pval { - string name<>; - string value<>; + string name<>; + string value<>; }; enum ndmp_error { - NDMP_NO_ERR, /* No error */ - NDMP_NOT_SUPPORTED_ERR, /* Call is not supported */ - NDMP_DEVICE_BUSY_ERR, /* The device is in use */ - NDMP_DEVICE_OPENED_ERR, /* Another tape or scsi device - *is already open */ - NDMP_NOT_AUTHORIZED_ERR, /* connection has not been authorized */ - NDMP_PERMISSION_ERR, /* some sort of permission problem */ - NDMP_DEV_NOT_OPEN_ERR, /* SCSI device is not open */ - NDMP_IO_ERR, /* I/O error */ - NDMP_TIMEOUT_ERR, /* command timed out */ - NDMP_ILLEGAL_ARGS_ERR, /* illegal arguments in request */ - NDMP_NO_TAPE_LOADED_ERR, /* Cannot open because there is - * no tape loaded */ - NDMP_WRITE_PROTECT_ERR, /* tape cannot be open for write */ - NDMP_EOF_ERR, /* Command encountered EOF */ - NDMP_EOM_ERR, /* Command encountered EOM */ - NDMP_FILE_NOT_FOUND_ERR, /* File not found during restore */ - NDMP_BAD_FILE_ERR, /* The file descriptor is invalid */ - NDMP_NO_DEVICE_ERR, /* The device is not at that target */ - NDMP_NO_BUS_ERR, /* Invalid controller */ - NDMP_XDR_DECODE_ERR, /* Can't decode the request argument */ - NDMP_ILLEGAL_STATE_ERR, /* Call can't be performed at this state */ - NDMP_UNDEFINED_ERR, /* Undefined Error */ - NDMP_XDR_ENCODE_ERR, /* Can't encode the reply argument */ - NDMP_NO_MEM_ERR, /* no memory */ - NDMP_CONNECT_ERR /* Error connecting to another NDMP server */ + NDMP_NO_ERR, /* No error */ + NDMP_NOT_SUPPORTED_ERR, /* Call is not supported */ + NDMP_DEVICE_BUSY_ERR, /* The device is in use */ + NDMP_DEVICE_OPENED_ERR, /* Another tape or scsi device + *is already open */ + NDMP_NOT_AUTHORIZED_ERR, /* connection has not been authorized */ + NDMP_PERMISSION_ERR, /* some sort of permission problem */ + NDMP_DEV_NOT_OPEN_ERR, /* SCSI device is not open */ + NDMP_IO_ERR, /* I/O error */ + NDMP_TIMEOUT_ERR, /* command timed out */ + NDMP_ILLEGAL_ARGS_ERR, /* illegal arguments in request */ + NDMP_NO_TAPE_LOADED_ERR, /* Cannot open because there is + * no tape loaded */ + NDMP_WRITE_PROTECT_ERR, /* tape cannot be open for write */ + NDMP_EOF_ERR, /* Command encountered EOF */ + NDMP_EOM_ERR, /* Command encountered EOM */ + NDMP_FILE_NOT_FOUND_ERR, /* File not found during restore */ + NDMP_BAD_FILE_ERR, /* The file descriptor is invalid */ + NDMP_NO_DEVICE_ERR, /* The device is not at that target */ + NDMP_NO_BUS_ERR, /* Invalid controller */ + NDMP_XDR_DECODE_ERR, /* Can't decode the request argument */ + NDMP_ILLEGAL_STATE_ERR, /* Call can't be performed at this state */ + NDMP_UNDEFINED_ERR, /* Undefined Error */ + NDMP_XDR_ENCODE_ERR, /* Can't encode the reply argument */ + NDMP_NO_MEM_ERR, /* no memory */ + NDMP_CONNECT_ERR /* Error connecting to another NDMP server */ }; enum ndmp_header_message_type { - NDMP_MESSAGE_REQUEST, - NDMP_MESSAGE_REPLY + NDMP_MESSAGE_REQUEST, + NDMP_MESSAGE_REPLY }; enum ndmp_message { - NDMP_CONNECT_OPEN = 0x900, /* CONNECT INTERFACE */ - NDMP_CONNECT_CLIENT_AUTH = 0x901, - NDMP_CONNECT_CLOSE = 0x902, - NDMP_CONNECT_SERVER_AUTH = 0x903, - - NDMP_CONFIG_GET_HOST_INFO = 0x100, /* CONFIG INTERFACE */ - NDMP_CONFIG_GET_CONNECTION_TYPE = 0x102, /* NDMP_CONFIG_GET_MOVER_TYPE on v2 */ - NDMP_CONFIG_GET_AUTH_ATTR = 0x103, - NDMP_CONFIG_GET_BUTYPE_INFO = 0x104, /* new from v3 */ - NDMP_CONFIG_GET_FS_INFO = 0x105, /* new from v3 */ - NDMP_CONFIG_GET_TAPE_INFO = 0x106, /* new from v3 */ - NDMP_CONFIG_GET_SCSI_INFO = 0x107, /* new from v3 */ - NDMP_CONFIG_GET_SERVER_INFO =0x108, /* new from v3 */ - - NDMP_SCSI_OPEN = 0x200, /* SCSI INTERFACE */ - NDMP_SCSI_CLOSE = 0x201, - NDMP_SCSI_GET_STATE = 0x202, - NDMP_SCSI_SET_TARGET = 0x203, - NDMP_SCSI_RESET_DEVICE = 0x204, - NDMP_SCSI_RESET_BUS = 0x205, - NDMP_SCSI_EXECUTE_CDB = 0x206, - - NDMP_TAPE_OPEN = 0x300, /* TAPE INTERFACE */ - NDMP_TAPE_CLOSE = 0x301, - NDMP_TAPE_GET_STATE = 0x302, - NDMP_TAPE_MTIO = 0x303, - NDMP_TAPE_WRITE = 0x304, - NDMP_TAPE_READ = 0x305, - NDMP_TAPE_EXECUTE_CDB = 0x307, - - NDMP_DATA_GET_STATE = 0x400, /* DATA INTERFACE */ - NDMP_DATA_START_BACKUP = 0x401, - NDMP_DATA_START_RECOVER = 0x402, - NDMP_DATA_ABORT = 0x403, - NDMP_DATA_GET_ENV = 0x404, - NDMP_DATA_STOP = 0x407, - NDMP_DATA_LISTEN = 0x409, /* new from V3 */ - NDMP_DATA_CONNECT = 0x40a, /* new from V3 */ - - NDMP_NOTIFY_DATA_HALTED =0x501, /* NOTIFY INTERFACE */ - NDMP_NOTIFY_CONNECTED = 0x502, - NDMP_NOTIFY_MOVER_HALTED = 0x503, - NDMP_NOTIFY_MOVER_PAUSED = 0x504, - NDMP_NOTIFY_DATA_READ =0x505, - - NDMP_LOG_FILE = 0x602, /* LOGGING INTERFACE */ - NDMP_LOG_MESSAGE = 0x603, /* new from v3 */ - - NDMP_FH_ADD_FILE = 0x703, /* FILE HISTORY INTERFACE */ - NDMP_FH_ADD_DIR = 0x704, - NDMP_FH_ADD_NODE = 0x705, - - NDMP_MOVER_GET_STATE = 0xa00, /* MOVER INTERFACE */ - NDMP_MOVER_LISTEN = 0xa01, - NDMP_MOVER_CONTINUE = 0xa02, - NDMP_MOVER_ABORT = 0xa03, - NDMP_MOVER_STOP = 0xa04, - NDMP_MOVER_SET_WINDOW = 0xa05, - NDMP_MOVER_READ = 0xa06, - NDMP_MOVER_CLOSE =0xa07, - NDMP_MOVER_SET_RECORD_SIZE =0xa08, - NDMP_MOVER_CONNECT =0xa09, /* new from V3 */ - - - NDMP_VENDORS_BASE = 0xf000, /* Reserved for the vendor - * specific usage - * from 0xf000 to 0xfeff */ - - NDMP_RESERVED_BASE = 0xff00 /* Reserved for prototyping - * from 0xff00 to 0xffff */ + NDMP_CONNECT_OPEN = 0x900, /* CONNECT INTERFACE */ + NDMP_CONNECT_CLIENT_AUTH = 0x901, + NDMP_CONNECT_CLOSE = 0x902, + NDMP_CONNECT_SERVER_AUTH = 0x903, + + NDMP_CONFIG_GET_HOST_INFO = 0x100, /* CONFIG INTERFACE */ + NDMP_CONFIG_GET_CONNECTION_TYPE = 0x102, /* NDMP_CONFIG_GET_MOVER_TYPE on v2 */ + NDMP_CONFIG_GET_AUTH_ATTR = 0x103, + NDMP_CONFIG_GET_BUTYPE_INFO = 0x104, /* new from v3 */ + NDMP_CONFIG_GET_FS_INFO = 0x105, /* new from v3 */ + NDMP_CONFIG_GET_TAPE_INFO = 0x106, /* new from v3 */ + NDMP_CONFIG_GET_SCSI_INFO = 0x107, /* new from v3 */ + NDMP_CONFIG_GET_SERVER_INFO =0x108, /* new from v3 */ + + NDMP_SCSI_OPEN = 0x200, /* SCSI INTERFACE */ + NDMP_SCSI_CLOSE = 0x201, + NDMP_SCSI_GET_STATE = 0x202, + NDMP_SCSI_SET_TARGET = 0x203, + NDMP_SCSI_RESET_DEVICE = 0x204, + NDMP_SCSI_RESET_BUS = 0x205, + NDMP_SCSI_EXECUTE_CDB = 0x206, + + NDMP_TAPE_OPEN = 0x300, /* TAPE INTERFACE */ + NDMP_TAPE_CLOSE = 0x301, + NDMP_TAPE_GET_STATE = 0x302, + NDMP_TAPE_MTIO = 0x303, + NDMP_TAPE_WRITE = 0x304, + NDMP_TAPE_READ = 0x305, + NDMP_TAPE_EXECUTE_CDB = 0x307, + + NDMP_DATA_GET_STATE = 0x400, /* DATA INTERFACE */ + NDMP_DATA_START_BACKUP = 0x401, + NDMP_DATA_START_RECOVER = 0x402, + NDMP_DATA_ABORT = 0x403, + NDMP_DATA_GET_ENV = 0x404, + NDMP_DATA_STOP = 0x407, + NDMP_DATA_LISTEN = 0x409, /* new from V3 */ + NDMP_DATA_CONNECT = 0x40a, /* new from V3 */ + + NDMP_NOTIFY_DATA_HALTED =0x501, /* NOTIFY INTERFACE */ + NDMP_NOTIFY_CONNECTED = 0x502, + NDMP_NOTIFY_MOVER_HALTED = 0x503, + NDMP_NOTIFY_MOVER_PAUSED = 0x504, + NDMP_NOTIFY_DATA_READ =0x505, + + NDMP_LOG_FILE = 0x602, /* LOGGING INTERFACE */ + NDMP_LOG_MESSAGE = 0x603, /* new from v3 */ + + NDMP_FH_ADD_FILE = 0x703, /* FILE HISTORY INTERFACE */ + NDMP_FH_ADD_DIR = 0x704, + NDMP_FH_ADD_NODE = 0x705, + + NDMP_MOVER_GET_STATE = 0xa00, /* MOVER INTERFACE */ + NDMP_MOVER_LISTEN = 0xa01, + NDMP_MOVER_CONTINUE = 0xa02, + NDMP_MOVER_ABORT = 0xa03, + NDMP_MOVER_STOP = 0xa04, + NDMP_MOVER_SET_WINDOW = 0xa05, + NDMP_MOVER_READ = 0xa06, + NDMP_MOVER_CLOSE =0xa07, + NDMP_MOVER_SET_RECORD_SIZE =0xa08, + NDMP_MOVER_CONNECT =0xa09, /* new from V3 */ + + + NDMP_VENDORS_BASE = 0xf000, /* Reserved for the vendor + * specific usage + * from 0xf000 to 0xfeff */ + + NDMP_RESERVED_BASE = 0xff00 /* Reserved for prototyping + * from 0xff00 to 0xffff */ }; struct ndmp_header { - u_long sequence; /* monotonically increasing number */ - u_long time_stamp; /* time stamp of message */ - ndmp_header_message_type message_type; /* what type of message */ - enum ndmp_message message; /* message number */ - u_long reply_sequence; /* reply is in response to */ - ndmp_error error; /* communications errors */ + u_long sequence; /* monotonically increasing number */ + u_long time_stamp; /* time stamp of message */ + ndmp_header_message_type message_type; /* what type of message */ + enum ndmp_message message; /* message number */ + u_long reply_sequence; /* reply is in response to */ + ndmp_error error; /* communications errors */ }; /**********************/ @@ -162,53 +162,53 @@ struct ndmp_header /* NDMP_CONNECT_OPEN */ struct ndmp_connect_open_request { - u_short protocol_version; /* the version of protocol supported */ + u_short protocol_version; /* the version of protocol supported */ }; struct ndmp_connect_open_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_CONNECT_CLIENT_AUTH */ enum ndmp_auth_type { - NDMP_AUTH_NONE, /* no password is required */ - NDMP_AUTH_TEXT, /* the clear text password */ - NDMP_AUTH_MD5 /* md5 */ + NDMP_AUTH_NONE, /* no password is required */ + NDMP_AUTH_TEXT, /* the clear text password */ + NDMP_AUTH_MD5 /* md5 */ }; struct ndmp_auth_text { - string auth_id<>; - string auth_password<>; + string auth_id<>; + string auth_password<>; }; struct ndmp_auth_md5 { - string auth_id<>; - opaque auth_digest[16]; + string auth_id<>; + opaque auth_digest[16]; }; union ndmp_auth_data switch (enum ndmp_auth_type auth_type) { - case NDMP_AUTH_NONE: - void; - case NDMP_AUTH_TEXT: - struct ndmp_auth_text auth_text; - case NDMP_AUTH_MD5: - struct ndmp_auth_md5 auth_md5; + case NDMP_AUTH_NONE: + void; + case NDMP_AUTH_TEXT: + struct ndmp_auth_text auth_text; + case NDMP_AUTH_MD5: + struct ndmp_auth_md5 auth_md5; }; struct ndmp_connect_client_auth_request { - ndmp_auth_data auth_data; + ndmp_auth_data auth_data; }; struct ndmp_connect_client_auth_reply { - ndmp_error error; + ndmp_error error; }; @@ -219,23 +219,23 @@ struct ndmp_connect_client_auth_reply /* NDMP_CONNECT_SERVER_AUTH */ union ndmp_auth_attr switch (enum ndmp_auth_type auth_type) { - case NDMP_AUTH_NONE: - void; - case NDMP_AUTH_TEXT: - void; - case NDMP_AUTH_MD5: - opaque challenge[64]; + case NDMP_AUTH_NONE: + void; + case NDMP_AUTH_TEXT: + void; + case NDMP_AUTH_MD5: + opaque challenge[64]; }; struct ndmp_connect_server_auth_request { - ndmp_auth_attr client_attr; + ndmp_auth_attr client_attr; }; struct ndmp_connect_server_auth_reply { - ndmp_error error; - ndmp_auth_data server_result; + ndmp_error error; + ndmp_auth_data server_result; }; @@ -247,133 +247,133 @@ struct ndmp_connect_server_auth_reply /* no request arguments */ struct ndmp_config_get_host_info_reply { - ndmp_error error; - string hostname<>; /* host name */ - string os_type<>; /* The operating system type (i.e. - * SOLARIS) */ - string os_vers<>; /* The version number of the OS (i.e. - * 2.5) */ - string hostid<>; + ndmp_error error; + string hostname<>; /* host name */ + string os_type<>; /* The operating system type (i.e. + * SOLARIS) */ + string os_vers<>; /* The version number of the OS (i.e. + * 2.5) */ + string hostid<>; }; enum ndmp_addr_type { - NDMP_ADDR_LOCAL, - NDMP_ADDR_TCP, - NDMP_ADDR_FC, - NDMP_ADDR_IPC + NDMP_ADDR_LOCAL, + NDMP_ADDR_TCP, + NDMP_ADDR_FC, + NDMP_ADDR_IPC }; /* NDMP_CONFIG_GET_CONNECTION_TYPE */ /* no request arguments */ struct ndmp_config_get_connection_type_reply { - ndmp_error error; - ndmp_addr_type addr_types<>; + ndmp_error error; + ndmp_addr_type addr_types<>; }; /* NDMP_CONFIG_GET_AUTH_ATTR */ struct ndmp_config_get_auth_attr_request { - ndmp_auth_type auth_type; + ndmp_auth_type auth_type; }; struct ndmp_config_get_auth_attr_reply { - ndmp_error error; - ndmp_auth_attr server_attr; + ndmp_error error; + ndmp_auth_attr server_attr; }; /* NDMP_CONFIG_GET_SERVER_INFO */ /* no requset arguments */ struct ndmp_config_get_server_info_reply { - ndmp_error error; - string vendor_name<>; - string product_name<>; - string revision_number<>; - ndmp_auth_type auth_type<>; + ndmp_error error; + string vendor_name<>; + string product_name<>; + string revision_number<>; + ndmp_auth_type auth_type<>; }; /* backup type attributes */ -const NDMP_BUTYPE_BACKUP_FILE_HISTORY = 0x0001; -const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; -const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; -const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; -const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; -const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; -const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; -const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; -const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; +const NDMP_BUTYPE_BACKUP_FILE_HISTORY = 0x0001; +const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; +const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; +const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; +const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; +const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; +const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; +const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; +const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; struct ndmp_butype_info { - string butype_name<>; - ndmp_pval default_env<>; - u_long attrs; + string butype_name<>; + ndmp_pval default_env<>; + u_long attrs; }; /* NDMP_CONFIG_GET_BUTYPE_INFO */ /* no request arguments */ struct ndmp_config_get_butype_info_reply { - ndmp_error error; - ndmp_butype_info butype_info<>; + ndmp_error error; + ndmp_butype_info butype_info<>; }; /* invalid bit */ -const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; -const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; -const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; -const NDMP_FS_INFO_TOTAL_INODES_INVALID = 0x00000008; -const NDMP_FS_INFO_USED_INODES_INVALID = 0x00000010; +const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; +const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; +const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; +const NDMP_FS_INFO_TOTAL_INODES_INVALID = 0x00000008; +const NDMP_FS_INFO_USED_INODES_INVALID = 0x00000010; struct ndmp_fs_info { - u_long invalid; - string fs_type<>; - string fs_logical_device<>; - string fs_physical_device<>; - ndmp_u_quad total_size; - ndmp_u_quad used_size; - ndmp_u_quad avail_size; - ndmp_u_quad total_inodes; - ndmp_u_quad used_inodes; - ndmp_pval fs_env<>; - string fs_status<>; + u_long invalid; + string fs_type<>; + string fs_logical_device<>; + string fs_physical_device<>; + ndmp_u_quad total_size; + ndmp_u_quad used_size; + ndmp_u_quad avail_size; + ndmp_u_quad total_inodes; + ndmp_u_quad used_inodes; + ndmp_pval fs_env<>; + string fs_status<>; }; /* NDMP_CONFIG_GET_FS_INFO */ /* no request arguments */ struct ndmp_config_get_fs_info_reply { - ndmp_error error; - ndmp_fs_info fs_info<>; + ndmp_error error; + ndmp_fs_info fs_info<>; }; /* NDMP_CONFIG_GET_TAPE_INFO */ /* no request arguments */ /* tape attributes */ -const NDMP_TAPE_ATTR_REWIND = 0x00000001; -const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; +const NDMP_TAPE_ATTR_REWIND = 0x00000001; +const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; struct ndmp_device_capability { - string device<>; - u_long attr; - ndmp_pval capability<>; + string device<>; + u_long attr; + ndmp_pval capability<>; }; struct ndmp_device_info { - string model<>; - ndmp_device_capability caplist<>; + string model<>; + ndmp_device_capability caplist<>; }; struct ndmp_config_get_tape_info_reply { - ndmp_error error; - ndmp_device_info tape_info<>; + ndmp_error error; + ndmp_device_info tape_info<>; }; @@ -381,8 +381,8 @@ struct ndmp_config_get_tape_info_reply /* jukebox attributes */ struct ndmp_config_get_scsi_info_reply { - ndmp_error error; - ndmp_device_info scsi_info<>; + ndmp_error error; + ndmp_device_info scsi_info<>; }; /******************/ @@ -392,79 +392,79 @@ struct ndmp_config_get_scsi_info_reply /* NDMP_SCSI_OPEN */ struct ndmp_scsi_open_request { - string device<>; + string device<>; }; struct ndmp_scsi_open_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_SCSI_CLOSE */ /* no request arguments */ struct ndmp_scsi_close_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_SCSI_GET_STATE */ /* no request arguments */ struct ndmp_scsi_get_state_reply { - ndmp_error error; - short target_controller; - short target_id; - short target_lun; + ndmp_error error; + short target_controller; + short target_id; + short target_lun; }; /* NDMP_SCSI_SET_TARGET */ struct ndmp_scsi_set_target_request { - string device<>; - u_short target_controller; - u_short target_id; - u_short target_lun; + string device<>; + u_short target_controller; + u_short target_id; + u_short target_lun; }; struct ndmp_scsi_set_target_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_SCSI_RESET_DEVICE */ /* no request arguments */ struct ndmp_scsi_reset_device_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_SCSI_RESET_BUS */ /* no request arguments */ struct ndmp_scsi_reset_bus_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_SCSI_EXECUTE_CDB */ -const NDMP_SCSI_DATA_IN = 0x00000001; /* Expect data from SCSI device */ -const NDMP_SCSI_DATA_OUT = 0x00000002; /* Transfer data to SCSI device */ +const NDMP_SCSI_DATA_IN = 0x00000001; /* Expect data from SCSI device */ +const NDMP_SCSI_DATA_OUT = 0x00000002; /* Transfer data to SCSI device */ struct ndmp_execute_cdb_request { - u_long flags; - u_long timeout; - u_long datain_len; /* Set for expected datain */ - opaque cdb<>; - opaque dataout<>; + u_long flags; + u_long timeout; + u_long datain_len; /* Set for expected datain */ + opaque cdb<>; + opaque dataout<>; }; struct ndmp_execute_cdb_reply { - ndmp_error error; - u_char status; /* SCSI status bytes */ - u_long dataout_len; - opaque datain<>; /* SCSI datain */ - opaque ext_sense<>; /* Extended sense data */ + ndmp_error error; + u_char status; /* SCSI status bytes */ + u_long dataout_len; + opaque datain<>; /* SCSI datain */ + opaque ext_sense<>; /* Extended sense data */ }; /******************/ @@ -473,111 +473,111 @@ struct ndmp_execute_cdb_reply /* NDMP_TAPE_OPEN */ enum ndmp_tape_open_mode { - NDMP_TAPE_READ_MODE, - NDMP_TAPE_RDWR_MODE + NDMP_TAPE_READ_MODE, + NDMP_TAPE_RDWR_MODE }; struct ndmp_tape_open_request { - string device<>; - ndmp_tape_open_mode mode; + string device<>; + ndmp_tape_open_mode mode; }; struct ndmp_tape_open_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_TAPE_CLOSE */ /* no request arguments */ struct ndmp_tape_close_reply { - ndmp_error error; + ndmp_error error; }; /*NDMP_TAPE_GET_STATE */ /* no request arguments */ -const NDMP_TAPE_STATE_NOREWIND = 0x0008; /* non-rewind device */ -const NDMP_TAPE_STATE_WR_PROT = 0x0010; /* write-protected */ -const NDMP_TAPE_STATE_ERROR = 0x0020; /* media error */ -const NDMP_TAPE_STATE_UNLOAD = 0x0040; /* tape will be unloaded when - * the device is closed */ +const NDMP_TAPE_STATE_NOREWIND = 0x0008; /* non-rewind device */ +const NDMP_TAPE_STATE_WR_PROT = 0x0010; /* write-protected */ +const NDMP_TAPE_STATE_ERROR = 0x0020; /* media error */ +const NDMP_TAPE_STATE_UNLOAD = 0x0040; /* tape will be unloaded when + * the device is closed */ /* invalid bit */ -const NDMP_TAPE_STATE_FILE_NUM_INVALID = 0x00000001; -const NDMP_TAPE_STATE_SOFT_ERRORS_INVALID = 0x00000002; -const NDMP_TAPE_STATE_BLOCK_SIZE_INVALID = 0x00000004; -const NDMP_TAPE_STATE_BLOCKNO_INVALID = 0x00000008; -const NDMP_TAPE_STATE_TOTAL_SPACE_INVALID = 0x00000010; -const NDMP_TAPE_STATE_SPACE_REMAIN_INVALID = 0x00000020; -const NDMP_TAPE_STATE_PARTITION_INVALID = 0x00000040; +const NDMP_TAPE_STATE_FILE_NUM_INVALID = 0x00000001; +const NDMP_TAPE_STATE_SOFT_ERRORS_INVALID = 0x00000002; +const NDMP_TAPE_STATE_BLOCK_SIZE_INVALID = 0x00000004; +const NDMP_TAPE_STATE_BLOCKNO_INVALID = 0x00000008; +const NDMP_TAPE_STATE_TOTAL_SPACE_INVALID = 0x00000010; +const NDMP_TAPE_STATE_SPACE_REMAIN_INVALID = 0x00000020; +const NDMP_TAPE_STATE_PARTITION_INVALID = 0x00000040; struct ndmp_tape_get_state_reply { - u_long invalid; - ndmp_error error; - u_long flags; - u_long file_num; - u_long soft_errors; - u_long block_size; - u_long blockno; - ndmp_u_quad total_space; - ndmp_u_quad space_remain; - u_long partition; + u_long invalid; + ndmp_error error; + u_long flags; + u_long file_num; + u_long soft_errors; + u_long block_size; + u_long blockno; + ndmp_u_quad total_space; + ndmp_u_quad space_remain; + u_long partition; }; /* NDMP_TAPE_MTIO */ enum ndmp_tape_mtio_op { - NDMP_MTIO_FSF, - NDMP_MTIO_BSF, - NDMP_MTIO_FSR, - NDMP_MTIO_BSR, - NDMP_MTIO_REW, - NDMP_MTIO_EOF, - NDMP_MTIO_OFF + NDMP_MTIO_FSF, + NDMP_MTIO_BSF, + NDMP_MTIO_FSR, + NDMP_MTIO_BSR, + NDMP_MTIO_REW, + NDMP_MTIO_EOF, + NDMP_MTIO_OFF }; struct ndmp_tape_mtio_request { - ndmp_tape_mtio_op tape_op; - u_long count; + ndmp_tape_mtio_op tape_op; + u_long count; }; struct ndmp_tape_mtio_reply { - ndmp_error error; - u_long resid_count; + ndmp_error error; + u_long resid_count; }; /* NDMP_TAPE_WRITE */ struct ndmp_tape_write_request { - opaque data_out<>; + opaque data_out<>; }; struct ndmp_tape_write_reply { - ndmp_error error; - u_long count; + ndmp_error error; + u_long count; }; /* NDMP_TAPE_READ */ struct ndmp_tape_read_request { - u_long count; + u_long count; }; struct ndmp_tape_read_reply { - ndmp_error error; - opaque data_in<>; + ndmp_error error; + opaque data_in<>; }; /* NDMP_TAPE_EXECUTE_CDB */ -typedef ndmp_execute_cdb_request ndmp_tape_execute_cdb_request; -typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; +typedef ndmp_execute_cdb_request ndmp_tape_execute_cdb_request; +typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; /********************************/ @@ -586,136 +586,136 @@ typedef ndmp_execute_cdb_reply ndmp_tape_execute_cdb_reply; /* NDMP_MOVER_GET_STATE */ enum ndmp_mover_state { - NDMP_MOVER_STATE_IDLE, - NDMP_MOVER_STATE_LISTEN, - NDMP_MOVER_STATE_ACTIVE, - NDMP_MOVER_STATE_PAUSED, - NDMP_MOVER_STATE_HALTED + NDMP_MOVER_STATE_IDLE, + NDMP_MOVER_STATE_LISTEN, + NDMP_MOVER_STATE_ACTIVE, + NDMP_MOVER_STATE_PAUSED, + NDMP_MOVER_STATE_HALTED }; enum ndmp_mover_pause_reason { - NDMP_MOVER_PAUSE_NA, - NDMP_MOVER_PAUSE_EOM, - NDMP_MOVER_PAUSE_EOF, - NDMP_MOVER_PAUSE_SEEK, - NDMP_MOVER_PAUSE_MEDIA_ERROR, - NDMP_MOVER_PAUSE_EOW + NDMP_MOVER_PAUSE_NA, + NDMP_MOVER_PAUSE_EOM, + NDMP_MOVER_PAUSE_EOF, + NDMP_MOVER_PAUSE_SEEK, + NDMP_MOVER_PAUSE_MEDIA_ERROR, + NDMP_MOVER_PAUSE_EOW }; enum ndmp_mover_halt_reason { - NDMP_MOVER_HALT_NA, - NDMP_MOVER_HALT_CONNECT_CLOSED, - NDMP_MOVER_HALT_ABORTED, - NDMP_MOVER_HALT_INTERNAL_ERROR, - NDMP_MOVER_HALT_CONNECT_ERROR + NDMP_MOVER_HALT_NA, + NDMP_MOVER_HALT_CONNECT_CLOSED, + NDMP_MOVER_HALT_ABORTED, + NDMP_MOVER_HALT_INTERNAL_ERROR, + NDMP_MOVER_HALT_CONNECT_ERROR }; /* mover address */ enum ndmp_mover_mode { - NDMP_MOVER_MODE_READ, /* read from data connection; write to tape */ - NDMP_MOVER_MODE_WRITE /* write to data connection; read from tape */ + NDMP_MOVER_MODE_READ, /* read from data connection; write to tape */ + NDMP_MOVER_MODE_WRITE /* write to data connection; read from tape */ }; struct ndmp_tcp_addr { - u_long ip_addr; - u_short port; + u_long ip_addr; + u_short port; }; struct ndmp_fc_addr { - u_long loop_id; + u_long loop_id; }; struct ndmp_ipc_addr { - opaque comm_data<>; + opaque comm_data<>; }; union ndmp_addr switch (ndmp_addr_type addr_type) { - case NDMP_ADDR_LOCAL: - void; - case NDMP_ADDR_TCP: - ndmp_tcp_addr tcp_addr; - case NDMP_ADDR_FC: - ndmp_fc_addr fc_addr; - case NDMP_ADDR_IPC: - ndmp_ipc_addr ipc_addr; - + case NDMP_ADDR_LOCAL: + void; + case NDMP_ADDR_TCP: + ndmp_tcp_addr tcp_addr; + case NDMP_ADDR_FC: + ndmp_fc_addr fc_addr; + case NDMP_ADDR_IPC: + ndmp_ipc_addr ipc_addr; + }; /* no request arguments */ struct ndmp_mover_get_state_reply { - ndmp_error error; - ndmp_mover_state state; - ndmp_mover_pause_reason pause_reason; - ndmp_mover_halt_reason halt_reason; - u_long record_size; - u_long record_num; - ndmp_u_quad data_written; - ndmp_u_quad seek_position; - ndmp_u_quad bytes_left_to_read; - ndmp_u_quad window_offset; - ndmp_u_quad window_length; - ndmp_addr data_connection_addr; + ndmp_error error; + ndmp_mover_state state; + ndmp_mover_pause_reason pause_reason; + ndmp_mover_halt_reason halt_reason; + u_long record_size; + u_long record_num; + ndmp_u_quad data_written; + ndmp_u_quad seek_position; + ndmp_u_quad bytes_left_to_read; + ndmp_u_quad window_offset; + ndmp_u_quad window_length; + ndmp_addr data_connection_addr; }; /* NDMP_MOVER_LISTEN */ struct ndmp_mover_listen_request { - ndmp_mover_mode mode; - ndmp_addr_type addr_type; + ndmp_mover_mode mode; + ndmp_addr_type addr_type; }; struct ndmp_mover_listen_reply { - ndmp_error error; - ndmp_addr data_connection_addr; + ndmp_error error; + ndmp_addr data_connection_addr; }; /* NDMP_MOVER_CONNECT */ struct ndmp_mover_connect_request { - ndmp_mover_mode mode; - ndmp_addr addr; + ndmp_mover_mode mode; + ndmp_addr addr; }; struct ndmp_mover_connect_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_SET_RECORD_SIZE */ struct ndmp_mover_set_record_size_request { - u_long len; + u_long len; }; struct ndmp_mover_set_record_size_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_SET_WINDOW */ struct ndmp_mover_set_window_request { - ndmp_u_quad offset; - ndmp_u_quad length; + ndmp_u_quad offset; + ndmp_u_quad length; }; struct ndmp_mover_set_window_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_CONTINUE */ /* no request arguments */ struct ndmp_mover_continue_reply { - ndmp_error error; + ndmp_error error; }; @@ -723,316 +723,316 @@ struct ndmp_mover_continue_reply /* no request arguments */ struct ndmp_mover_abort_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_STOP */ /* no request arguments */ struct ndmp_mover_stop_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_READ */ struct ndmp_mover_read_request { - ndmp_u_quad offset; - ndmp_u_quad length; + ndmp_u_quad offset; + ndmp_u_quad length; }; struct ndmp_mover_read_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_MOVER_CLOSE */ /* no request arguments */ struct ndmp_mover_close_reply { - ndmp_error error; + ndmp_error error; }; /********************************/ -/* DATA INTERFACE */ +/* DATA INTERFACE */ /********************************/ /* NDMP_DATA_GET_STATE */ /* no request arguments */ enum ndmp_data_operation { - NDMP_DATA_OP_NOACTION, - NDMP_DATA_OP_BACKUP, - NDMP_DATA_OP_RESTORE + NDMP_DATA_OP_NOACTION, + NDMP_DATA_OP_BACKUP, + NDMP_DATA_OP_RESTORE }; enum ndmp_data_state { - NDMP_DATA_STATE_IDLE, - NDMP_DATA_STATE_ACTIVE, - NDMP_DATA_STATE_HALTED, - NDMP_DATA_STATE_LISTEN, - NDMP_DATA_STATE_CONNECTED + NDMP_DATA_STATE_IDLE, + NDMP_DATA_STATE_ACTIVE, + NDMP_DATA_STATE_HALTED, + NDMP_DATA_STATE_LISTEN, + NDMP_DATA_STATE_CONNECTED }; enum ndmp_data_halt_reason { - NDMP_DATA_HALT_NA, - NDMP_DATA_HALT_SUCCESSFUL, - NDMP_DATA_HALT_ABORTED, - NDMP_DATA_HALT_INTERNAL_ERROR, - NDMP_DATA_HALT_CONNECT_ERROR + NDMP_DATA_HALT_NA, + NDMP_DATA_HALT_SUCCESSFUL, + NDMP_DATA_HALT_ABORTED, + NDMP_DATA_HALT_INTERNAL_ERROR, + NDMP_DATA_HALT_CONNECT_ERROR }; /* invalid bit */ -const NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID = 0x00000001; -const NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID = 0x00000002; +const NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID = 0x00000001; +const NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID = 0x00000002; struct ndmp_data_get_state_reply { - u_long invalid; - ndmp_error error; - ndmp_data_operation operation; - ndmp_data_state state; - ndmp_data_halt_reason halt_reason; - ndmp_u_quad bytes_processed; - ndmp_u_quad est_bytes_remain; - u_long est_time_remain; - ndmp_addr data_connection_addr; - ndmp_u_quad read_offset; - ndmp_u_quad read_length; + u_long invalid; + ndmp_error error; + ndmp_data_operation operation; + ndmp_data_state state; + ndmp_data_halt_reason halt_reason; + ndmp_u_quad bytes_processed; + ndmp_u_quad est_bytes_remain; + u_long est_time_remain; + ndmp_addr data_connection_addr; + ndmp_u_quad read_offset; + ndmp_u_quad read_length; }; /* NDMP_DATA_START_BACKUP */ struct ndmp_data_start_backup_request { - string bu_type<>; /* backup method to use */ - ndmp_pval env<>; /* Parameters that may modify backup */ + string bu_type<>; /* backup method to use */ + ndmp_pval env<>; /* Parameters that may modify backup */ }; struct ndmp_data_start_backup_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_DATA_START_RECOVER */ struct ndmp_name { - string original_path<>; - string destination_dir<>; - string new_name<>; /* Direct access restore only */ - string other_name<>; /* Direct access restore only */ - ndmp_u_quad node; /* Direct access restore only */ - ndmp_u_quad fh_info; /* Direct access restore only */ + string original_path<>; + string destination_dir<>; + string new_name<>; /* Direct access restore only */ + string other_name<>; /* Direct access restore only */ + ndmp_u_quad node; /* Direct access restore only */ + ndmp_u_quad fh_info; /* Direct access restore only */ }; struct ndmp_data_start_recover_request { - ndmp_pval env<>; - ndmp_name nlist<>; - string bu_type<>; + ndmp_pval env<>; + ndmp_name nlist<>; + string bu_type<>; }; struct ndmp_data_start_recover_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_DATA_ABORT */ /* no request arguments */ struct ndmp_data_abort_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_DATA_STOP */ /* no request arguments */ struct ndmp_data_stop_reply { - ndmp_error error; + ndmp_error error; }; /* NDMP_DATA_GET_ENV */ /* no request arguments */ struct ndmp_data_get_env_reply { - ndmp_error error; - ndmp_pval env<>; + ndmp_error error; + ndmp_pval env<>; }; /* NDMP_DATA_LISTEN */ struct ndmp_data_listen_request { - ndmp_addr_type addr_type; + ndmp_addr_type addr_type; }; struct ndmp_data_listen_reply { - ndmp_error error; - ndmp_addr data_connection_addr; + ndmp_error error; + ndmp_addr data_connection_addr; }; /* NDMP_DATA_CONNECT */ struct ndmp_data_connect_request { - ndmp_addr addr; + ndmp_addr addr; }; struct ndmp_data_connect_reply { - ndmp_error error; + ndmp_error error; }; /****************************************/ -/* NOTIFY INTERFACE */ +/* NOTIFY INTERFACE */ /****************************************/ /* NDMP_NOTIFY_DATA_HALTED */ struct ndmp_notify_data_halted_request { - ndmp_data_halt_reason reason; - string text_reason<>; + ndmp_data_halt_reason reason; + string text_reason<>; }; /* NDMP_NOTIFY_CONNECTED */ enum ndmp_connect_reason { - NDMP_CONNECTED, /* Connect sucessfully */ - NDMP_SHUTDOWN, /* Connection shutdown */ - NDMP_REFUSED /* reach the maximum number of connections */ + NDMP_CONNECTED, /* Connect sucessfully */ + NDMP_SHUTDOWN, /* Connection shutdown */ + NDMP_REFUSED /* reach the maximum number of connections */ }; struct ndmp_notify_connected_request { - ndmp_connect_reason reason; - u_short protocol_version; - string text_reason<>; + ndmp_connect_reason reason; + u_short protocol_version; + string text_reason<>; }; /* NDMP_NOTIFY_MOVER_PAUSED */ struct ndmp_notify_mover_paused_request { - ndmp_mover_pause_reason reason; - ndmp_u_quad seek_position; + ndmp_mover_pause_reason reason; + ndmp_u_quad seek_position; }; /* No reply */ /* NDMP_NOTIFY_MOVER_HALTED */ struct ndmp_notify_mover_halted_request { - ndmp_mover_halt_reason reason; - string text_reason<>; + ndmp_mover_halt_reason reason; + string text_reason<>; }; /* No reply */ /* NDMP_NOTIFY_DATA_READ */ struct ndmp_notify_data_read_request { - ndmp_u_quad offset; - ndmp_u_quad length; + ndmp_u_quad offset; + ndmp_u_quad length; }; /* No reply */ /********************************/ -/* LOG INTERFACE */ +/* LOG INTERFACE */ /********************************/ /* NDMP_LOG_MESSAGE */ enum ndmp_log_type { - NDMP_LOG_NORMAL, - NDMP_LOG_DEBUG, - NDMP_LOG_ERROR, - NDMP_LOG_WARNING + NDMP_LOG_NORMAL, + NDMP_LOG_DEBUG, + NDMP_LOG_ERROR, + NDMP_LOG_WARNING }; struct ndmp_log_message_request { - ndmp_log_type log_type; - u_long message_id; - string entry<>; + ndmp_log_type log_type; + u_long message_id; + string entry<>; }; /* No reply */ /* NDMP_LOG_FILE */ struct ndmp_log_file_request { - string name<>; - ndmp_error error; + string name<>; + ndmp_error error; }; /* No reply */ /********************************/ -/* File History INTERFACE */ +/* File History INTERFACE */ /********************************/ /* NDMP_FH_ADD_FILE */ enum ndmp_fs_type { - NDMP_FS_UNIX, /* UNIX */ - NDMP_FS_NT, /* NT */ - NDMP_FS_OTHER + NDMP_FS_UNIX, /* UNIX */ + NDMP_FS_NT, /* NT */ + NDMP_FS_OTHER }; typedef string ndmp_path<>; struct ndmp_nt_path { - ndmp_path nt_path; - ndmp_path dos_path; + ndmp_path nt_path; + ndmp_path dos_path; }; union ndmp_file_name switch (ndmp_fs_type fs_type) { - case NDMP_FS_UNIX: - ndmp_path unix_name; - case NDMP_FS_NT: - ndmp_nt_path nt_name; - default: - ndmp_path other_name; + case NDMP_FS_UNIX: + ndmp_path unix_name; + case NDMP_FS_NT: + ndmp_nt_path nt_name; + default: + ndmp_path other_name; }; enum ndmp_file_type { - NDMP_FILE_DIR, - NDMP_FILE_FIFO, - NDMP_FILE_CSPEC, - NDMP_FILE_BSPEC, - NDMP_FILE_REG, - NDMP_FILE_SLINK, - NDMP_FILE_SOCK, - NDMP_FILE_REGISTRY, - NDMP_FILE_OTHER + NDMP_FILE_DIR, + NDMP_FILE_FIFO, + NDMP_FILE_CSPEC, + NDMP_FILE_BSPEC, + NDMP_FILE_REG, + NDMP_FILE_SLINK, + NDMP_FILE_SOCK, + NDMP_FILE_REGISTRY, + NDMP_FILE_OTHER }; /* invalid bit */ -const NDMP_FILE_STAT_ATIME_INVALID = 0x00000001; -const NDMP_FILE_STAT_CTIME_INVALID = 0x00000002; -const NDMP_FILE_STAT_GROUP_INVALID = 0x00000004; +const NDMP_FILE_STAT_ATIME_INVALID = 0x00000001; +const NDMP_FILE_STAT_CTIME_INVALID = 0x00000002; +const NDMP_FILE_STAT_GROUP_INVALID = 0x00000004; struct ndmp_file_stat { - u_long invalid; - ndmp_fs_type fs_type; - ndmp_file_type ftype; - u_long mtime; - u_long atime; - u_long ctime; - u_long owner; /* uid for UNIX, owner for NT */ - u_long group; /* gid for UNIX, NA for NT */ - u_long fattr; /* mode for UNIX, fattr for NT */ - ndmp_u_quad size; - u_long links; + u_long invalid; + ndmp_fs_type fs_type; + ndmp_file_type ftype; + u_long mtime; + u_long atime; + u_long ctime; + u_long owner; /* uid for UNIX, owner for NT */ + u_long group; /* gid for UNIX, NA for NT */ + u_long fattr; /* mode for UNIX, fattr for NT */ + ndmp_u_quad size; + u_long links; }; /* one file could have both UNIX and NT name and attributes */ struct ndmp_file { - ndmp_file_name names<>; - ndmp_file_stat stats<>; - ndmp_u_quad node; /* used for the direct access */ - ndmp_u_quad fh_info; /* used for the direct access */ + ndmp_file_name names<>; + ndmp_file_stat stats<>; + ndmp_u_quad node; /* used for the direct access */ + ndmp_u_quad fh_info; /* used for the direct access */ }; struct ndmp_fh_add_file_request { - ndmp_file files<>; + ndmp_file files<>; }; /* No reply */ @@ -1040,28 +1040,28 @@ struct ndmp_fh_add_file_request struct ndmp_dir { - ndmp_file_name names<>; - ndmp_u_quad node; - ndmp_u_quad parent; + ndmp_file_name names<>; + ndmp_u_quad node; + ndmp_u_quad parent; }; struct ndmp_fh_add_dir_request { - ndmp_dir dirs<>; + ndmp_dir dirs<>; }; /* No reply */ /* NDMP_FH_ADD_NODE */ struct ndmp_node { - ndmp_file_stat stats<>; - ndmp_u_quad node; - ndmp_u_quad fh_info; + ndmp_file_stat stats<>; + ndmp_u_quad node; + ndmp_u_quad fh_info; }; struct ndmp_fh_add_node_request { - ndmp_node nodes<>; + ndmp_node nodes<>; }; /* No reply */ diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c index 6dc6170..7a9e911 100644 --- a/ndmp/src/ndmp_config.c +++ b/ndmp/src/ndmp_config.c @@ -44,421 +44,421 @@ static char *fs_mount = "/"; /* change later */ */ void ndmp_config_get_host_info(struct client_txn *txn, - struct ndmp_header header, XDR* request_stream) + struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONFIG_GET_HOST_INFO - * - * no request arguments - * - * struct ndmp_config_get_host_info_reply - * { - * ndmp_error error; - * string hostname<>; - * string os_type<>; - * string os_vers<>; - * string hostid<>; - * }; - */ - - struct ndmp_header reply_header; - struct ndmp_config_get_host_info_reply reply; - char hostname[32]; - struct utsname os_info; - XDR reply_stream; - - reply.error = NDMP_NO_ERR; - - if (gethostname(hostname,32) != -1) - reply.hostname = hostname; - else - reply.error = NDMP_NOT_SUPPORTED_ERR; - - if (uname(&os_info) != -1){ - reply.os_type = os_info.sysname; - reply.os_vers = os_info.version; - } - else - reply.error = NDMP_NOT_SUPPORTED_ERR; - - reply.hostid = "1"; - - set_header(header, &reply_header, reply.error); - + /* NDMP_CONFIG_GET_HOST_INFO + * + * no request arguments + * + * struct ndmp_config_get_host_info_reply + * { + * ndmp_error error; + * string hostname<>; + * string os_type<>; + * string os_vers<>; + * string hostid<>; + * }; + */ + + struct ndmp_header reply_header; + struct ndmp_config_get_host_info_reply reply; + char hostname[32]; + struct utsname os_info; + XDR reply_stream; + + reply.error = NDMP_NO_ERR; + + if (gethostname(hostname,32) != -1) + reply.hostname = hostname; + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + + if (uname(&os_info) != -1){ + reply.os_type = os_info.sysname; + reply.os_vers = os_info.version; + } + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + + reply.hostid = "1"; + + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_host_info_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); if (reply.error == NDMP_NO_ERR) { xdr_ndmp_config_get_host_info_reply(&reply_stream, &reply); } else txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_host_info_reply, &reply); + xdr_ndmp_config_get_host_info_reply, &reply); } void ndmp_config_get_connection_type(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONFIG_GET_CONNECTION_TYPE - * - * no request arguments - * - * enum ndmp_addr_type - * { - * NDMP_ADDR_LOCAL, - * NDMP_ADDR_TCP, - * NDMP_ADDR_FC, - * NDMP_ADDR_IPC - * }; - * - * struct ndmp_config_get_connection_type_reply - * { - * ndmp_error error; - * ndmp_addr_type addr_types<>; - * }; - * - */ - - struct ndmp_header reply_header; - struct ndmp_config_get_connection_type_reply reply; - enum ndmp_addr_type addr_types[2] = {NDMP_ADDR_LOCAL, NDMP_ADDR_TCP}; - XDR reply_stream; - - reply.addr_types.addr_types_len = 2; - reply.addr_types.addr_types_val = addr_types; - reply.error = NDMP_NO_ERR; - - set_header(header, &reply_header, reply.error); - + /* NDMP_CONFIG_GET_CONNECTION_TYPE + * + * no request arguments + * + * enum ndmp_addr_type + * { + * NDMP_ADDR_LOCAL, + * NDMP_ADDR_TCP, + * NDMP_ADDR_FC, + * NDMP_ADDR_IPC + * }; + * + * struct ndmp_config_get_connection_type_reply + * { + * ndmp_error error; + * ndmp_addr_type addr_types<>; + * }; + * + */ + + struct ndmp_header reply_header; + struct ndmp_config_get_connection_type_reply reply; + enum ndmp_addr_type addr_types[2] = {NDMP_ADDR_LOCAL, NDMP_ADDR_TCP}; + XDR reply_stream; + + reply.addr_types.addr_types_len = 2; + reply.addr_types.addr_types_val = addr_types; + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_connection_type_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); if (reply.error == NDMP_NO_ERR) { xdr_ndmp_config_get_connection_type_reply(&reply_stream, &reply); } else txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_connection_type_reply, - &reply); + xdr_ndmp_config_get_connection_type_reply, + &reply); } void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* /* NDMP_CONFIG_GET_AUTH_ATTR - * - * struct ndmp_config_get_auth_attr_request - * { - * ndmp_auth_type auth_type; - * }; - * - * struct ndmp_config_get_auth_attr_reply - * { - * ndmp_error error; - * ndmp_auth_attr server_attr; - * }; - */ - - struct ndmp_header reply_header; - struct ndmp_config_get_auth_attr_request request; - struct ndmp_config_get_auth_attr_reply reply; - XDR reply_stream; - - - xdr_ndmp_config_get_auth_attr_request(request_stream, &request); - - switch (request.auth_type) { - case NDMP_AUTH_NONE: - reply.server_attr.auth_type = NDMP_AUTH_NONE; - strcpy(reply.server_attr.ndmp_auth_attr_u.challenge, - ""); /* No challenge */ - reply.error = NDMP_NO_ERR; - break; - case NDMP_AUTH_TEXT: - case NDMP_AUTH_MD5: - default: - reply.error = NDMP_NOT_SUPPORTED_ERR; - } - - set_header(header, &reply_header, reply.error); - + /* /* NDMP_CONFIG_GET_AUTH_ATTR + * + * struct ndmp_config_get_auth_attr_request + * { + * ndmp_auth_type auth_type; + * }; + * + * struct ndmp_config_get_auth_attr_reply + * { + * ndmp_error error; + * ndmp_auth_attr server_attr; + * }; + */ + + struct ndmp_header reply_header; + struct ndmp_config_get_auth_attr_request request; + struct ndmp_config_get_auth_attr_reply reply; + XDR reply_stream; + + + xdr_ndmp_config_get_auth_attr_request(request_stream, &request); + + switch (request.auth_type) { + case NDMP_AUTH_NONE: + reply.server_attr.auth_type = NDMP_AUTH_NONE; + strcpy(reply.server_attr.ndmp_auth_attr_u.challenge, + ""); /* No challenge */ + reply.error = NDMP_NO_ERR; + break; + case NDMP_AUTH_TEXT: + case NDMP_AUTH_MD5: + default: + reply.error = NDMP_NOT_SUPPORTED_ERR; + } + + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_auth_attr_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); if (reply.error == NDMP_NO_ERR) { xdr_ndmp_config_get_auth_attr_reply(&reply_stream, &reply); } else txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_auth_attr_reply, - &reply); + xdr_ndmp_config_get_auth_attr_reply, + &reply); } void ndmp_config_get_butype_info(struct client_txn *txn, - struct ndmp_header header, XDR* request_stream) + struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONFIG_GET_BUTYPE_INFO - * - * No request arguments - * - * backup type attributes - * const NDMP_BTYPE_BACKUP_FILE_HISTORY = 0x0001; - * const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; - * const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; - * const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; - * const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; - * const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; - * const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; - * const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; - * const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; - * - * struct ndmp_butype_info - * { - * string butype_name <>; - * ndmp_pval default_env <>; - * u_long attrs; - * }; - * struct ndmp_config_get_butype_attr_reply - * { - * ndmp_error error; - * ndmp_butype_info butype_info <>; - * }; - */ - - struct ndmp_config_get_butype_info_reply reply; - struct ndmp_butype_info *bu_type_info; - ndmp_header reply_header; - XDR reply_stream; - int i; - int bu_types[] = {NDMP_BUTYPE_BACKUP_FILELIST, NDMP_BUTYPE_BACKUP_DIRECT, - NDMP_BUTYPE_BACKUP_INCREMENTAL, NDMP_BUTYPE_BACKUP_UTF8}; - int num_attrs = 4; - reply.error = NDMP_NO_ERR; - reply.butype_info.butype_info_len = 3*num_attrs; - bu_type_info = (struct ndmp_butype_info *) - malloc(reply.butype_info.butype_info_len*sizeof(struct ndmp_butype_info)); + /* NDMP_CONFIG_GET_BUTYPE_INFO + * + * No request arguments + * + * backup type attributes + * const NDMP_BTYPE_BACKUP_FILE_HISTORY = 0x0001; + * const NDMP_BUTYPE_BACKUP_FILELIST = 0x0002; + * const NDMP_BUTYPE_RECOVER_FILELIST = 0x0004; + * const NDMP_BUTYPE_BACKUP_DIRECT = 0x0008; + * const NDMP_BUTYPE_RECOVER_DIRECT = 0x0010; + * const NDMP_BUTYPE_BACKUP_INCREMENTAL = 0x0020; + * const NDMP_BUTYPE_RECOVER_INCREMENTAL = 0x0040; + * const NDMP_BUTYPE_BACKUP_UTF8 = 0x0080; + * const NDMP_BUTYPE_RECOVER_UTF8 = 0x0100; + * + * struct ndmp_butype_info + * { + * string butype_name <>; + * ndmp_pval default_env <>; + * u_long attrs; + * }; + * struct ndmp_config_get_butype_attr_reply + * { + * ndmp_error error; + * ndmp_butype_info butype_info <>; + * }; + */ + + struct ndmp_config_get_butype_info_reply reply; + struct ndmp_butype_info *bu_type_info; + ndmp_header reply_header; + XDR reply_stream; + int i; + int bu_types[] = {NDMP_BUTYPE_BACKUP_FILELIST, NDMP_BUTYPE_BACKUP_DIRECT, + NDMP_BUTYPE_BACKUP_INCREMENTAL, NDMP_BUTYPE_BACKUP_UTF8}; + int num_attrs = 4; + reply.error = NDMP_NO_ERR; + reply.butype_info.butype_info_len = 3*num_attrs; + bu_type_info = (struct ndmp_butype_info *) + malloc(reply.butype_info.butype_info_len*sizeof(struct ndmp_butype_info)); - for (i=0; i<3*num_attrs; i+=3) { - bu_type_info[i].butype_name = "dump"; - bu_type_info[i].attrs = bu_types[i/3]; - bu_type_info[i].default_env.default_env_len = 0; - bu_type_info[i+1].butype_name = "tar"; - bu_type_info[i+1].attrs = bu_types[i/3]; - bu_type_info[i+1].default_env.default_env_len = 0; - bu_type_info[i+2].butype_name = "cpio"; - bu_type_info[i+2].attrs = bu_types[i/3]; - bu_type_info[i+2].default_env.default_env_len = 0; - } - reply.butype_info.butype_info_val = bu_type_info; - set_header(header, &reply_header, reply.error); - + for (i=0; i<3*num_attrs; i+=3) { + bu_type_info[i].butype_name = "dump"; + bu_type_info[i].attrs = bu_types[i/3]; + bu_type_info[i].default_env.default_env_len = 0; + bu_type_info[i+1].butype_name = "tar"; + bu_type_info[i+1].attrs = bu_types[i/3]; + bu_type_info[i+1].default_env.default_env_len = 0; + bu_type_info[i+2].butype_name = "cpio"; + bu_type_info[i+2].attrs = bu_types[i/3]; + bu_type_info[i+2].default_env.default_env_len = 0; + } + reply.butype_info.butype_info_val = bu_type_info; + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_butype_info_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); - xdr_ndmp_config_get_butype_info_reply(&reply_stream, &reply); - - free(bu_type_info); + xdr_ndmp_config_get_butype_info_reply(&reply_stream, &reply); + + free(bu_type_info); - + } void ndmp_config_get_fs_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* /* NDMP_CONFIG_GET_FS_INFO - * - * No request arguments - * - * const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; - * const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; - * const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; - * const NDMP_FS_INFO_TOTOAL_INODES_INVALID = 0x00000008; - * const NDMP_FS_INFO_USED_INNODES_INVALID = 0x00000010; - * - * struct ndmp_fs_info - * { - * u_long invalid; /* invalid bit - * string fs_type <>; - * string fs_logical_device <>; - * string fs_physical_device <>; - * ndmp_u_quad total_size; - * ndmp_u_quad used_size; - * ndmp_u_quad avail_size; - * ndmp_u_quad total_inodes; - * ndmp_u_quad used_inodes; - * ndmp_pval fs_env <>; - * string fs_status<>; - * }; - * - * struct ndmp_config_get_fs_info_reply - * { - * ndmp_error error; - * ndmp_fs_info fs_info <>; - * }; - */ - - - struct statvfs statvfsbuf; - struct ndmp_header reply_header; - struct ndmp_config_get_fs_info_reply reply; - struct ndmp_fs_info *fs_info; - int rc; - XDR reply_stream; - - rc = statvfs(fs_mount, &statvfsbuf); - if (rc == -1) - reply.error = NDMP_NOT_SUPPORTED_ERR; - else - reply.error = NDMP_NO_ERR; - - set_header(header, &reply_header, reply.error); - - if (rc != -1) { - reply.fs_info.fs_info_len = 1; - reply.fs_info.fs_info_val = (struct ndmp_fs_info *) - malloc(sizeof(struct ndmp_fs_info)); - fs_info = reply.fs_info.fs_info_val; - fs_info->invalid = 0; - fs_info->fs_type = "glusterfs"; - fs_info->fs_logical_device = - (char *)malloc(strlen(fs_mount)*sizeof(char)); - strcpy(fs_info->fs_logical_device, fs_mount); - fs_info->fs_physical_device = - (char *)malloc(strlen(fs_mount)*sizeof(char)); - strcpy(fs_info->fs_physical_device, fs_mount); - - fs_info->total_size.low = - statvfsbuf.f_blocks*statvfsbuf.f_frsize/1024; - fs_info->total_size.high = 0; - fs_info->avail_size.low = - statvfsbuf.f_bavail*statvfsbuf.f_frsize/1024; - fs_info->avail_size.high = 0; - fs_info->used_size.low = fs_info->total_size.low - - statvfsbuf.f_bfree*statvfsbuf.f_frsize/1024; - fs_info->used_size.high = 0; - fs_info->total_inodes.low = statvfsbuf.f_files; - fs_info->total_inodes.high = 0; - fs_info->used_inodes.low = statvfsbuf.f_files - - statvfsbuf.f_ffree; - - fs_info->used_inodes.high = 0; - fs_info->fs_env.fs_env_len = 0; - fs_info->fs_status = "up"; - } - - txn->reply.length = xdr_sizeof((xdrproc_t) + /* /* NDMP_CONFIG_GET_FS_INFO + * + * No request arguments + * + * const NDMP_FS_INFO_TOTAL_SIZE_INVALID = 0x00000001; + * const NDMP_FS_INFO_USED_SIZE_INVALID = 0x00000002; + * const NDMP_FS_INFO_AVAIL_SIZE_INVALID = 0x00000004; + * const NDMP_FS_INFO_TOTOAL_INODES_INVALID = 0x00000008; + * const NDMP_FS_INFO_USED_INNODES_INVALID = 0x00000010; + * + * struct ndmp_fs_info + * { + * u_long invalid; /* invalid bit + * string fs_type <>; + * string fs_logical_device <>; + * string fs_physical_device <>; + * ndmp_u_quad total_size; + * ndmp_u_quad used_size; + * ndmp_u_quad avail_size; + * ndmp_u_quad total_inodes; + * ndmp_u_quad used_inodes; + * ndmp_pval fs_env <>; + * string fs_status<>; + * }; + * + * struct ndmp_config_get_fs_info_reply + * { + * ndmp_error error; + * ndmp_fs_info fs_info <>; + * }; + */ + + + struct statvfs statvfsbuf; + struct ndmp_header reply_header; + struct ndmp_config_get_fs_info_reply reply; + struct ndmp_fs_info *fs_info; + int rc; + XDR reply_stream; + + rc = statvfs(fs_mount, &statvfsbuf); + if (rc == -1) + reply.error = NDMP_NOT_SUPPORTED_ERR; + else + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + + if (rc != -1) { + reply.fs_info.fs_info_len = 1; + reply.fs_info.fs_info_val = (struct ndmp_fs_info *) + malloc(sizeof(struct ndmp_fs_info)); + fs_info = reply.fs_info.fs_info_val; + fs_info->invalid = 0; + fs_info->fs_type = "glusterfs"; + fs_info->fs_logical_device = + (char *)malloc(strlen(fs_mount)*sizeof(char)); + strcpy(fs_info->fs_logical_device, fs_mount); + fs_info->fs_physical_device = + (char *)malloc(strlen(fs_mount)*sizeof(char)); + strcpy(fs_info->fs_physical_device, fs_mount); + + fs_info->total_size.low = + statvfsbuf.f_blocks*statvfsbuf.f_frsize/1024; + fs_info->total_size.high = 0; + fs_info->avail_size.low = + statvfsbuf.f_bavail*statvfsbuf.f_frsize/1024; + fs_info->avail_size.high = 0; + fs_info->used_size.low = fs_info->total_size.low - + statvfsbuf.f_bfree*statvfsbuf.f_frsize/1024; + fs_info->used_size.high = 0; + fs_info->total_inodes.low = statvfsbuf.f_files; + fs_info->total_inodes.high = 0; + fs_info->used_inodes.low = statvfsbuf.f_files - + statvfsbuf.f_ffree; + + fs_info->used_inodes.high = 0; + fs_info->fs_env.fs_env_len = 0; + fs_info->fs_status = "up"; + } + + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_fs_info_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); if (reply.error == NDMP_NO_ERR) { xdr_ndmp_config_get_fs_info_reply(&reply_stream, &reply); } else txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_fs_info_reply, - &reply); + xdr_ndmp_config_get_fs_info_reply, + &reply); - free(fs_info->fs_logical_device); - free(fs_info->fs_physical_device); + free(fs_info->fs_logical_device); + free(fs_info->fs_physical_device); } void ndmp_config_get_tape_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONFIG_GET_TAPE_INFO - * - * tape attributes - * - * const NDMP_TAPE_ATTR_REWIND = 0x00000001; - * const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; - * - * No request arguments - * - * struct ndmp_device_capability - * { - * string device <>; - * u_long attr; - * ndmp_pval capability <>; - * }; - * - * struct ndmp_device_info - * { - * string model <>; - * ndmp_device_capability caplist <>; - * }; - * - * struct ndmp_config_get_tape_info_reply - * { - * ndmp_error error; - * ndmp_device_info tape_info <>; - * }; - */ - - struct ndmp_header reply_header; - struct ndmp_config_get_tape_info_reply reply; - XDR reply_stream; - - ndmp_device_info tapeInfo; - ndmp_device_capability devCap; - ndmp_pval pval; - - reply.error = NDMP_NO_ERR; - reply.tape_info.tape_info_len = 1; - reply.tape_info.tape_info_val = &tapeInfo; - - tapeInfo.model = "HP MSL6000 Tape"; - tapeInfo.caplist.caplist_len = 1; - tapeInfo.caplist.caplist_val = &devCap; + /* NDMP_CONFIG_GET_TAPE_INFO + * + * tape attributes + * + * const NDMP_TAPE_ATTR_REWIND = 0x00000001; + * const NDMP_TAPE_ATTR_UNLOAD = 0x00000002; + * + * No request arguments + * + * struct ndmp_device_capability + * { + * string device <>; + * u_long attr; + * ndmp_pval capability <>; + * }; + * + * struct ndmp_device_info + * { + * string model <>; + * ndmp_device_capability caplist <>; + * }; + * + * struct ndmp_config_get_tape_info_reply + * { + * ndmp_error error; + * ndmp_device_info tape_info <>; + * }; + */ + + struct ndmp_header reply_header; + struct ndmp_config_get_tape_info_reply reply; + XDR reply_stream; + + ndmp_device_info tapeInfo; + ndmp_device_capability devCap; + ndmp_pval pval; + + reply.error = NDMP_NO_ERR; + reply.tape_info.tape_info_len = 1; + reply.tape_info.tape_info_val = &tapeInfo; + + tapeInfo.model = "HP MSL6000 Tape"; + tapeInfo.caplist.caplist_len = 1; + tapeInfo.caplist.caplist_val = &devCap; - devCap.device = "/dev/tape0"; - devCap.attr = NDMP_TAPE_ATTR_REWIND; - devCap.capability.capability_len = 1; - devCap.capability.capability_val = &pval; + devCap.device = "/dev/tape0"; + devCap.attr = NDMP_TAPE_ATTR_REWIND; + devCap.capability.capability_len = 1; + devCap.capability.capability_val = &pval; - pval.name = "TAPE_SIZE"; - pval.value = "1GB"; + pval.name = "TAPE_SIZE"; + pval.value = "1GB"; - set_header(header, &reply_header, reply.error); - + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_tape_info_reply, &reply); - xdrmem_create(&reply_stream, + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); xdr_ndmp_header(&reply_stream, &reply_header); @@ -467,313 +467,313 @@ void ndmp_config_get_tape_info(struct client_txn *txn, struct ndmp_header header } else txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_tape_info_reply, - &reply); + &reply); } void ndmp_config_get_scsi_info(struct client_txn *txn, - struct ndmp_header header, - XDR* request_stream) + struct ndmp_header header, + XDR* request_stream) { - /* NDMP_CONFIG_GET_SCSI_INFO - * - * No request arguments - * - * no SCSI attributes - * - * struct ndmp_config_get_scsi_info_reply - * { - * ndmp_error error; - * ndmp_device_info scsi_info <>; - * }; - */ - XDR reply_stream; - struct ndmp_header reply_header; - struct ndmp_config_get_scsi_info_reply reply; - struct ndmp_config_get_scsi_info_reply *scsi_info = - alloc_scsi_info(); - - - get_scsi_info(scsi_info); - - /* - * Check if there are any scsi devices - */ - if (scsi_info->scsi_info.scsi_info_len > 0) { - /* - * There is device info to be sent - */ - reply.error = NDMP_NO_ERR; - reply.scsi_info.scsi_info_len = - scsi_info->scsi_info.scsi_info_len; - reply.scsi_info.scsi_info_val = - scsi_info->scsi_info.scsi_info_val; - - } - else - reply.error = NDMP_NOT_SUPPORTED_ERR; - set_header(header, &reply_header, reply.error); - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_scsi_info_reply, - &reply); - - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - if (reply.error == NDMP_NO_ERR) { - xdr_ndmp_config_get_scsi_info_reply(&reply_stream, &reply); - } - else - txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_scsi_info_reply, - &reply); - - - free_scsi_info(scsi_info); + /* NDMP_CONFIG_GET_SCSI_INFO + * + * No request arguments + * + * no SCSI attributes + * + * struct ndmp_config_get_scsi_info_reply + * { + * ndmp_error error; + * ndmp_device_info scsi_info <>; + * }; + */ + XDR reply_stream; + struct ndmp_header reply_header; + struct ndmp_config_get_scsi_info_reply reply; + struct ndmp_config_get_scsi_info_reply *scsi_info = + alloc_scsi_info(); + + + get_scsi_info(scsi_info); + + /* + * Check if there are any scsi devices + */ + if (scsi_info->scsi_info.scsi_info_len > 0) { + /* + * There is device info to be sent + */ + reply.error = NDMP_NO_ERR; + reply.scsi_info.scsi_info_len = + scsi_info->scsi_info.scsi_info_len; + reply.scsi_info.scsi_info_val = + scsi_info->scsi_info.scsi_info_val; + + } + else + reply.error = NDMP_NOT_SUPPORTED_ERR; + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_scsi_info_reply, + &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_config_get_scsi_info_reply(&reply_stream, &reply); + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_config_get_scsi_info_reply, + &reply); + + + free_scsi_info(scsi_info); } void ndmp_config_get_server_info(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONFIG_GET_SERVER_INFO - * - * no request arguments - * - * struct ndmp_config_get_server_info_reply - * { - * ndmp_error error; - * string vendor_name<>; - * string product_name<>; - * string revision_number<>; - * ndmp_auth_type auth_type<>; - * }; - */ - - struct ndmp_header reply_header; - struct ndmp_config_get_server_info_reply reply; - enum ndmp_auth_type auth_types[1] = {NDMP_AUTH_NONE}; - XDR reply_stream; - - reply.vendor_name = "Red Hat, Inc."; - reply.product_name = "NDMP Server"; - reply.revision_number = "0.1"; - reply.auth_type.auth_type_len = 1; - reply.auth_type.auth_type_val = auth_types; - reply.error = NDMP_NO_ERR; - - set_header(header, &reply_header, reply.error); - + /* NDMP_CONFIG_GET_SERVER_INFO + * + * no request arguments + * + * struct ndmp_config_get_server_info_reply + * { + * ndmp_error error; + * string vendor_name<>; + * string product_name<>; + * string revision_number<>; + * ndmp_auth_type auth_type<>; + * }; + */ + + struct ndmp_header reply_header; + struct ndmp_config_get_server_info_reply reply; + enum ndmp_auth_type auth_types[1] = {NDMP_AUTH_NONE}; + XDR reply_stream; + + reply.vendor_name = "Red Hat, Inc."; + reply.product_name = "NDMP Server"; + reply.revision_number = "0.1"; + reply.auth_type.auth_type_len = 1; + reply.auth_type.auth_type_val = auth_types; + reply.error = NDMP_NO_ERR; + + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); txn->reply.length += xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_server_info_reply, - &reply); - - xdrmem_create(&reply_stream, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - + xdr_ndmp_header(&reply_stream, &reply_header); if (reply.error == NDMP_NO_ERR) { xdr_ndmp_config_get_server_info_reply(&reply_stream, &reply); } else txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_config_get_server_info_reply, - &reply); + xdr_ndmp_config_get_server_info_reply, + &reply); } void get_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info ) { - /* - * This function reads scsi information from /proc/scsi/scsi - */ - - FILE *scsi = fopen("/proc/scsi/scsi", "r"); - char *data; - char *s; - char *name; - char *value; - char *saveptr; - int i, j,k; - struct ndmp_device_info *device_info; - struct ndmp_device_capability *device_capability; - struct ndmp_pval *pval; - char *model, *device; - data = (char *)malloc(80*sizeof(char)); - name = (char *)malloc(80*sizeof(char)); - value = (char *)malloc(80*sizeof(char)); - device = (char *) malloc(80*sizeof(char)); - - fgets(data, 80, scsi); // read and ignore first line - if (scsi != NULL) { - i = -1; - j = 0; - while(fgets(data,80, scsi) != NULL) { - // strtok_r is reentrant - s = strtok_r(data, " ", &saveptr); - if (strcmp(s,"Host:") == 0) { - /* - * New scsi device - */ - i++; - scsi_info->scsi_info.scsi_info_len = i+1; /* number of devices */ - device_info = scsi_info->scsi_info.scsi_info_val+i; - j = 0; - } - do { - strcpy(name, ""); - strcpy(value,""); - s = get_name(name, s, &saveptr); - - if (strcmp(s, "Type:") == 0) { - s = get_value(value, s, &saveptr,1); - } - else { - s = get_value(value, s, &saveptr,0); - } - - if (value[strlen(value)-1] == '\n') - value[strlen(value)-1] = '\0'; - - pval = device_info->caplist.caplist_val->capability.capability_val+j; - strcpy(pval->name, name); - strcpy(pval->value, value); - if (strcmp(name, "Model:") == 0) - strcpy(device_info->model, value); - if (strcmp(name, "Type:")==0) { - strcpy(device_info->caplist.caplist_val->device, value); - } - device_info->caplist.caplist_val->attr = j; - j++; - device_info->caplist.caplist_val->capability.capability_len = j; - device_info->caplist.caplist_len = 1; - }while(s!=NULL); - printf ("\n"); - } - } - free(data); - free(name); - free(value); - free(device); + /* + * This function reads scsi information from /proc/scsi/scsi + */ + + FILE *scsi = fopen("/proc/scsi/scsi", "r"); + char *data; + char *s; + char *name; + char *value; + char *saveptr; + int i, j,k; + struct ndmp_device_info *device_info; + struct ndmp_device_capability *device_capability; + struct ndmp_pval *pval; + char *model, *device; + data = (char *)malloc(80*sizeof(char)); + name = (char *)malloc(80*sizeof(char)); + value = (char *)malloc(80*sizeof(char)); + device = (char *) malloc(80*sizeof(char)); + + fgets(data, 80, scsi); // read and ignore first line + if (scsi != NULL) { + i = -1; + j = 0; + while(fgets(data,80, scsi) != NULL) { + // strtok_r is reentrant + s = strtok_r(data, " ", &saveptr); + if (strcmp(s,"Host:") == 0) { + /* + * New scsi device + */ + i++; + scsi_info->scsi_info.scsi_info_len = i+1; /* number of devices */ + device_info = scsi_info->scsi_info.scsi_info_val+i; + j = 0; + } + do { + strcpy(name, ""); + strcpy(value,""); + s = get_name(name, s, &saveptr); + + if (strcmp(s, "Type:") == 0) { + s = get_value(value, s, &saveptr,1); + } + else { + s = get_value(value, s, &saveptr,0); + } + + if (value[strlen(value)-1] == '\n') + value[strlen(value)-1] = '\0'; + + pval = device_info->caplist.caplist_val->capability.capability_val+j; + strcpy(pval->name, name); + strcpy(pval->value, value); + if (strcmp(name, "Model:") == 0) + strcpy(device_info->model, value); + if (strcmp(name, "Type:")==0) { + strcpy(device_info->caplist.caplist_val->device, value); + } + device_info->caplist.caplist_val->attr = j; + j++; + device_info->caplist.caplist_val->capability.capability_len = j; + device_info->caplist.caplist_len = 1; + }while(s!=NULL); + printf ("\n"); + } + } + free(data); + free(name); + free(value); + free(device); } char * get_name(char* name, char *curr, char** saveptr) { - - while(curr!= NULL && curr[strlen(curr)-1] != ':') { - if(strcmp(name,"") == 0) - strcpy(name, curr); - else - sprintf(name,"%s %s", name, curr); - curr = strtok_r(NULL, " ", saveptr); - } - if (strcmp(name, "") == 0) - strcpy(name, curr); - else - sprintf(name, "%s %s", name, curr); - return name; + + while(curr!= NULL && curr[strlen(curr)-1] != ':') { + if(strcmp(name,"") == 0) + strcpy(name, curr); + else + sprintf(name,"%s %s", name, curr); + curr = strtok_r(NULL, " ", saveptr); + } + if (strcmp(name, "") == 0) + strcpy(name, curr); + else + sprintf(name, "%s %s", name, curr); + return name; } char *get_value(char *value, char *curr, char** saveptr, int one_word) { - - curr = strtok_r(NULL, " ", saveptr); - if (!one_word) { - while(curr!=NULL && curr[strlen(curr)-1] != ':') { - if(strcmp(value, "") == 0) - strcpy(value,curr); - else - sprintf(value,"%s %s",value, curr); - curr = strtok_r(NULL, " ", saveptr); - } - } - else { - strcpy(value,curr); - curr = strtok_r(NULL, " ", saveptr); - } - return curr; + + curr = strtok_r(NULL, " ", saveptr); + if (!one_word) { + while(curr!=NULL && curr[strlen(curr)-1] != ':') { + if(strcmp(value, "") == 0) + strcpy(value,curr); + else + sprintf(value,"%s %s",value, curr); + curr = strtok_r(NULL, " ", saveptr); + } + } + else { + strcpy(value,curr); + curr = strtok_r(NULL, " ", saveptr); + } + return curr; } struct ndmp_config_get_scsi_info_reply* alloc_scsi_info() { - /* - * Allocation approach: - * ndmp_config_get_scsi_info_reply has many nmpd_device_info structs - * one for each device - * Each ndmp_device_info has a ndmp_device_capabilty struct, which + /* + * Allocation approach: + * ndmp_config_get_scsi_info_reply has many nmpd_device_info structs + * one for each device + * Each ndmp_device_info has a ndmp_device_capabilty struct, which * has a number of properties ndmp_pval structs. - * - * Assumptions: We will assume a max of 32 scsi devices - * which is plenty. - * We will assume max of 16 name-value properties for each - * device, which should also be plenty. - * These assumptions simplify getting scsi information - * and setting them in struct ndmp_config_get_scsi_info_repy - * especially having to set info_len attribute and capability_len - * attributes. It would require a two pass traversal of scsi device - * info, otherwise. - */ - - int max_number_of_devices = 32; - int max_number_of_properties = 16; - int str_size = 32; - int i,j; - - struct ndmp_config_get_scsi_info_reply* retval; - struct ndmp_device_capability device_capability; - struct ndmp_device_info *device; - struct ndmp_pval *pval; - retval = malloc(sizeof(struct ndmp_config_get_scsi_info_reply)); - - retval->scsi_info.scsi_info_val = (struct ndmp_device_info *) - malloc(max_number_of_devices* - sizeof(struct ndmp_device_info)); - - for (i=0; iscsi_info.scsi_info_val+i; - device->model = malloc(str_size*sizeof(char)); - device->caplist.caplist_val = (struct ndmp_device_capability *) - malloc(sizeof(struct ndmp_device_capability)); - device->caplist.caplist_val->capability.capability_val = (struct ndmp_pval *) - malloc(max_number_of_properties*sizeof(struct ndmp_pval)); - device->caplist.caplist_val->device = (char *) - malloc(str_size*sizeof(char)); - - for (j=0; jcaplist.caplist_val->capability.capability_val+j; - pval->name = (char *) malloc(str_size*sizeof(char)); - pval->value = (char *)malloc(str_size*sizeof(char)); - } - } - return retval; + * + * Assumptions: We will assume a max of 32 scsi devices + * which is plenty. + * We will assume max of 16 name-value properties for each + * device, which should also be plenty. + * These assumptions simplify getting scsi information + * and setting them in struct ndmp_config_get_scsi_info_repy + * especially having to set info_len attribute and capability_len + * attributes. It would require a two pass traversal of scsi device + * info, otherwise. + */ + + int max_number_of_devices = 32; + int max_number_of_properties = 16; + int str_size = 32; + int i,j; + + struct ndmp_config_get_scsi_info_reply* retval; + struct ndmp_device_capability device_capability; + struct ndmp_device_info *device; + struct ndmp_pval *pval; + retval = malloc(sizeof(struct ndmp_config_get_scsi_info_reply)); + + retval->scsi_info.scsi_info_val = (struct ndmp_device_info *) + malloc(max_number_of_devices* + sizeof(struct ndmp_device_info)); + + for (i=0; iscsi_info.scsi_info_val+i; + device->model = malloc(str_size*sizeof(char)); + device->caplist.caplist_val = (struct ndmp_device_capability *) + malloc(sizeof(struct ndmp_device_capability)); + device->caplist.caplist_val->capability.capability_val = (struct ndmp_pval *) + malloc(max_number_of_properties*sizeof(struct ndmp_pval)); + device->caplist.caplist_val->device = (char *) + malloc(str_size*sizeof(char)); + + for (j=0; jcaplist.caplist_val->capability.capability_val+j; + pval->name = (char *) malloc(str_size*sizeof(char)); + pval->value = (char *)malloc(str_size*sizeof(char)); + } + } + return retval; } void free_scsi_info(struct ndmp_config_get_scsi_info_reply* scsi_info) { - /* - * Frees space held in scsi_info as per assumption - * in alloc_scsi_info - */ - - int max_number_of_devices = 32; - int max_number_of_properties = 16; - int i,j; - - struct ndmp_device_capability *device_capability; - struct ndmp_device_info *device; - struct ndmp_pval *pval; - - for (i=0; iscsi_info.scsi_info_val+i; - free(device->model); - device_capability = device->caplist.caplist_val; - for (j=0; jcapability.capability_val[j].name); - free(device_capability->capability.capability_val[j].value); - } - free(device_capability->device); - free(device_capability); - } - free(scsi_info->scsi_info.scsi_info_val); - free(scsi_info); + /* + * Frees space held in scsi_info as per assumption + * in alloc_scsi_info + */ + + int max_number_of_devices = 32; + int max_number_of_properties = 16; + int i,j; + + struct ndmp_device_capability *device_capability; + struct ndmp_device_info *device; + struct ndmp_pval *pval; + + for (i=0; iscsi_info.scsi_info_val+i; + free(device->model); + device_capability = device->caplist.caplist_val; + for (j=0; jcapability.capability_val[j].name); + free(device_capability->capability.capability_val[j].value); + } + free(device_capability->device); + free(device_capability); + } + free(scsi_info->scsi_info.scsi_info_val); + free(scsi_info); } diff --git a/ndmp/src/ndmp_connect.c b/ndmp/src/ndmp_connect.c index c861fb7..38d7e98 100644 --- a/ndmp/src/ndmp_connect.c +++ b/ndmp/src/ndmp_connect.c @@ -33,91 +33,91 @@ void ndmp_connect_open(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_CONNECT_OPEN - * - * struct ndmp_connect_open_request - * { - * u_short protocol_version; - * }; - * - * struct ndmp_connect_open_reply - * { - * ndmp_error error; - * }; - * - */ - - struct ndmp_connect_open_request request; - struct ndmp_header reply_header; - struct ndmp_connect_open_reply reply; - struct ndmp_session_info *session_info; - XDR reply_stream; - - xdr_ndmp_connect_open_request(request_stream, &request); - - session_info = get_session_info(txn->client_session.session_id); - - /* - * There could be concurrent sessions for the - * same client. Since this fuction updates shared data, - * it needs to be thread-safe. - */ + /* NDMP_CONNECT_OPEN + * + * struct ndmp_connect_open_request + * { + * u_short protocol_version; + * }; + * + * struct ndmp_connect_open_reply + * { + * ndmp_error error; + * }; + * + */ + + struct ndmp_connect_open_request request; + struct ndmp_header reply_header; + struct ndmp_connect_open_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + xdr_ndmp_connect_open_request(request_stream, &request); + + session_info = get_session_info(txn->client_session.session_id); + + /* + * There could be concurrent sessions for the + * same client. Since this fuction updates shared data, + * it needs to be thread-safe. + */ - enter_critical_section(session_info->s_lock); + enter_critical_section(session_info->s_lock); - if (session_info->connection_state != LISTEN) - reply.error = NDMP_ILLEGAL_STATE_ERR; - else if (request.protocol_version >= 1 && request.protocol_version <= 3) - reply.error = NDMP_NO_ERR; - else if (request.protocol_version > 3) - reply.error = NDMP_ILLEGAL_ARGS_ERR; + if (session_info->connection_state != LISTEN) + reply.error = NDMP_ILLEGAL_STATE_ERR; + else if (request.protocol_version >= 1 && request.protocol_version <= 3) + reply.error = NDMP_NO_ERR; + else if (request.protocol_version > 3) + reply.error = NDMP_ILLEGAL_ARGS_ERR; - set_header(header, &reply_header, reply.error); - - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_connect_open_reply, &reply); - - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - if (reply.error == NDMP_NO_ERR) { - xdr_ndmp_connect_open_reply(&reply_stream, &reply); - session_info->connection_state = CONNECTED; - /* TBD: What about other states? */ - } - else - txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_connect_open_reply, &reply); - exit_critical_section(session_info->s_lock); + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_connect_open_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) { + xdr_ndmp_connect_open_reply(&reply_stream, &reply); + session_info->connection_state = CONNECTED; + /* TBD: What about other states? */ + } + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_connect_open_reply, &reply); + exit_critical_section(session_info->s_lock); } void ndmp_connect_close(struct client_txn *txn, - struct ndmp_header header, - XDR* request_stream) + struct ndmp_header header, + XDR* request_stream) { - /* NDMP_CONNECT_CLOSE */ - /* no request arguments */ - /* no reply message */ - - struct ndmp_session_info *session_info; + /* NDMP_CONNECT_CLOSE */ + /* no request arguments */ + /* no reply message */ + + struct ndmp_session_info *session_info; - session_info = get_session_info(txn->client_session.session_id); - - enter_critical_section(session_info->s_lock); + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); - /* - * States set as per Figure 8 in NDMP V3 spec. - */ + /* + * States set as per Figure 8 in NDMP V3 spec. + */ - session_info->connection_state = HALTED; // No state diagram for connect? - session_info->data_state = HALTED; - session_info->mover_state = HALTED; - txn->reply.length = 0; // No reply to be sent + session_info->connection_state = HALTED; // No state diagram for connect? + session_info->data_state = HALTED; + session_info->mover_state = HALTED; + txn->reply.length = 0; // No reply to be sent - exit_critical_section(session_info->s_lock); + exit_critical_section(session_info->s_lock); } diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index 532ed85..89b42a5 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -26,159 +26,159 @@ struct queue_hdr* get_session_queue() ; void xdr_decode_encode(struct client_txn *txn) { - /* - * 1. Decode the message type from txn->request - * 2. Depending on the message type call the appropriate - * NDMP message handler. When the handler returns, - * txn->response will hold the marshaled (encoded) NDMP response - * 3. Enqueue the response into the response queue - */ - - XDR request_stream, stream_len; - int message_type; - struct ndmp_header header; - char *buf, mesg_len[4]; - int len; - struct comm_context *ctx = comm_context(); - if (txn->request.is_tcp_connect == 1) { - header.message = 0xf001; - } - else { - xdrmem_create(&request_stream, txn->request.message+4, txn->request.length-4, - XDR_DECODE); - /* - * Read the ndmp header - */ - - xdr_ndmp_header(&request_stream, &header); - } - /* - * Add job to session's job queue - */ - - add_job_to_session(txn); - ndmp_dispatch(header.message)(txn, header, &request_stream); - - if (cleanup_session(txn) == 1 || txn->reply.length == 0) { - free(txn); /* client terminated. Don't send response */ - } - else { - /* - * It is possible that at this point in time - * or later before the response is sent the client - * terminates. comm layer needs to check again for - * client termination, before sending the response - */ - - buf = (char *)malloc(txn->reply.length+4); - memcpy(buf+4,txn->reply.message,txn->reply.length); - len = txn->reply.length | (1<<31); - xdrmem_create(&stream_len,mesg_len,4, XDR_ENCODE); - xdr_int(&stream_len, &len); - memcpy(buf,mesg_len,4); - memcpy(txn->reply.message, buf, txn->reply.length+4); - txn->reply.length +=4; - enqueue(ctx->reply_jobs, txn); - free(buf); - } + /* + * 1. Decode the message type from txn->request + * 2. Depending on the message type call the appropriate + * NDMP message handler. When the handler returns, + * txn->response will hold the marshaled (encoded) NDMP response + * 3. Enqueue the response into the response queue + */ + + XDR request_stream, stream_len; + int message_type; + struct ndmp_header header; + char *buf, mesg_len[4]; + int len; + struct comm_context *ctx = comm_context(); + if (txn->request.is_tcp_connect == 1) { + header.message = 0xf001; + } + else { + xdrmem_create(&request_stream, txn->request.message+4, txn->request.length-4, + XDR_DECODE); + /* + * Read the ndmp header + */ + + xdr_ndmp_header(&request_stream, &header); + } + /* + * Add job to session's job queue + */ + + add_job_to_session(txn); + ndmp_dispatch(header.message)(txn, header, &request_stream); + + if (cleanup_session(txn) == 1 || txn->reply.length == 0) { + free(txn); /* client terminated. Don't send response */ + } + else { + /* + * It is possible that at this point in time + * or later before the response is sent the client + * terminates. comm layer needs to check again for + * client termination, before sending the response + */ + + buf = (char *)malloc(txn->reply.length+4); + memcpy(buf+4,txn->reply.message,txn->reply.length); + len = txn->reply.length | (1<<31); + xdrmem_create(&stream_len,mesg_len,4, XDR_ENCODE); + xdr_int(&stream_len, &len); + memcpy(buf,mesg_len,4); + memcpy(txn->reply.message, buf, txn->reply.length+4); + txn->reply.length +=4; + enqueue(ctx->reply_jobs, txn); + free(buf); + } } ndmp_message_handler ndmp_dispatch(int message) { - switch (message) { - case 0xf001: - return ndmp_accept_notify; - case 0x900: - return ndmp_connect_open; - case 0x902: - return ndmp_connect_close; - case 0x100: - return ndmp_config_get_host_info; - case 0x102: - return ndmp_config_get_connection_type; - case 0x103: - return ndmp_config_get_auth_attr; - case 0x104: - return ndmp_config_get_butype_info; - case 0x105: - return ndmp_config_get_fs_info; - case 0x106: - return ndmp_config_get_tape_info; - case 0x107: - return ndmp_config_get_scsi_info; - case 0x108: - return ndmp_config_get_server_info; - default: - return ndmp_error_message; - } + switch (message) { + case 0xf001: + return ndmp_accept_notify; + case 0x900: + return ndmp_connect_open; + case 0x902: + return ndmp_connect_close; + case 0x100: + return ndmp_config_get_host_info; + case 0x102: + return ndmp_config_get_connection_type; + case 0x103: + return ndmp_config_get_auth_attr; + case 0x104: + return ndmp_config_get_butype_info; + case 0x105: + return ndmp_config_get_fs_info; + case 0x106: + return ndmp_config_get_tape_info; + case 0x107: + return ndmp_config_get_scsi_info; + case 0x108: + return ndmp_config_get_server_info; + default: + return ndmp_error_message; + } } void ndmp_error_message(struct client_txn *txn, - struct ndmp_header header, - XDR* requeststream) + struct ndmp_header header, + XDR* requeststream) { - struct ndmp_header reply_header; - XDR reply_stream; - set_header(header, &reply_header, NDMP_NOT_SUPPORTED_ERR); - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, - &reply_header); - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, - XDR_ENCODE); - xdr_ndmp_header(&reply_stream, &reply_header); + struct ndmp_header reply_header; + XDR reply_stream; + set_header(header, &reply_header, NDMP_NOT_SUPPORTED_ERR); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, + &reply_header); + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, + XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); } void ndmp_accept_notify(struct client_txn* txn, struct ndmp_header header, XDR* request_stream) { - struct ndmp_notify_connected_request reply; - struct ndmp_header reply_header; - XDR reply_stream; - - reply.reason = NDMP_CONNECTED; - reply.protocol_version = 3; - reply.text_reason = "SUCCESSFUL CONNECTION"; - - reply_header.sequence = get_next_seq_number(); - reply_header.time_stamp = (u_long) time(NULL); - reply_header.message_type = NDMP_MESSAGE_REQUEST; - reply_header.message = NDMP_NOTIFY_CONNECTED; - reply_header.reply_sequence = 0; - reply_header.error = NDMP_NO_ERR; - - //set_header(header, &reply_header, NDMP_NO_ERR); - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, - &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_notify_connected_request, - &reply); - - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, - XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - xdr_ndmp_notify_connected_request(&reply_stream, &reply); + struct ndmp_notify_connected_request reply; + struct ndmp_header reply_header; + XDR reply_stream; + + reply.reason = NDMP_CONNECTED; + reply.protocol_version = 3; + reply.text_reason = ""; + + reply_header.sequence = get_next_seq_number(); + reply_header.time_stamp = (u_long) time(NULL); + reply_header.message_type = NDMP_MESSAGE_REQUEST; + reply_header.message = NDMP_NOTIFY_CONNECTED; + reply_header.reply_sequence = 0; + reply_header.error = NDMP_NO_ERR; + + //set_header(header, &reply_header, NDMP_NO_ERR); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, + &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_notify_connected_request, + &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length, + XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + xdr_ndmp_notify_connected_request(&reply_stream, &reply); } int get_next_seq_number() { - static int sequence_number = 1; + static int sequence_number = 1; - return sequence_number++; + return sequence_number++; } void set_header(ndmp_header req, ndmp_header *reply, ndmp_error err) { - reply->sequence = get_next_seq_number(); - reply->time_stamp = (u_long) time(NULL); - reply->message_type = NDMP_MESSAGE_REPLY; - reply->message = req.message; - reply->reply_sequence = req.sequence; - reply->error = err; + reply->sequence = get_next_seq_number(); + reply->time_stamp = (u_long) time(NULL); + reply->message_type = NDMP_MESSAGE_REPLY; + reply->message = req.message; + reply->reply_sequence = req.sequence; + reply->error = err; } @@ -190,76 +190,76 @@ void set_header(ndmp_header req, ndmp_header *reply, ndmp_error err) struct queue_hdr* get_session_queue() { - static struct queue_hdr *session_info_queue = NULL; - struct lock *s_lock = get_lock(); - enter_critical_section(s_lock); + static struct queue_hdr *session_info_queue = NULL; + struct lock *s_lock = get_lock(); + enter_critical_section(s_lock); - if (session_info_queue == NULL) { - session_info_queue = init_queue(); - } - exit_critical_section(s_lock); + if (session_info_queue == NULL) { + session_info_queue = init_queue(); + } + exit_critical_section(s_lock); - return session_info_queue; + return session_info_queue; } struct ndmp_session_info* get_session_info(int session_id) { - struct queue_hdr* session_queue; - struct ndmp_session_info *retval; - struct lock *s_lock = get_lock(); - - /* - * This functon returns the ndmp_session_info - * struct. The ndmp_session_info structs are in - * a queue, keyed by session_id. The states are - * owned and managed by the caller(s). The queue - * does not manage them. The state updates must - * occur in a thread-safe manner. Hence the struct - * has a lock. - * - */ - enter_critical_section(s_lock); - - session_queue = get_session_queue(); - - /* - * Since we create a new sessions - * in this function, it needs to be - * thread-safe - */ - - retval = get_elem(session_queue, (void *)&session_id, - session_info_cmp); - if (retval == NULL) { - - /* - * This must be a new session - * set the the session states to LISTEN - */ - - retval = (struct ndmp_session_info*) malloc( - sizeof(struct ndmp_session_info)); - retval->session_id = session_id; - retval->connection_state = LISTEN; - retval->data_state = LISTEN; - retval->mover_state = LISTEN; - retval->s_lock = get_lock(); - retval->jobs = init_queue(); - retval->is_terminated = 0; - enqueue(session_queue, retval); - } - exit_critical_section(s_lock); - return retval; + struct queue_hdr* session_queue; + struct ndmp_session_info *retval; + struct lock *s_lock = get_lock(); + + /* + * This functon returns the ndmp_session_info + * struct. The ndmp_session_info structs are in + * a queue, keyed by session_id. The states are + * owned and managed by the caller(s). The queue + * does not manage them. The state updates must + * occur in a thread-safe manner. Hence the struct + * has a lock. + * + */ + enter_critical_section(s_lock); + + session_queue = get_session_queue(); + + /* + * Since we create a new sessions + * in this function, it needs to be + * thread-safe + */ + + retval = get_elem(session_queue, (void *)&session_id, + session_info_cmp); + if (retval == NULL) { + + /* + * This must be a new session + * set the the session states to LISTEN + */ + + retval = (struct ndmp_session_info*) malloc( + sizeof(struct ndmp_session_info)); + retval->session_id = session_id; + retval->connection_state = LISTEN; + retval->data_state = LISTEN; + retval->mover_state = LISTEN; + retval->s_lock = get_lock(); + retval->jobs = init_queue(); + retval->is_terminated = 0; + enqueue(session_queue, retval); + } + exit_critical_section(s_lock); + return retval; } int session_info_cmp (void *id, void *session) { - int session_id = *(int *) id; - int queue_elem_session_id = - ((struct ndmp_session_info *)session)->session_id; - - return session_id == queue_elem_session_id; + int session_id = *(int *) id; + int queue_elem_session_id = + ((struct ndmp_session_info *)session)->session_id; + + return session_id == queue_elem_session_id; } /* @@ -270,11 +270,11 @@ int session_info_cmp (void *id, void *session) void add_job_to_session(struct client_txn *txn) { - struct ndmp_session_info *session; + struct ndmp_session_info *session; - session = get_session_info(txn->client_session.session_id); - enqueue(session->jobs, txn); -} + session = get_session_info(txn->client_session.session_id); + enqueue(session->jobs, txn); +} /* * Each session will have outstanding jobs held in * a queue; one queue element for each request in @@ -291,30 +291,30 @@ void add_job_to_session(struct client_txn *txn) int cleanup_session(struct client_txn *txn) { - struct ndmp_session_info *session; - struct queue_hdr *session_queue; - - session = get_session_info(txn->client_session.session_id); - remove_elem(session->jobs, txn, job_cmp); - if (session->is_terminated) { - /* - * If all jobs are done, remove session - */ - if (num_elems(session->jobs) == 0) { - session_queue = get_session_queue(); - remove_elem(session_queue, - &session->session_id, - session_info_cmp); - free(session); - } - return 1; /* session terminated */ - } - return 0; /* session active */ + struct ndmp_session_info *session; + struct queue_hdr *session_queue; + + session = get_session_info(txn->client_session.session_id); + remove_elem(session->jobs, txn, job_cmp); + if (session->is_terminated) { + /* + * If all jobs are done, remove session + */ + if (num_elems(session->jobs) == 0) { + session_queue = get_session_queue(); + remove_elem(session_queue, + &session->session_id, + session_info_cmp); + free(session); + } + return 1; /* session terminated */ + } + return 0; /* session active */ } int job_cmp(void *target, void *elem) { - return target == elem; + return target == elem; } /* @@ -326,8 +326,8 @@ int job_cmp(void *target, void *elem) void terminate_session(int session_id) { - struct ndmp_session_info *session; - - session = get_session_info(session_id); - session->is_terminated = 1; + struct ndmp_session_info *session; + + session = get_session_info(session_id); + session->is_terminated = 1; } diff --git a/ndmp/src/ndmp_msg.h b/ndmp/src/ndmp_msg.h index fcaa62c..e3655a3 100644 --- a/ndmp/src/ndmp_msg.h +++ b/ndmp/src/ndmp_msg.h @@ -18,13 +18,13 @@ enum ndmp_state {IDLE, LISTEN, CONNECTED, ACTIVE, HALTED}; struct ndmp_session_info { - int session_id; - enum ndmp_state connection_state; - enum ndmp_state data_state; - enum ndmp_state mover_state; - struct lock *s_lock; /* for thread-safe updates to session states */ - struct queue_hdr *jobs; /* outstanding client requests */ - int is_terminated; + int session_id; + enum ndmp_state connection_state; + enum ndmp_state data_state; + enum ndmp_state mover_state; + struct lock *s_lock; /* for thread-safe updates to session states */ + struct queue_hdr *jobs; /* outstanding client requests */ + int is_terminated; }; /* @@ -44,8 +44,8 @@ void xdr_decode_encode(struct client_txn *txn); */ typedef void (*ndmp_message_handler)(struct client_txn *txn, - ndmp_header header, - XDR* request_stream); + ndmp_header header, + XDR* request_stream); /* * ndmp_dispatch determines the message handler for a given @@ -88,7 +88,7 @@ int get_next_seq_number(); */ void set_header(struct ndmp_header request, - struct ndmp_header *reply, ndmp_error err); + struct ndmp_header *reply, ndmp_error err); /* * * struct_ndmp_session_info* get_session_info(int session_id) diff --git a/utils/src/hexdump.c b/utils/src/hexdump.c index f0affc4..f297aa4 100644 --- a/utils/src/hexdump.c +++ b/utils/src/hexdump.c @@ -11,14 +11,14 @@ void hexdump(void *buffer, unsigned int size) { - unsigned char *buf = (unsigned char*) buffer; - int i, j; + unsigned char *buf = (unsigned char*) buffer; + int i, j; - for (i = 0; i < size; i += 16) { - printf("%04x ", i); - dump_hex(buf, i, size); - dump_ascii(buf, i, size); - } + for (i = 0; i < size; i += 16) { + printf("%04x ", i); + dump_hex(buf, i, size); + dump_ascii(buf, i, size); + } } @@ -30,17 +30,17 @@ void hexdump(void *buffer, unsigned int size) void dump_hex(unsigned char *buf, unsigned int whence, unsigned int size) { - int i, j, offset; - for (i = 0; i < 2; i++) { - for (j = 0; j < 8; j++) { - offset = whence + i * 8 + j; - if (offset < size) { - printf("%02x ", buf[offset]); - } else - printf(" "); - } - putchar(' '); - } + int i, j, offset; + for (i = 0; i < 2; i++) { + for (j = 0; j < 8; j++) { + offset = whence + i * 8 + j; + if (offset < size) { + printf("%02x ", buf[offset]); + } else + printf(" "); + } + putchar(' '); + } } /* @@ -50,14 +50,14 @@ void dump_hex(unsigned char *buf, unsigned int whence, unsigned int size) void dump_ascii(unsigned char *buf, unsigned int whence, unsigned int size) { - char c; - int i; - printf("|"); - for (i = 0; i < 16; i++) { - if (i + whence < size) { - c = buf[i + whence]; - putchar(isprint(c) ? c : '.'); - } - } - printf("|\n"); + char c; + int i; + printf("|"); + for (i = 0; i < 16; i++) { + if (i + whence < size) { + c = buf[i + whence]; + putchar(isprint(c) ? c : '.'); + } + } + printf("|\n"); } diff --git a/utils/src/locks.c b/utils/src/locks.c index d1f95a8..58abb19 100644 --- a/utils/src/locks.c +++ b/utils/src/locks.c @@ -12,21 +12,21 @@ struct lock* get_lock() { - struct lock* retval; - pthread_mutexattr_t attr; + struct lock* retval; + pthread_mutexattr_t attr; - retval = (struct lock *) malloc(sizeof(struct lock)); - /* create a recursive lock */ - pthread_mutex_init(&retval->mutex, NULL ); - return retval; + retval = (struct lock *) malloc(sizeof(struct lock)); + /* create a recursive lock */ + pthread_mutex_init(&retval->mutex, NULL ); + return retval; } void enter_critical_section(struct lock* a_lock) { - pthread_mutex_lock(&a_lock->mutex); + pthread_mutex_lock(&a_lock->mutex); } void exit_critical_section(struct lock* a_lock) { - pthread_mutex_unlock(&a_lock->mutex); + pthread_mutex_unlock(&a_lock->mutex); } diff --git a/utils/src/locks.h b/utils/src/locks.h index 918d5f8..1817117 100644 --- a/utils/src/locks.h +++ b/utils/src/locks.h @@ -12,7 +12,7 @@ #include struct lock { - pthread_mutex_t mutex; + pthread_mutex_t mutex; }; diff --git a/utils/src/queue.c b/utils/src/queue.c index 8ea1331..0151afa 100644 --- a/utils/src/queue.c +++ b/utils/src/queue.c @@ -16,130 +16,130 @@ void exit_critical_section(struct lock *q_lock); struct queue_hdr* init_queue() { - struct queue_hdr* retval = (struct queue_hdr *) calloc(1, - sizeof(struct queue_hdr)); - retval->lock = get_lock(); + struct queue_hdr* retval = (struct queue_hdr *) calloc(1, + sizeof(struct queue_hdr)); + retval->lock = get_lock(); - return retval; + return retval; } void enqueue(struct queue_hdr* hdr, void *elem) { - struct queue_node *node = (struct queue_node *) malloc( - sizeof(struct queue_node)); - node->elem = elem; - node->next = NULL; - - enter_critical_section(hdr->lock); - /* - * Queue can either be empty or non-empty - */ - - if (hdr->first == NULL ) { // empty queue - hdr->first = node; - hdr->last = node; - } else { // non-empty queue - hdr->last->next = node; - hdr->last = node; - } - hdr->num_elems++; - exit_critical_section(hdr->lock); + struct queue_node *node = (struct queue_node *) malloc( + sizeof(struct queue_node)); + node->elem = elem; + node->next = NULL; + + enter_critical_section(hdr->lock); + /* + * Queue can either be empty or non-empty + */ + + if (hdr->first == NULL ) { // empty queue + hdr->first = node; + hdr->last = node; + } else { // non-empty queue + hdr->last->next = node; + hdr->last = node; + } + hdr->num_elems++; + exit_critical_section(hdr->lock); } void *dequeue(struct queue_hdr *hdr) { - void* retval; - struct queue_node *node; - - enter_critical_section(hdr->lock); - if (hdr->first == NULL ) { - exit_critical_section(hdr->lock); - return NULL ; - } - node = hdr->first; - hdr->first = node->next; // dequeue elem - - retval = node->elem; - free(node); // free what we created in enqueue - hdr->num_elems--; - exit_critical_section(hdr->lock); - - return retval; + void* retval; + struct queue_node *node; + + enter_critical_section(hdr->lock); + if (hdr->first == NULL ) { + exit_critical_section(hdr->lock); + return NULL ; + } + node = hdr->first; + hdr->first = node->next; // dequeue elem + + retval = node->elem; + free(node); // free what we created in enqueue + hdr->num_elems--; + exit_critical_section(hdr->lock); + + return retval; } void* get_elem(struct queue_hdr *hdr, void* target, comparator cmp) { - int result; - struct queue_node *node; - enter_critical_section(hdr->lock); - node = hdr->first; - while (node != NULL ) { - result = cmp(target, node->elem); - if (result) { - exit_critical_section(hdr->lock); - return node->elem; - } else - node = node->next; - } - exit_critical_section(hdr->lock); - return NULL ; + int result; + struct queue_node *node; + enter_critical_section(hdr->lock); + node = hdr->first; + while (node != NULL ) { + result = cmp(target, node->elem); + if (result) { + exit_critical_section(hdr->lock); + return node->elem; + } else + node = node->next; + } + exit_critical_section(hdr->lock); + return NULL ; } void remove_elem(struct queue_hdr *hdr, void* target, comparator cmp) { - struct queue_node *node, *nodeprev; - - enter_critical_section(hdr->lock); - nodeprev = hdr->first; - node = nodeprev; - - while (node != NULL ) { - if (cmp(target, node->elem)) { - /* Is target the first element? */ - if (node == hdr->first) { - hdr->first = node->next; - } - /* Is target the last element? */ - else if (node == hdr->last) { - hdr->last = nodeprev; - nodeprev->next = NULL; - } - /* Else it is in the middle of the list */ - else { - nodeprev->next = node->next; - } - hdr->num_elems--; - free(node); - break; - } - nodeprev = node; - node = node->next; - } - exit_critical_section(hdr->lock); + struct queue_node *node, *nodeprev; + + enter_critical_section(hdr->lock); + nodeprev = hdr->first; + node = nodeprev; + + while (node != NULL ) { + if (cmp(target, node->elem)) { + /* Is target the first element? */ + if (node == hdr->first) { + hdr->first = node->next; + } + /* Is target the last element? */ + else if (node == hdr->last) { + hdr->last = nodeprev; + nodeprev->next = NULL; + } + /* Else it is in the middle of the list */ + else { + nodeprev->next = node->next; + } + hdr->num_elems--; + free(node); + break; + } + nodeprev = node; + node = node->next; + } + exit_critical_section(hdr->lock); } void** get_all_elems(struct queue_hdr *hdr) { - int n = num_elems(hdr); - int i = 0; - struct queue_node *node = hdr->first; - void** retval = calloc(n, sizeof(void *)); - enter_critical_section(hdr->lock); - while (node != NULL ) { - retval[i++] = node->elem; - node = node->next; - } - exit_critical_section(hdr->lock); - return retval; + int n = num_elems(hdr); + int i = 0; + struct queue_node *node = hdr->first; + void** retval = calloc(n, sizeof(void *)); + enter_critical_section(hdr->lock); + while (node != NULL ) { + retval[i++] = node->elem; + node = node->next; + } + exit_critical_section(hdr->lock); + return retval; } int num_elems(struct queue_hdr *hdr) { - int retval = 0; + int retval = 0; - enter_critical_section(hdr->lock); - retval = hdr->num_elems; - exit_critical_section(hdr->lock); + enter_critical_section(hdr->lock); + retval = hdr->num_elems; + exit_critical_section(hdr->lock); - return retval; + return retval; } diff --git a/utils/src/queue.h b/utils/src/queue.h index 6f52df7..2f0bfea 100644 --- a/utils/src/queue.h +++ b/utils/src/queue.h @@ -18,15 +18,15 @@ #include struct queue_node { - void *elem; - struct queue_node *next; + void *elem; + struct queue_node *next; }; struct queue_hdr { - struct queue_node *first; - struct queue_node *last; - struct lock *lock; - int num_elems; + struct queue_node *first; + struct queue_node *last; + struct lock *lock; + int num_elems; }; typedef int (*comparator)(void *target, void *elem); /* returns 1 if target matches From c44783f8d1f20c93032d7b507a959cc1e82c10a4 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Sat, 30 Mar 2013 12:57:58 +0530 Subject: [PATCH 14/18] Changed makefiles, fixed compiler errors in mtestq.c. --- comm/src/makefile | 2 ++ ndmp/src/makefile | 2 ++ utils/src/makefile | 2 ++ utils/src/test/mtestq.c | 24 +++++++++++++----------- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/comm/src/makefile b/comm/src/makefile index 41f4799..b5bd237 100644 --- a/comm/src/makefile +++ b/comm/src/makefile @@ -1,6 +1,7 @@ CFLAGS = -g -I . -I ../../utils/src -DDEBUG all: comm.o worker.o + (cd test; make); comm.o: comm.c comm.h gcc $(CFLAGS) -c comm.c @@ -10,3 +11,4 @@ worker.o: worker.h worker.c comm.h clean: rm *.o + (cd test; make clean); diff --git a/ndmp/src/makefile b/ndmp/src/makefile index f83caad..849e2c8 100644 --- a/ndmp/src/makefile +++ b/ndmp/src/makefile @@ -5,6 +5,7 @@ CFLAGS = -g -I. -I$(COM)/src -I$(UTILS)/src -DDEBUG HEADERS = ndmp.h ndmp_msg.h all: ndmp_xdr.o ndmp_config.o ndmp_connect.o ndmp_msg.o + (cd test; make) ndmp.h: ndmp.x rpcgen ndmp.x @@ -23,3 +24,4 @@ ndmp_msg.o: ndmp_msg.c $(HEADERS) clean: rm *.o ndmp.h ndmp_xdr.c + (cd test; make clean) diff --git a/utils/src/makefile b/utils/src/makefile index 5d0975f..89fe9f5 100644 --- a/utils/src/makefile +++ b/utils/src/makefile @@ -1,5 +1,6 @@ CFLAGS = -g -I . all: queue.o locks.o hexdump.o + (cd test; make) queue.o: queue.h queue.c locks.c gcc $(CFLAGS) -c queue.c @@ -12,3 +13,4 @@ hexdump.o: hexdump.c hexdump.h clean: rm *.o + (cd test; make clean) diff --git a/utils/src/test/mtestq.c b/utils/src/test/mtestq.c index a323320..df8cc90 100644 --- a/utils/src/test/mtestq.c +++ b/utils/src/test/mtestq.c @@ -24,19 +24,10 @@ struct thread_args { void set_up_job_queue(struct queue_hdr* queue, int num_jobs); void check_job_queue(struct queue_hdr* queue, int num_jobs, int num_threads); void *get_jobs(void *queue); -void queue_cmp(void *target, void *elem); +int queue_cmp(void *target, void *elem); void *get_and_remove_jobs(void *args); -int main() -{ - struct queue_hdr *job_queue = init_queue(); - set_up_job_queue(job_queue, 100); - check_job_queue(job_queue, 100, 10); - printf("Multi-threaded enqueue-dequeue test passed\n"); - set_up_job_queue(job_queue, 100); - check_job_removal(job_queue, 100, 10); - printf("Multi-threaded check_job_removal test passed\n"); -} + void add_a_job(struct queue_hdr *job_queue, int i) { @@ -131,3 +122,14 @@ int queue_cmp(void *target, void *elem) { return (*((int *) target) == *((int *) elem)); } + +int main() +{ + struct queue_hdr *job_queue = init_queue(); + set_up_job_queue(job_queue, 100); + check_job_queue(job_queue, 100, 10); + printf("Multi-threaded enqueue-dequeue test passed\n"); + set_up_job_queue(job_queue, 100); + check_job_removal(job_queue, 100, 10); + printf("Multi-threaded check_job_removal test passed\n"); +} From b1ce89c58c324174cdc55f03192af552da8b13b2 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 15 Apr 2013 11:36:12 +0530 Subject: [PATCH 15/18] Data interface backup and recover complete. --- comm/src/comm.c | 1 - ndmp/src/files | 1 + ndmp/src/makefile | 5 +- ndmp/src/ndmp_data.c | 712 ++++++++++++++++++++++++++++++++++++++++ ndmp/src/ndmp_msg.c | 23 +- ndmp/src/ndmp_msg.h | 9 + ndmp/src/test/makefile | 3 +- utils/src/test/mtestq.c | 2 +- 8 files changed, 749 insertions(+), 7 deletions(-) create mode 100644 ndmp/src/ndmp_data.c diff --git a/comm/src/comm.c b/comm/src/comm.c index 7cc4e0f..b85b55a 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -175,7 +175,6 @@ void comm_listen(struct comm_context *ctx) } } - } int accept_all_connections(int listener, fd_set *read_socks, diff --git a/ndmp/src/files b/ndmp/src/files index 16c8ae9..4f9e217 100644 --- a/ndmp/src/files +++ b/ndmp/src/files @@ -1,4 +1,5 @@ makefile +ndmp_data.c ndmp_config.c ndmp_connect.c ndmp.h diff --git a/ndmp/src/makefile b/ndmp/src/makefile index 849e2c8..9f5ea92 100644 --- a/ndmp/src/makefile +++ b/ndmp/src/makefile @@ -4,7 +4,7 @@ UTILS=$(ROOT)/utils CFLAGS = -g -I. -I$(COM)/src -I$(UTILS)/src -DDEBUG HEADERS = ndmp.h ndmp_msg.h -all: ndmp_xdr.o ndmp_config.o ndmp_connect.o ndmp_msg.o +all: ndmp_xdr.o ndmp_config.o ndmp_connect.o ndmp_data.o ndmp_msg.o (cd test; make) ndmp.h: ndmp.x @@ -18,6 +18,9 @@ ndmp_config.o: ndmp_config.c $(HEADERS) ndmp_connect.o: ndmp_connect.c $(HEADERS) gcc $(CFLAGS) -c ndmp_connect.c + +ndmp_data.o: ndmp_data.c $(HEADERS) + gcc $(CFLAGS) -c ndmp_data.c ndmp_msg.o: ndmp_msg.c $(HEADERS) gcc $(CFLAGS) -c ndmp_msg.c diff --git a/ndmp/src/ndmp_data.c b/ndmp/src/ndmp_data.c new file mode 100644 index 0000000..b2d0b58 --- /dev/null +++ b/ndmp/src/ndmp_data.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + * This file is part of glfs-ndmp. + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +struct environment +{ + u_int env_len; + ndmp_pval *env_val; +}; + +struct environment* get_environment() +{ + static struct environment *retval = NULL; + if (retval == NULL ) { + retval = calloc(1, sizeof(struct environment)); + retval->env_len = 0; + retval->env_val = NULL; + } + return retval; +} + +struct environment* init_environment() +{ + struct environment *env = get_environment(); + env->env_len = 0; + env->env_val = NULL; + return env; +} + +ndmp_data_state get_data_state(struct client_txn *txn ) +{ + struct ndmp_session_info *session_info; + session_info = get_session_info(txn->client_session.session_id); + return session_info->data_state; +} + +void set_data_state(struct client_txn *txn , ndmp_data_state new_data_state ) +{ + struct ndmp_session_info *session_info; + session_info = get_session_info(txn->client_session.session_id); + session_info->data_state = new_data_state; +} + +void ndmp_data_get_state(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + +} + +void ndmp_data_start_backup(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* struct ndmp_data_start_backup_request + * { + * string bu_type<>; + * ndmp_pval env<>; + * }; + * + * struct ndmp_data_start_backup_reply + * { + * ndmp_error error; + * }; + * + */ + printf("Printing from the data Start backup \n"); + + static bool mount_done = FALSE ; + struct ndmp_data_start_backup_request request; + struct ndmp_header reply_header; + struct ndmp_data_start_backup_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + struct environment *data_env = get_environment(); + session_info = get_session_info(txn->client_session.session_id); + int i; + + /* We assume that the backup type and env key-value pairs have a + * maximum length of 8 characters, and that the keys and values + * themselves have a maximum length of 64 characters. + */ + + request.bu_type = (char*) malloc(8*sizeof(char)); + request.env.env_len = 8; + request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + data_env->env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + + for (i = 0; i < request.env.env_len; i++) { + request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); + data_env->env_val[i].name = (char*) malloc(64*sizeof(char)); + data_env->env_val[i].value = (char*) malloc(64*sizeof(char)); + } + + printf("before xdr decoding\n "); + xdr_ndmp_data_start_backup_request(request_stream, &request); + printf("after xdr decoding \n"); + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + // checking state + if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + //changing state + session_info->data_state = NDMP_DATA_STATE_ACTIVE; + } + + char full_ip[30]=""; + strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); + + printf("printing full ip : %s \n",full_ip); + + printf("after xdr decoding : Printing from the data Start backup \n"); + + printf("Butype : %s \n",request.bu_type ); + printf("ENV variables \n"); + + + ndmp_pval* env_val = request.env.env_val; + u_long env_len = request.env.env_len; + + data_env->env_len = request.env.env_len; + + for (i = 0; i < env_len; i++){ + strcpy(data_env->env_val[i].name,request.env.env_val[i].name); + strcpy(data_env->env_val[i].value,request.env.env_val[i].value); + } + + char* name_buf; + char* val_buf; + + char *client_path; + char *user_name; + + for( i=0;ireply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_backup_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_start_backup_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_backup_reply, &reply); + + session_info->data_state = NDMP_DATA_STATE_HALTED; + + exit_critical_section(session_info->s_lock); + printf("Exiting data start backup \n "); +} + +void ndmp_data_start_recover(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* struct ndmp_name + * { + * string original_path<>; + * string destination_dir<>; + * string new_name <>; + * string other_name <>; + * ndmp_u_quad node; + * ndmp_u_quad fh_info; + * }; + * + * struct ndmp_data_start_recover_request + * { + * ndmp_pval env<>; + * ndmp_name nlist<>; + * string bu_type<>; + * }; + * struct ndmp_data_start_recover_reply + * { + * ndmp_error error; + * }; + */ + + printf("Printing from the data Start Recovery \n"); + + struct ndmp_data_start_recover_request request; + struct ndmp_header reply_header; + struct ndmp_data_start_recover_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + session_info = get_session_info(txn->client_session.session_id); + int i; + + /* We assume that the backup type and env key-value pairs have a + * maximum length of 8 characters, and that the keys and values + * themselves have a maximum length of 64 characters. + */ + + request.bu_type = (char*) malloc(8*sizeof(char)); + request.env.env_len = 8; + request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + for (i = 0; i < request.env.env_len; i++) { + request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); + } + + request.nlist.nlist_len = 5; + request.nlist.nlist_val = (ndmp_name*)malloc(5*sizeof(ndmp_name) ); + + for (i = 0; i < request.nlist.nlist_len; i++) { + request.nlist.nlist_val[i].original_path = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].destination_dir = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].new_name = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].other_name = (char*) malloc(64*sizeof(char)); + } + + printf("before xdr decoding\n "); + xdr_ndmp_data_start_recover_request(request_stream, &request); + printf("after xdr decoding \n"); + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + //changing state + session_info->data_state = NDMP_DATA_STATE_ACTIVE; + } + + char full_ip[20]=""; + strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); + + ndmp_pval* env_val = request.env.env_val; + u_long env_len = request.env.env_len; + + char* name_buf; + char* val_buf; + + char *client_path; + char *user_name; + + for( i=0;ireply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_recover_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_start_recover_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_recover_reply, &reply); + + session_info->data_state = NDMP_DATA_STATE_HALTED; + + + exit_critical_section(session_info->s_lock); + printf("Exiting data start recover \n "); +} + +void ndmp_data_abort(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + +} + +void ndmp_data_get_env(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_DATA_GET_ENV + * + * no request arguments + * + * struct ndmp_data_get_env_reply + * { + * ndmp_error error; + * ndmp_pval env<>; + * }; + * + */ + + int i; + struct ndmp_header reply_header; + struct ndmp_data_get_env_reply reply; + struct ndmp_session_info *session_info; + struct environment *data_env = get_environment(); + XDR reply_stream; + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); + + printf("Inside get-env's critical section\n"); + + reply.error = NDMP_NO_ERR; + reply.env.env_len = data_env->env_len; + + printf("number of env variables: %d\n", data_env->env_len); + + reply.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + if (session_info-> data_state != NDMP_DATA_STATE_ACTIVE || session_info-> data_state != NDMP_DATA_STATE_HALTED){ + reply.error = NDMP_NO_ERR; + if (data_env->env_len != 0) { + + for (i = 0; i < data_env->env_len; i++) { + reply.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + reply.env.env_val[i].value = (char*) malloc(64*sizeof(char)); + } + + for (i = 0; i < data_env->env_len; i++) { + reply.env.env_val[i].name = data_env->env_val[i].name; + reply.env.env_val[i].value = data_env->env_val[i].value; + + printf("reply.env.env_val[i].name = %s\n reply.env.env_val[i].value = %s\n\n", + reply.env.env_val[i].name, reply.env.env_val[i].value); + } + } + else + reply.env.env_val = NULL; + } + else + reply.error = NDMP_ILLEGAL_STATE_ERR; + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_get_env_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_get_env_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_get_env_reply, &reply); + + exit_critical_section(session_info->s_lock); +} + +void ndmp_data_stop(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_DATA_STOP + * + * no request arguments + * + * struct ndmp_data_stop_reply + * { + * ndmp_error error; + * }; + * + */ + + struct ndmp_header reply_header; + struct ndmp_data_stop_reply reply; + struct ndmp_session_info *session_info; + struct environment* data_env = get_environment(); + + XDR reply_stream; + + session_info = get_session_info(txn->client_session.session_id); + enter_critical_section(session_info->s_lock); + + if (session_info-> data_state != NDMP_DATA_STATE_HALTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + session_info->data_state = NDMP_DATA_STATE_IDLE; + data_env = init_environment(); + reply.error = NDMP_NO_ERR; + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_stop_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_stop_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_stop_reply, &reply); + + exit_critical_section(session_info->s_lock); + + printf("Data state: %d\n",session_info->data_state); + +} + +void ndmp_data_listen(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_DATA_LISTEN + * + * struct ndmp_tcp_addr + * { + * u_long ip_addr; + * u_short port; + * }; + * + * struct ndmp_fc_addr + * { + * u_long loop_id; + * }; + * + * struct ndmp_ipc_addr + * { + * opaque comm_data<>; + * }; + * + * union ndmp_addr switch (ndmp_addr_type addr_type) + * { + * case NDMP_ADDR_LOCAL: + * void; + * case NDMP_ADDR_TCP: + * ndmp_tcp_addr tcp_addr; + * case NDMP_ADDR_FC: + * ndmp_fc_addr fc_addr; + * case NDMP_ADDR_IPC: + * ndmp_ipc_addr ipc_addr; + * }; + * + * struct ndmp_data_listen_request + * { + * ndmp_addr_type addr_type; + * }; + * + * struct ndmp_data_listen_reply + * { + * ndmp_error error; + * ndmp_addr data_connection_addr; + * }; + */ + + struct ndmp_data_listen_request request; + struct ndmp_header reply_header; + struct ndmp_data_listen_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + xdr_ndmp_data_listen_request(request_stream, &request); + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + if (session_info-> data_state != NDMP_DATA_STATE_IDLE){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else{ + if(request.addr_type== NDMP_ADDR_LOCAL ){ + session_info->data_state = NDMP_DATA_STATE_CONNECTED; + // change the state to connected + reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL; + // reply.data_connection_addr.ndmp_addr_u = NULL; + } + else{ + // send illegal argument err + reply.error = NDMP_ILLEGAL_ARGS_ERR ; + } + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_listen_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_listen_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_listen_reply, &reply); + + exit_critical_section(session_info->s_lock); + +} + +void ndmp_data_connect(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_DATA_CONNECT + * struct ndmp_data_connect_request + * { + * ndmp_addr addr; + * }; + * + * struct ndmp_data_connect_reply + * { + * ndmp_error error; + * }; + */ + + struct ndmp_data_connect_request request; + struct ndmp_header reply_header; + struct ndmp_data_connect_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + xdr_ndmp_data_connect_request(request_stream, &request); + + printf("Printing from the data connect open \n"); + printf("Request message received : \ + addr_type : %d \n ",request.addr.addr_type); + + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + if (session_info-> data_state != NDMP_DATA_STATE_IDLE ){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else{ + if(request.addr.addr_type== NDMP_ADDR_LOCAL ){ + session_info->data_state = NDMP_DATA_STATE_CONNECTED; + // change the state to connected + } + + else{ + // send illegal argument err + reply.error = NDMP_ILLEGAL_ARGS_ERR ; + } + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_connect_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_connect_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_connect_reply, &reply); + + exit_critical_section(session_info->s_lock); +} diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c index 89b42a5..6994e6a 100644 --- a/ndmp/src/ndmp_msg.c +++ b/ndmp/src/ndmp_msg.c @@ -16,6 +16,7 @@ int session_info_cmp (void *id, void *session); int job_cmp(void *target, void*elem); void add_job_to_session(struct client_txn *txn); struct queue_hdr* get_session_queue() ; + /* * xdr_decode_encode is the entry point * and callback method for the comm layer @@ -109,6 +110,22 @@ ndmp_message_handler ndmp_dispatch(int message) { return ndmp_config_get_scsi_info; case 0x108: return ndmp_config_get_server_info; + case 0x400: + return ndmp_data_get_state; + case 0x401: + return ndmp_data_start_backup; + case 0x402: + return ndmp_data_start_recover; + case 0x403: + return ndmp_data_abort; + case 0x404: + return ndmp_data_get_env; + case 0x407: + return ndmp_data_stop; + case 0x409: + return ndmp_data_listen; + case 0x40A: + return ndmp_data_connect; default: return ndmp_error_message; } @@ -210,7 +227,7 @@ struct ndmp_session_info* get_session_info(int session_id) { struct lock *s_lock = get_lock(); /* - * This functon returns the ndmp_session_info + * This function returns the ndmp_session_info * struct. The ndmp_session_info structs are in * a queue, keyed by session_id. The states are * owned and managed by the caller(s). The queue @@ -242,8 +259,8 @@ struct ndmp_session_info* get_session_info(int session_id) { sizeof(struct ndmp_session_info)); retval->session_id = session_id; retval->connection_state = LISTEN; - retval->data_state = LISTEN; - retval->mover_state = LISTEN; + retval->data_state = IDLE; + retval->mover_state = IDLE; retval->s_lock = get_lock(); retval->jobs = init_queue(); retval->is_terminated = 0; diff --git a/ndmp/src/ndmp_msg.h b/ndmp/src/ndmp_msg.h index e3655a3..6d59c6c 100644 --- a/ndmp/src/ndmp_msg.h +++ b/ndmp/src/ndmp_msg.h @@ -114,5 +114,14 @@ void ndmp_config_get_fs_info(struct client_txn *, struct ndmp_header, XDR*); void ndmp_config_get_tape_info(struct client_txn *, struct ndmp_header, XDR*); void ndmp_config_get_scsi_info(struct client_txn *, struct ndmp_header, XDR*); void ndmp_config_get_server_info(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_get_state(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_start_backup(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_start_recover(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_abort(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_get_env(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_stop(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_listen(struct client_txn *, struct ndmp_header, XDR*); +void ndmp_data_connect(struct client_txn *, struct ndmp_header, XDR*); void ndmp_error_message(struct client_txn *, struct ndmp_header, XDR *); // For wrong message type + #endif diff --git a/ndmp/src/test/makefile b/ndmp/src/test/makefile index 88b6db9..4cd12a7 100644 --- a/ndmp/src/test/makefile +++ b/ndmp/src/test/makefile @@ -11,6 +11,7 @@ SRC = testndmp.c CFLAGS = -g -I $(ROOT)/comm/src -I $(ROOT)/ndmp/src -I $(ROOT)/utils/src -DDEBUG LIBS = -lpthread OBJS = $(ROOT)/ndmp/src/ndmp_connect.o \ + $(ROOT)/ndmp/src/ndmp_data.o \ $(ROOT)/ndmp/src/ndmp_msg.o \ $(ROOT)/ndmp/src/ndmp_config.o \ $(ROOT)/ndmp/src/ndmp_xdr.o \ @@ -26,4 +27,4 @@ testndmp: gcc $(CFLAGS) -o testndmp testndmp.o $(OBJS) $(LIBS) clean: - rm *.o testndmp + rm *.o testndmp \ No newline at end of file diff --git a/utils/src/test/mtestq.c b/utils/src/test/mtestq.c index df8cc90..6359fee 100644 --- a/utils/src/test/mtestq.c +++ b/utils/src/test/mtestq.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include "queue.h" #include static struct lock *num_lock; From b231df30938d00082d2418575096252d5f8b634c Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 15 Apr 2013 12:46:36 +0530 Subject: [PATCH 16/18] Added debug statements. --- ndmp/src/ndmp_data.c | 127 ++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 37 deletions(-) diff --git a/ndmp/src/ndmp_data.c b/ndmp/src/ndmp_data.c index b2d0b58..6ac8cda 100644 --- a/ndmp/src/ndmp_data.c +++ b/ndmp/src/ndmp_data.c @@ -72,8 +72,9 @@ void ndmp_data_start_backup(struct client_txn *txn, * }; * */ +#ifdef DEBUG printf("Printing from the data Start backup \n"); - +#endif static bool mount_done = FALSE ; struct ndmp_data_start_backup_request request; struct ndmp_header reply_header; @@ -101,10 +102,13 @@ void ndmp_data_start_backup(struct client_txn *txn, data_env->env_val[i].name = (char*) malloc(64*sizeof(char)); data_env->env_val[i].value = (char*) malloc(64*sizeof(char)); } - +#ifdef DEBUG printf("before xdr decoding\n "); +#endif xdr_ndmp_data_start_backup_request(request_stream, &request); +#ifdef DEBUG printf("after xdr decoding \n"); +#endif enter_critical_section(session_info->s_lock); reply.error = NDMP_NO_ERR; @@ -119,14 +123,14 @@ void ndmp_data_start_backup(struct client_txn *txn, char full_ip[30]=""; strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); - +#ifdef DEBUG printf("printing full ip : %s \n",full_ip); printf("after xdr decoding : Printing from the data Start backup \n"); printf("Butype : %s \n",request.bu_type ); printf("ENV variables \n"); - +#endif ndmp_pval* env_val = request.env.env_val; u_long env_len = request.env.env_len; @@ -168,12 +172,11 @@ void ndmp_data_start_backup(struct client_txn *txn, char vol_name[20]; printf("enter the volume name : "); scanf("%s",vol_name ); - +#ifdef DEBUG printf("printing volume name 11 : %s \n", vol_name); - // create mount point dir printf("creating the mounting dir \n"); - +#endif char *mount_point; mount_point = (char*) malloc(16 * sizeof(char)); // char mount_point[300]; @@ -181,7 +184,7 @@ void ndmp_data_start_backup(struct client_txn *txn, mount_point = (char*) realloc ( mount_point,strlen(mount_point) + strlen(full_ip) + strlen(client_path) +1 ); strcat(mount_point,full_ip); strcat(mount_point,client_path); - // mount point doesnot has / at the end + // mount point does not has / at the end char *dir_instr; dir_instr = (char*) malloc( 11 * sizeof(char)); @@ -189,9 +192,9 @@ void ndmp_data_start_backup(struct client_txn *txn, strcpy(dir_instr,"mkdir -p "); dir_instr = (char*) realloc(dir_instr,strlen(dir_instr) + strlen(mount_point)+1); strcat(dir_instr,mount_point); - +#ifdef DEBUG printf("\nprinting mount instr $ %s \n",dir_instr); - +#endif if(system(dir_instr) <0){ printf("mount point creation failed or already exists \n"); } @@ -201,17 +204,14 @@ void ndmp_data_start_backup(struct client_txn *txn, //char mount_instr[400]; strcpy(mount_instr,"mount -t glusterfs "); mount_instr = (char*) realloc( mount_instr , strlen(mount_instr) + 17+ strlen(vol_name) + strlen(mount_point)); - strcat(mount_instr,"10.70.1.93:/"); + strcat(mount_instr,"10.70.1.93:/"); //where to mount, currently ajeet's laptop strcat(mount_instr,vol_name); strcat(mount_instr," "); strcat(mount_instr,mount_point); - +#ifdef DEBUG printf("printing volume name 1 : %s \n ",vol_name ); - - - printf("\nprinting mount instr $ %s \n",mount_instr); - +#endif if(mount_done == FALSE ){ if(system(mount_instr) <0){ printf("failed : mount volume \n"); @@ -233,9 +233,9 @@ void ndmp_data_start_backup(struct client_txn *txn, strcat(rsync_instr, client_path); strcat(rsync_instr,"/ "); strcat(rsync_instr,mount_point); - +#ifdef DEBUG printf("printing rsync instr $ %s \n",rsync_instr); - +#endif if(system(rsync_instr) <0){ printf("failed : rsync \n"); return; @@ -255,7 +255,9 @@ void ndmp_data_start_backup(struct client_txn *txn, session_info->data_state = NDMP_DATA_STATE_HALTED; exit_critical_section(session_info->s_lock); +#ifdef DEBUG printf("Exiting data start backup \n "); +#endif } void ndmp_data_start_recover(struct client_txn *txn, @@ -282,9 +284,9 @@ void ndmp_data_start_recover(struct client_txn *txn, * ndmp_error error; * }; */ - +#ifdef DEBUG printf("Printing from the data Start Recovery \n"); - +#endif struct ndmp_data_start_recover_request request; struct ndmp_header reply_header; struct ndmp_data_start_recover_reply reply; @@ -317,10 +319,13 @@ void ndmp_data_start_recover(struct client_txn *txn, request.nlist.nlist_val[i].new_name = (char*) malloc(64*sizeof(char)); request.nlist.nlist_val[i].other_name = (char*) malloc(64*sizeof(char)); } - +#ifdef DEBUG printf("before xdr decoding\n "); +#endif xdr_ndmp_data_start_recover_request(request_stream, &request); +#ifdef DEBUG printf("after xdr decoding \n"); +#endif enter_critical_section(session_info->s_lock); reply.error = NDMP_NO_ERR; @@ -349,9 +354,9 @@ void ndmp_data_start_recover(struct client_txn *txn, val_buf = (char*)malloc(strlen(env_val[i].value)+1); strcpy(name_buf,env_val[i].name); strcpy(val_buf,env_val[i].value); - +#ifdef DEBUG printf("\nname : %s \nvalue : %s \n\n",name_buf,val_buf); - +#endif if(strcmp(env_val[i].name,"FILESYSTEM") ==0 ) { client_path = (char*) malloc (strlen(env_val[i].value) +1 ); strcpy(client_path,env_val[i].value); @@ -362,10 +367,10 @@ void ndmp_data_start_recover(struct client_txn *txn, } } - +#ifdef DEBUG // obtaining mount point dir printf("obtaining the dir/file to recover \n"); - +#endif char *mount_point; mount_point = (char*) malloc(16*sizeof(char) ); //char mount_point[300]; @@ -393,9 +398,9 @@ void ndmp_data_start_recover(struct client_txn *txn, strcat(rsync_instr,":"); strcat(rsync_instr, request.nlist.nlist_val[0].destination_dir); //strcat(rsync_instr,"/"); - +#ifdef DEBUG printf("printing rsync instr $ %s \n",rsync_instr); - +#endif if(system(rsync_instr) <0){ printf("failed : rsync \n"); return; @@ -417,12 +422,64 @@ void ndmp_data_start_recover(struct client_txn *txn, exit_critical_section(session_info->s_lock); +#ifdef DEBUG printf("Exiting data start recover \n "); +#endif } void ndmp_data_abort(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { + /* NDMP_DATA_ABORT + * + * no request arguments + * + * struct ndmp_data_abort_reply + * { + * ndmp_error error; + * }; + * + */ + + struct ndmp_header reply_header; + struct ndmp_data_abort_reply reply; + struct ndmp_session_info *session_info; + + XDR reply_stream; + + session_info = get_session_info(txn->client_session.session_id); + enter_critical_section(session_info->s_lock); + + if (session_info-> data_state == NDMP_DATA_STATE_HALTED || session_info-> data_state == NDMP_DATA_STATE_IDLE){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + session_info->data_state = NDMP_DATA_STATE_HALTED; + reply.error = NDMP_NO_ERR; + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_abort_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_abort_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_abort_reply, &reply); + + exit_critical_section(session_info->s_lock); +#ifdef DEBUG + printf("Data state: %d\n",session_info->data_state); +#endif } @@ -451,13 +508,9 @@ void ndmp_data_get_env(struct client_txn *txn, enter_critical_section(session_info->s_lock); - printf("Inside get-env's critical section\n"); - reply.error = NDMP_NO_ERR; reply.env.env_len = data_env->env_len; - printf("number of env variables: %d\n", data_env->env_len); - reply.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); if (session_info-> data_state != NDMP_DATA_STATE_ACTIVE || session_info-> data_state != NDMP_DATA_STATE_HALTED){ @@ -556,9 +609,9 @@ void ndmp_data_stop(struct client_txn *txn, xdr_ndmp_data_stop_reply, &reply); exit_critical_section(session_info->s_lock); - +#ifdef DEBUG printf("Data state: %d\n",session_info->data_state); - +#endif } void ndmp_data_listen(struct client_txn *txn, @@ -623,8 +676,8 @@ void ndmp_data_listen(struct client_txn *txn, } else{ if(request.addr_type== NDMP_ADDR_LOCAL ){ - session_info->data_state = NDMP_DATA_STATE_CONNECTED; - // change the state to connected + session_info->data_state = NDMP_DATA_STATE_LISTEN; + // change the state to listen reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL; // reply.data_connection_addr.ndmp_addr_u = NULL; } @@ -671,11 +724,11 @@ void ndmp_data_connect(struct client_txn *txn, struct ndmp_header header, XDR* r XDR reply_stream; xdr_ndmp_data_connect_request(request_stream, &request); - +#ifdef DEBUG printf("Printing from the data connect open \n"); printf("Request message received : \ addr_type : %d \n ",request.addr.addr_type); - +#endif session_info = get_session_info(txn->client_session.session_id); enter_critical_section(session_info->s_lock); From c9bc76d94757c50c9683855b22105d2e05f7f722 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 15 Apr 2013 12:47:09 +0530 Subject: [PATCH 17/18] Added debug statements. --- ndmp/src/ndmp_config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c index 7a9e911..7b676d5 100644 --- a/ndmp/src/ndmp_config.c +++ b/ndmp/src/ndmp_config.c @@ -152,7 +152,6 @@ void ndmp_config_get_connection_type(struct client_txn *txn, struct ndmp_header txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_config_get_connection_type_reply, &reply); - } void ndmp_config_get_auth_attr(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) @@ -709,7 +708,7 @@ struct ndmp_config_get_scsi_info_reply* alloc_scsi_info() { * We will assume max of 16 name-value properties for each * device, which should also be plenty. * These assumptions simplify getting scsi information - * and setting them in struct ndmp_config_get_scsi_info_repy + * and setting them in struct ndmp_config_get_scsi_info_reply * especially having to set info_len attribute and capability_len * attributes. It would require a two pass traversal of scsi device * info, otherwise. From 0aea2caf80a195c3b13919f560c137cbc2e3ef87 Mon Sep 17 00:00:00 2001 From: shrinidhihudli Date: Mon, 22 Apr 2013 16:02:52 +0530 Subject: [PATCH 18/18] Review commit The overall structure of the project looks like this: The NDMP server is split into different components, represented as subdirectories of ndmp, which are currently 1. comm 2. docs 3. ndmp 4. utils In each component the source code is in a src directory. Each component has makefiles for easy execution. comm is reponsible for actual client-server communicationndmp is responsible for the ndmp server responses to client requests. ndmp consists of xdr management as well. utils provides thread-safe queues and hex dumps. docs provides program documentation. comm comm/src/comm.c, comm/src/comm.h: Structures and functions for listening and management of client connections/requests. Currently listens for connections from multiple clients. New connections are added to a list of sessions. Requests from connected clients are enqueued into a job queue. comm/src/worker.c, comm/src/worker.h: Thread creation, shutdown, running jobs from request queue, and processing jobs from response queue. ndmp ndmp/src/ndmp.x: Contains ndmp structures that the NDMP protocol uses. We use rpcgen to generate C structures and the routines for XDR marshaling and unmarshaling. These are contained in ndmp.h and ndmp_xdr.c respectively. ndmp/src/ndmp_config.c: Contains functions for responses to NDMP config client requests. ndmp/src/ndmp_connect.c: Contains functions for responses to NDMP connect client requests. ndmp/src/ndmp_data.c: Contains functions for responses to NDMP config data requests. ndmp/src/ndmp_msg.c, ndmp/src/ndmp_msg.h: Structures and functions for XDR message handling and session management. It contains session states and session queues. utils utils/src/hexdump.c, utils/sec/hexdump.h: Hexdump utility. utils/src/locks.c, utils/src/locks.h: Provides mutex locks to make queues thread-safe. utils/src/queue.c, utils/src/queue.h: Thread-safe queue implementation. Each queue has its own lock. Two queues are used by comm - request_jobs, for client requests and response_jobs, for server responses. --- comm/src/comm.c | 10 +- comm/src/comm.h | 5 + comm/src/makefile | 10 + comm/src/test/makefile | 14 +- comm/src/test/testcomm.c | 5 + comm/src/worker.c | 5 + comm/src/worker.h | 5 + {DOCS => docs}/CollegeProjectSynopsis.pdf | Bin docs/client_input_sample | 21 + {DOCS => docs}/ndmp_draft_v3_0.doc | 0 ndmp/src/makefile | 10 + ndmp/src/ndmp_config.c | 5 + ndmp/src/ndmp_data.c | 1274 +++++++++++---------- ndmp/src/ndmp_msg.h | 5 + ndmp/src/test/makefile | 3 + utils/src/hexdump.c | 5 + utils/src/hexdump.h | 5 + utils/src/locks.c | 5 + utils/src/locks.h | 5 + utils/src/makefile | 10 + utils/src/queue.c | 5 + utils/src/queue.h | 5 + utils/src/test/makefile | 4 + 23 files changed, 782 insertions(+), 634 deletions(-) rename {DOCS => docs}/CollegeProjectSynopsis.pdf (100%) create mode 100644 docs/client_input_sample rename {DOCS => docs}/ndmp_draft_v3_0.doc (100%) diff --git a/comm/src/comm.c b/comm/src/comm.c index b85b55a..ed32f89 100644 --- a/comm/src/comm.c +++ b/comm/src/comm.c @@ -7,11 +7,16 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include #include /* - * comm_int: + * comm_context: * Creates a comm_context structure * which is the anchor structure that * holds the session structures for all @@ -35,7 +40,6 @@ struct comm_context* comm_context() } /* - * * create_listener * creates a listener socket to listen on specified port and * returns the socket to the caller @@ -61,7 +65,7 @@ int create_listener(int port) { retval = socket(AF_INET, SOCK_STREAM, 0); setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); - fcntl(retval, F_SETFL, O_NONBLOCK); + // fcntl(retval, F_SETFL, O_NONBLOCK); if (bind(retval, (struct sockaddr *) &listener, sizeof(struct sockaddr_in)) == -1) errExit("Error:bind"); diff --git a/comm/src/comm.h b/comm/src/comm.h index 0110837..88a3a19 100644 --- a/comm/src/comm.h +++ b/comm/src/comm.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #ifndef __H__COMM__ #define __H__COMM__ diff --git a/comm/src/makefile b/comm/src/makefile index b5bd237..e6dced7 100644 --- a/comm/src/makefile +++ b/comm/src/makefile @@ -1,3 +1,13 @@ +# Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com +# This file is part of glfs-ndmp. +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. + +# This file and its components written by Shrinidhi +# unless otherwise specified. + CFLAGS = -g -I . -I ../../utils/src -DDEBUG all: comm.o worker.o diff --git a/comm/src/test/makefile b/comm/src/test/makefile index ebddd41..e01f0c3 100644 --- a/comm/src/test/makefile +++ b/comm/src/test/makefile @@ -1,10 +1,12 @@ - # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com - # This file is part of glfs-ndmp. - # This file is licensed to you under your choice of the GNU Lesser - # General Public License, version 3 or any later version (LGPLv3 or - # later), or the GNU General Public License, version 2 (GPLv2), in all - # cases as published by the Free Software Foundation. +# Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com +# This file is part of glfs-ndmp. +# This file is licensed to you under your choice of the GNU Lesser +# General Public License, version 3 or any later version (LGPLv3 or +# later), or the GNU General Public License, version 2 (GPLv2), in all +# cases as published by the Free Software Foundation. +# This file and its components written by Shrinidhi +# unless otherwise specified. SRC = testhexdump.c ../hexdump.c OBJS = testhexdump.o hexdump.o diff --git a/comm/src/test/testcomm.c b/comm/src/test/testcomm.c index 77359c7..35e7c9b 100644 --- a/comm/src/test/testcomm.c +++ b/comm/src/test/testcomm.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include #include #include diff --git a/comm/src/worker.c b/comm/src/worker.c index b930995..67e0a41 100644 --- a/comm/src/worker.c +++ b/comm/src/worker.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include #include diff --git a/comm/src/worker.h b/comm/src/worker.h index 1bbd1d3..9762532 100644 --- a/comm/src/worker.h +++ b/comm/src/worker.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #ifndef __H_WORKER__ #define __H_WORKER__ diff --git a/DOCS/CollegeProjectSynopsis.pdf b/docs/CollegeProjectSynopsis.pdf similarity index 100% rename from DOCS/CollegeProjectSynopsis.pdf rename to docs/CollegeProjectSynopsis.pdf diff --git a/docs/client_input_sample b/docs/client_input_sample new file mode 100644 index 0000000..9bb1b31 --- /dev/null +++ b/docs/client_input_sample @@ -0,0 +1,21 @@ +connect_open + +data_connect local +add_env FILESYSTEM /mnt/bu_point/gl_vol_1 +add_env USER root +data_start_backup dump + +add_nlist /test /mnt/recover_bu/gl_vol_1 fh_info node new_name other_name +data_start_recover dump + +data_stop + + +config_get_host_info +config_get_connection_type +config_get_auth_attr none|text|md5 +config_get_butype_info +config_get_fs_info +config_get_tape_info +config_get_scsi_info +config_get_server_info diff --git a/DOCS/ndmp_draft_v3_0.doc b/docs/ndmp_draft_v3_0.doc similarity index 100% rename from DOCS/ndmp_draft_v3_0.doc rename to docs/ndmp_draft_v3_0.doc diff --git a/ndmp/src/makefile b/ndmp/src/makefile index 9f5ea92..c578f21 100644 --- a/ndmp/src/makefile +++ b/ndmp/src/makefile @@ -1,3 +1,13 @@ + # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + # This file is part of glfs-ndmp. + # This file is licensed to you under your choice of the GNU Lesser + # General Public License, version 3 or any later version (LGPLv3 or + # later), or the GNU General Public License, version 2 (GPLv2), in all + # cases as published by the Free Software Foundation. + + # This file and its components written by Shrinidhi + # unless specified otherwise. + ROOT=../.. COM=$(ROOT)/comm UTILS=$(ROOT)/utils diff --git a/ndmp/src/ndmp_config.c b/ndmp/src/ndmp_config.c index 7b676d5..32d3c9f 100644 --- a/ndmp/src/ndmp_config.c +++ b/ndmp/src/ndmp_config.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its functions written by Shrinidhi + * unless otherwise specified. + */ + #include #include #include diff --git a/ndmp/src/ndmp_data.c b/ndmp/src/ndmp_data.c index 6ac8cda..22d3b3c 100644 --- a/ndmp/src/ndmp_data.c +++ b/ndmp/src/ndmp_data.c @@ -14,27 +14,27 @@ struct environment { - u_int env_len; - ndmp_pval *env_val; + u_int env_len; + ndmp_pval *env_val; }; struct environment* get_environment() { - static struct environment *retval = NULL; - if (retval == NULL ) { - retval = calloc(1, sizeof(struct environment)); - retval->env_len = 0; - retval->env_val = NULL; - } + static struct environment *retval = NULL; + if (retval == NULL ) { + retval = calloc(1, sizeof(struct environment)); + retval->env_len = 0; + retval->env_val = NULL; + } return retval; } struct environment* init_environment() { - struct environment *env = get_environment(); - env->env_len = 0; - env->env_val = NULL; - return env; + struct environment *env = get_environment(); + env->env_len = 0; + env->env_val = NULL; + return env; } ndmp_data_state get_data_state(struct client_txn *txn ) @@ -57,709 +57,733 @@ void ndmp_data_get_state(struct client_txn *txn, } -void ndmp_data_start_backup(struct client_txn *txn, +void ndmp_data_listen(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* struct ndmp_data_start_backup_request - * { - * string bu_type<>; - * ndmp_pval env<>; - * }; - * - * struct ndmp_data_start_backup_reply - * { - * ndmp_error error; - * }; - * - */ -#ifdef DEBUG - printf("Printing from the data Start backup \n"); -#endif - static bool mount_done = FALSE ; - struct ndmp_data_start_backup_request request; - struct ndmp_header reply_header; - struct ndmp_data_start_backup_reply reply; - struct ndmp_session_info *session_info; - XDR reply_stream; - struct environment *data_env = get_environment(); - session_info = get_session_info(txn->client_session.session_id); - int i; - - /* We assume that the backup type and env key-value pairs have a - * maximum length of 8 characters, and that the keys and values - * themselves have a maximum length of 64 characters. - */ - - request.bu_type = (char*) malloc(8*sizeof(char)); - request.env.env_len = 8; - request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); - data_env->env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); - - - for (i = 0; i < request.env.env_len; i++) { - request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); - request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); - data_env->env_val[i].name = (char*) malloc(64*sizeof(char)); - data_env->env_val[i].value = (char*) malloc(64*sizeof(char)); - } -#ifdef DEBUG - printf("before xdr decoding\n "); -#endif - xdr_ndmp_data_start_backup_request(request_stream, &request); -#ifdef DEBUG - printf("after xdr decoding \n"); -#endif - enter_critical_section(session_info->s_lock); - reply.error = NDMP_NO_ERR; - - // checking state - if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else { - //changing state - session_info->data_state = NDMP_DATA_STATE_ACTIVE; - } - - char full_ip[30]=""; - strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); -#ifdef DEBUG - printf("printing full ip : %s \n",full_ip); + /* NDMP_DATA_LISTEN + * + * struct ndmp_tcp_addr + * { + * u_long ip_addr; + * u_short port; + * }; + * + * struct ndmp_fc_addr + * { + * u_long loop_id; + * }; + * + * struct ndmp_ipc_addr + * { + * opaque comm_data<>; + * }; + * + * union ndmp_addr switch (ndmp_addr_type addr_type) + * { + * case NDMP_ADDR_LOCAL: + * void; + * case NDMP_ADDR_TCP: + * ndmp_tcp_addr tcp_addr; + * case NDMP_ADDR_FC: + * ndmp_fc_addr fc_addr; + * case NDMP_ADDR_IPC: + * ndmp_ipc_addr ipc_addr; + * }; + * + * struct ndmp_data_listen_request + * { + * ndmp_addr_type addr_type; + * }; + * + * struct ndmp_data_listen_reply + * { + * ndmp_error error; + * ndmp_addr data_connection_addr; + * }; + */ - printf("after xdr decoding : Printing from the data Start backup \n"); + struct ndmp_data_listen_request request; + struct ndmp_header reply_header; + struct ndmp_data_listen_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; - printf("Butype : %s \n",request.bu_type ); - printf("ENV variables \n"); -#endif + xdr_ndmp_data_listen_request(request_stream, &request); + session_info = get_session_info(txn->client_session.session_id); - ndmp_pval* env_val = request.env.env_val; - u_long env_len = request.env.env_len; + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; - data_env->env_len = request.env.env_len; + if (session_info-> data_state != NDMP_DATA_STATE_IDLE){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else{ + if(request.addr_type== NDMP_ADDR_LOCAL ){ + session_info->data_state = NDMP_DATA_STATE_LISTEN; + // change the state to listen + reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL; + // reply.data_connection_addr.ndmp_addr_u = NULL; + } + else{ + // send illegal argument err + reply.error = NDMP_ILLEGAL_ARGS_ERR ; + } + } - for (i = 0; i < env_len; i++){ - strcpy(data_env->env_val[i].name,request.env.env_val[i].name); - strcpy(data_env->env_val[i].value,request.env.env_val[i].value); - } + set_header(header, &reply_header, reply.error); - char* name_buf; - char* val_buf; + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_listen_reply, &reply); - char *client_path; - char *user_name; + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); - for( i=0;ireply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_listen_reply, &reply); - printf("\nname : %s \nvalue : %s \n\n",name_buf,val_buf); + exit_critical_section(session_info->s_lock); - if(strcmp(env_val[i].name,"FILESYSTEM") ==0 ) { - client_path = (char*) malloc (strlen(env_val[i].value) +1 ); - strcpy(client_path,env_val[i].value); - } - if(strcmp(env_val[i].name,"USER")==0){ - user_name = (char*) malloc (strlen( env_val[i].value ) +1 ); - strcpy(user_name,env_val[i].value); - } +} +void ndmp_data_connect(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +{ + /* NDMP_DATA_CONNECT + * struct ndmp_data_connect_request + * { + * ndmp_addr addr; + * }; + * + * struct ndmp_data_connect_reply + * { + * ndmp_error error; + * }; + */ + + struct ndmp_data_connect_request request; + struct ndmp_header reply_header; + struct ndmp_data_connect_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; - } + xdr_ndmp_data_connect_request(request_stream, &request); - // get volume name, assuming volume name less than 20 - char vol_name[20]; - printf("enter the volume name : "); - scanf("%s",vol_name ); #ifdef DEBUG - printf("printing volume name 11 : %s \n", vol_name); - // create mount point dir - printf("creating the mounting dir \n"); + printf("Printing from the data connect open \n"); + printf("Request message received : \ + addr_type : %d \n ",request.addr.addr_type); #endif - char *mount_point; - mount_point = (char*) malloc(16 * sizeof(char)); - // char mount_point[300]; - strcpy(mount_point,"/mnt/backedup2/"); - mount_point = (char*) realloc ( mount_point,strlen(mount_point) + strlen(full_ip) + strlen(client_path) +1 ); - strcat(mount_point,full_ip); - strcat(mount_point,client_path); - // mount point does not has / at the end - - char *dir_instr; - dir_instr = (char*) malloc( 11 * sizeof(char)); - //char dir_instr[400]; - strcpy(dir_instr,"mkdir -p "); - dir_instr = (char*) realloc(dir_instr,strlen(dir_instr) + strlen(mount_point)+1); - strcat(dir_instr,mount_point); + + session_info = get_session_info(txn->client_session.session_id); + + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + if (session_info-> data_state != NDMP_DATA_STATE_IDLE ){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else{ + if(request.addr.addr_type== NDMP_ADDR_LOCAL ){ + session_info->data_state = NDMP_DATA_STATE_CONNECTED; + // change the state to connected + } + else{ + // send illegal argument err + reply.error = NDMP_ILLEGAL_ARGS_ERR ; + } + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_connect_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_connect_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_connect_reply, &reply); + + exit_critical_section(session_info->s_lock); +} + +void ndmp_data_start_backup(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) +{ + /* struct ndmp_data_start_backup_request + * { + * string bu_type<>; + * ndmp_pval env<>; + * }; + * + * struct ndmp_data_start_backup_reply + * { + * ndmp_error error; + * }; + * + */ + + static bool mount_done = FALSE ; + struct ndmp_data_start_backup_request request; + struct ndmp_header reply_header; + struct ndmp_data_start_backup_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + struct environment *data_env = get_environment(); + session_info = get_session_info(txn->client_session.session_id); + int i; + + /* We assume that the backup type and env key-value pairs have a + * maximum length of 8 characters, and that the keys and values + * themselves have a maximum length of 64 characters. + */ + + request.bu_type = (char*) malloc(8*sizeof(char)); + request.env.env_len = 8; + request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + data_env->env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + for (i = 0; i < request.env.env_len; i++) { + request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); + data_env->env_val[i].name = (char*) malloc(64*sizeof(char)); + data_env->env_val[i].value = (char*) malloc(64*sizeof(char)); + } + + xdr_ndmp_data_start_backup_request(request_stream, &request); + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + // checking state + if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + //changing state + session_info->data_state = NDMP_DATA_STATE_ACTIVE; + } + + char full_ip[30]=""; + strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); + #ifdef DEBUG - printf("\nprinting mount instr $ %s \n",dir_instr); + printf("Butype : %s \n",request.bu_type ); + printf("ENV variables \n"); #endif - if(system(dir_instr) <0){ - printf("mount point creation failed or already exists \n"); - } - - char *mount_instr; - mount_instr=(char*) malloc( 21 * sizeof(char ) ); - //char mount_instr[400]; - strcpy(mount_instr,"mount -t glusterfs "); - mount_instr = (char*) realloc( mount_instr , strlen(mount_instr) + 17+ strlen(vol_name) + strlen(mount_point)); - strcat(mount_instr,"10.70.1.93:/"); //where to mount, currently ajeet's laptop - strcat(mount_instr,vol_name); - strcat(mount_instr," "); - strcat(mount_instr,mount_point); + + ndmp_pval* env_val = request.env.env_val; + u_long env_len = request.env.env_len; + + data_env->env_len = request.env.env_len; + + for (i = 0; i < env_len; i++){ + strcpy(data_env->env_val[i].name,request.env.env_val[i].name); + strcpy(data_env->env_val[i].value,request.env.env_val[i].value); + } + + char* name_buf; + char* val_buf; + + char *client_path; + char *user_name; + + for( i=0;ireply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_backup_reply, &reply); + if(mount_done == FALSE ){ + + int ret_mount_instr = system(mount_instr); + + if(ret_mount_instr != 0){ + printf("failed : mount volume \n"); + reply.error = NDMP_ILLEGAL_STATE_ERR; + session_info->data_state = NDMP_DATA_STATE_HALTED; + goto SEND ; + } + + mount_done = TRUE; + } + + char* backup_location; - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - xdr_ndmp_header(&reply_stream, &reply_header); - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_start_backup_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_backup_reply, &reply); + backup_location = (char*) malloc (strlen(mount_point) + strlen(full_ip) + strlen(client_path) +3 ); - session_info->data_state = NDMP_DATA_STATE_HALTED; + strcat(backup_location,mount_point); + strcat(backup_location,"/"); + strcat(backup_location ,full_ip); + strcat(backup_location ,client_path); + + char *dir_instr; + dir_instr = (char*) malloc( 11 * sizeof(char)); + strcpy(dir_instr,"mkdir -p "); + dir_instr = (char*) realloc(dir_instr,strlen(dir_instr) + strlen(backup_location)+1); + strcat(dir_instr,backup_location); + + int ret_dir_instr = system(dir_instr); + + if(ret_dir_instr != 0){ + printf("mount point directory creation failed or already exists \n"); + } + + char *rsync_instr; + rsync_instr = (char*) malloc ( 12 * sizeof(char )); + strcpy(rsync_instr,"rsync -av "); + rsync_instr = (char*) realloc(rsync_instr,strlen(rsync_instr) + 6 + strlen(user_name) +\ + strlen(full_ip) + strlen(client_path) + strlen(backup_location) ); + strcat(rsync_instr,user_name); + strcat(rsync_instr,"@"); + strcat(rsync_instr,full_ip); + strcat(rsync_instr,":"); + strcat(rsync_instr, client_path); + strcat(rsync_instr,"/ "); + strcat(rsync_instr,backup_location); - exit_critical_section(session_info->s_lock); #ifdef DEBUG - printf("Exiting data start backup \n "); + printf("printing rsync instr $ %s \n",rsync_instr); #endif + + int ret_rsync_instr = system(rsync_instr); + + //printf("return value of rsync instr = %d \n", ret_rsync_instr); + + if(ret_rsync_instr != 0){ + // return after replying with proper error code tot the client + printf("failed : rsync \n"); + reply.error = NDMP_ILLEGAL_STATE_ERR; + session_info->data_state = NDMP_DATA_STATE_HALTED; + goto SEND ; + } + +SEND: set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_backup_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_start_backup_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_backup_reply, &reply); + + session_info->data_state = NDMP_DATA_STATE_HALTED; + + exit_critical_section(session_info->s_lock); } void ndmp_data_start_recover(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* struct ndmp_name - * { - * string original_path<>; - * string destination_dir<>; - * string new_name <>; - * string other_name <>; - * ndmp_u_quad node; - * ndmp_u_quad fh_info; - * }; - * - * struct ndmp_data_start_recover_request - * { - * ndmp_pval env<>; - * ndmp_name nlist<>; - * string bu_type<>; - * }; - * struct ndmp_data_start_recover_reply - * { - * ndmp_error error; - * }; - */ -#ifdef DEBUG - printf("Printing from the data Start Recovery \n"); -#endif - struct ndmp_data_start_recover_request request; - struct ndmp_header reply_header; - struct ndmp_data_start_recover_reply reply; - struct ndmp_session_info *session_info; - XDR reply_stream; - - session_info = get_session_info(txn->client_session.session_id); - int i; - - /* We assume that the backup type and env key-value pairs have a - * maximum length of 8 characters, and that the keys and values - * themselves have a maximum length of 64 characters. - */ - - request.bu_type = (char*) malloc(8*sizeof(char)); - request.env.env_len = 8; - request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); - - for (i = 0; i < request.env.env_len; i++) { - request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); - request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); - } - - request.nlist.nlist_len = 5; - request.nlist.nlist_val = (ndmp_name*)malloc(5*sizeof(ndmp_name) ); - - for (i = 0; i < request.nlist.nlist_len; i++) { - request.nlist.nlist_val[i].original_path = (char*) malloc(64*sizeof(char)); - request.nlist.nlist_val[i].destination_dir = (char*) malloc(64*sizeof(char)); - request.nlist.nlist_val[i].new_name = (char*) malloc(64*sizeof(char)); - request.nlist.nlist_val[i].other_name = (char*) malloc(64*sizeof(char)); - } -#ifdef DEBUG - printf("before xdr decoding\n "); -#endif - xdr_ndmp_data_start_recover_request(request_stream, &request); -#ifdef DEBUG - printf("after xdr decoding \n"); -#endif - enter_critical_section(session_info->s_lock); - reply.error = NDMP_NO_ERR; - - if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else { - //changing state - session_info->data_state = NDMP_DATA_STATE_ACTIVE; - } - - char full_ip[20]=""; - strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); - - ndmp_pval* env_val = request.env.env_val; - u_long env_len = request.env.env_len; - - char* name_buf; - char* val_buf; - - char *client_path; - char *user_name; - - for( i=0;i; + * string destination_dir<>; + * string new_name <>; + * string other_name <>; + * ndmp_u_quad node; + * ndmp_u_quad fh_info; + * }; + * + * struct ndmp_data_start_recover_request + * { + * ndmp_pval env<>; + * ndmp_name nlist<>; + * string bu_type<>; + * }; + * struct ndmp_data_start_recover_reply + * { + * ndmp_error error; + * }; + */ + + struct ndmp_data_start_recover_request request; + struct ndmp_header reply_header; + struct ndmp_data_start_recover_reply reply; + struct ndmp_session_info *session_info; + XDR reply_stream; + + session_info = get_session_info(txn->client_session.session_id); + int i; + + /* We assume that the backup type and env key-value pairs have a + * maximum length of 8 characters, and that the keys and values + * themselves have a maximum length of 64 characters. + */ + + request.bu_type = (char*) malloc(8*sizeof(char)); + request.env.env_len = 8; + request.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + for (i = 0; i < request.env.env_len; i++) { + request.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + request.env.env_val[i].value = (char*) malloc(64*sizeof(char)); + } + + request.nlist.nlist_len = 5; + request.nlist.nlist_val = (ndmp_name*)malloc(5*sizeof(ndmp_name) ); + + for (i = 0; i < request.nlist.nlist_len; i++) { + request.nlist.nlist_val[i].original_path = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].destination_dir = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].new_name = (char*) malloc(64*sizeof(char)); + request.nlist.nlist_val[i].other_name = (char*) malloc(64*sizeof(char)); + } + + xdr_ndmp_data_start_recover_request(request_stream, &request); + enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + + if(session_info -> data_state != NDMP_DATA_STATE_CONNECTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + //changing state + session_info->data_state = NDMP_DATA_STATE_ACTIVE; + } + + char full_ip[20]=""; + strcpy(full_ip,inet_ntoa(txn->client_session.client_info.client.sin_addr)); + + ndmp_pval* env_val = request.env.env_val; + u_long env_len = request.env.env_len; + + char* name_buf; + char* val_buf; + + char *client_path; + char *user_name; + + for( i=0;ireply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_recover_reply, &reply); + if( ret_rsync_instr != 0){ - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - xdr_ndmp_header(&reply_stream, &reply_header); - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_start_recover_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_recover_reply, &reply); + // return after replying with proper error code to the client + printf("failed : rsync \n"); + reply.error = NDMP_ILLEGAL_STATE_ERR; + session_info->data_state = NDMP_DATA_STATE_HALTED; + goto SEND ; + } - session_info->data_state = NDMP_DATA_STATE_HALTED; - exit_critical_section(session_info->s_lock); -#ifdef DEBUG - printf("Exiting data start recover \n "); -#endif + SEND : set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_start_recover_reply, &reply); + + xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); + xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_start_recover_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_start_recover_reply, &reply); + + session_info->data_state = NDMP_DATA_STATE_HALTED; + + + exit_critical_section(session_info->s_lock); } void ndmp_data_abort(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_DATA_ABORT - * - * no request arguments - * - * struct ndmp_data_abort_reply - * { - * ndmp_error error; - * }; - * - */ - - struct ndmp_header reply_header; - struct ndmp_data_abort_reply reply; - struct ndmp_session_info *session_info; - - XDR reply_stream; - - session_info = get_session_info(txn->client_session.session_id); - enter_critical_section(session_info->s_lock); - - if (session_info-> data_state == NDMP_DATA_STATE_HALTED || session_info-> data_state == NDMP_DATA_STATE_IDLE){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else { - session_info->data_state = NDMP_DATA_STATE_HALTED; - reply.error = NDMP_NO_ERR; - } - - set_header(header, &reply_header, reply.error); - - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_data_abort_reply, &reply); - - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_abort_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_data_abort_reply, &reply); - - exit_critical_section(session_info->s_lock); -#ifdef DEBUG - printf("Data state: %d\n",session_info->data_state); -#endif + /* NDMP_DATA_ABORT + * + * no request arguments + * + * struct ndmp_data_abort_reply + * { + * ndmp_error error; + * }; + * + */ -} + struct ndmp_header reply_header; + struct ndmp_data_abort_reply reply; + struct ndmp_session_info *session_info; -void ndmp_data_get_env(struct client_txn *txn, - struct ndmp_header header, XDR* request_stream) -{ - /* NDMP_DATA_GET_ENV - * - * no request arguments - * - * struct ndmp_data_get_env_reply - * { - * ndmp_error error; - * ndmp_pval env<>; - * }; - * - */ - - int i; - struct ndmp_header reply_header; - struct ndmp_data_get_env_reply reply; - struct ndmp_session_info *session_info; - struct environment *data_env = get_environment(); - XDR reply_stream; - session_info = get_session_info(txn->client_session.session_id); - - enter_critical_section(session_info->s_lock); - - reply.error = NDMP_NO_ERR; - reply.env.env_len = data_env->env_len; - - reply.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); - - if (session_info-> data_state != NDMP_DATA_STATE_ACTIVE || session_info-> data_state != NDMP_DATA_STATE_HALTED){ - reply.error = NDMP_NO_ERR; - if (data_env->env_len != 0) { - - for (i = 0; i < data_env->env_len; i++) { - reply.env.env_val[i].name = (char*) malloc(64*sizeof(char)); - reply.env.env_val[i].value = (char*) malloc(64*sizeof(char)); - } - - for (i = 0; i < data_env->env_len; i++) { - reply.env.env_val[i].name = data_env->env_val[i].name; - reply.env.env_val[i].value = data_env->env_val[i].value; - - printf("reply.env.env_val[i].name = %s\n reply.env.env_val[i].value = %s\n\n", - reply.env.env_val[i].name, reply.env.env_val[i].value); - } - } - else - reply.env.env_val = NULL; - } - else - reply.error = NDMP_ILLEGAL_STATE_ERR; - - set_header(header, &reply_header, reply.error); - - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_data_get_env_reply, &reply); - - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_get_env_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_data_get_env_reply, &reply); + XDR reply_stream; - exit_critical_section(session_info->s_lock); -} + session_info = get_session_info(txn->client_session.session_id); + enter_critical_section(session_info->s_lock); -void ndmp_data_stop(struct client_txn *txn, - struct ndmp_header header, XDR* request_stream) -{ - /* NDMP_DATA_STOP - * - * no request arguments - * - * struct ndmp_data_stop_reply - * { - * ndmp_error error; - * }; - * - */ - - struct ndmp_header reply_header; - struct ndmp_data_stop_reply reply; - struct ndmp_session_info *session_info; - struct environment* data_env = get_environment(); - - XDR reply_stream; - - session_info = get_session_info(txn->client_session.session_id); - enter_critical_section(session_info->s_lock); - - if (session_info-> data_state != NDMP_DATA_STATE_HALTED){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else { - session_info->data_state = NDMP_DATA_STATE_IDLE; - data_env = init_environment(); - reply.error = NDMP_NO_ERR; - } - - set_header(header, &reply_header, reply.error); - - txn->reply.length = xdr_sizeof((xdrproc_t) - xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t) - xdr_ndmp_data_stop_reply, &reply); - - xdrmem_create(&reply_stream, - txn->reply.message, txn->reply.length,XDR_ENCODE); - - xdr_ndmp_header(&reply_stream, &reply_header); - - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_stop_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) - xdr_ndmp_data_stop_reply, &reply); + if (session_info-> data_state == NDMP_DATA_STATE_HALTED || session_info-> data_state == NDMP_DATA_STATE_IDLE){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + session_info->data_state = NDMP_DATA_STATE_HALTED; + reply.error = NDMP_NO_ERR; + } + + set_header(header, &reply_header, reply.error); + + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_abort_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_abort_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_abort_reply, &reply); - exit_critical_section(session_info->s_lock); + exit_critical_section(session_info->s_lock); #ifdef DEBUG - printf("Data state: %d\n",session_info->data_state); + printf("Data state: %d\n",session_info->data_state); #endif + } -void ndmp_data_listen(struct client_txn *txn, +void ndmp_data_stop(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) { - /* NDMP_DATA_LISTEN - * - * struct ndmp_tcp_addr - * { - * u_long ip_addr; - * u_short port; - * }; - * - * struct ndmp_fc_addr - * { - * u_long loop_id; - * }; - * - * struct ndmp_ipc_addr - * { - * opaque comm_data<>; - * }; - * - * union ndmp_addr switch (ndmp_addr_type addr_type) - * { - * case NDMP_ADDR_LOCAL: - * void; - * case NDMP_ADDR_TCP: - * ndmp_tcp_addr tcp_addr; - * case NDMP_ADDR_FC: - * ndmp_fc_addr fc_addr; - * case NDMP_ADDR_IPC: - * ndmp_ipc_addr ipc_addr; - * }; - * - * struct ndmp_data_listen_request - * { - * ndmp_addr_type addr_type; - * }; - * - * struct ndmp_data_listen_reply - * { - * ndmp_error error; - * ndmp_addr data_connection_addr; - * }; - */ - - struct ndmp_data_listen_request request; - struct ndmp_header reply_header; - struct ndmp_data_listen_reply reply; - struct ndmp_session_info *session_info; - XDR reply_stream; - - xdr_ndmp_data_listen_request(request_stream, &request); - session_info = get_session_info(txn->client_session.session_id); - - enter_critical_section(session_info->s_lock); - reply.error = NDMP_NO_ERR; - - if (session_info-> data_state != NDMP_DATA_STATE_IDLE){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else{ - if(request.addr_type== NDMP_ADDR_LOCAL ){ - session_info->data_state = NDMP_DATA_STATE_LISTEN; - // change the state to listen - reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL; - // reply.data_connection_addr.ndmp_addr_u = NULL; - } - else{ - // send illegal argument err - reply.error = NDMP_ILLEGAL_ARGS_ERR ; - } - } + /* NDMP_DATA_STOP + * + * no request arguments + * + * struct ndmp_data_stop_reply + * { + * ndmp_error error; + * }; + * + */ - set_header(header, &reply_header, reply.error); + struct ndmp_header reply_header; + struct ndmp_data_stop_reply reply; + struct ndmp_session_info *session_info; + struct environment* data_env = get_environment(); - txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_listen_reply, &reply); + XDR reply_stream; - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); - xdr_ndmp_header(&reply_stream, &reply_header); - if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_listen_reply(&reply_stream, &reply); - else - txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_listen_reply, &reply); + session_info = get_session_info(txn->client_session.session_id); + enter_critical_section(session_info->s_lock); - exit_critical_section(session_info->s_lock); + if (session_info-> data_state != NDMP_DATA_STATE_HALTED){ + reply.error = NDMP_ILLEGAL_STATE_ERR; + } + else { + session_info->data_state = NDMP_DATA_STATE_IDLE; + data_env = init_environment(); + reply.error = NDMP_NO_ERR; + } + + set_header(header, &reply_header, reply.error); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_stop_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); + + xdr_ndmp_header(&reply_stream, &reply_header); + + if (reply.error == NDMP_NO_ERR) + xdr_ndmp_data_stop_reply(&reply_stream, &reply); + else + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_stop_reply, &reply); + + exit_critical_section(session_info->s_lock); +#ifdef DEBUG + printf("Data state: %d\n",session_info->data_state); +#endif } -void ndmp_data_connect(struct client_txn *txn, struct ndmp_header header, XDR* request_stream) +void ndmp_data_get_env(struct client_txn *txn, + struct ndmp_header header, XDR* request_stream) { - /* NDMP_DATA_CONNECT - * struct ndmp_data_connect_request - * { - * ndmp_addr addr; - * }; + /* NDMP_DATA_GET_ENV * - * struct ndmp_data_connect_reply + * no request arguments + * + * struct ndmp_data_get_env_reply * { - * ndmp_error error; + * ndmp_error error; + * ndmp_pval env<>; * }; - */ + * + */ - struct ndmp_data_connect_request request; + int i; struct ndmp_header reply_header; - struct ndmp_data_connect_reply reply; + struct ndmp_data_get_env_reply reply; struct ndmp_session_info *session_info; + struct environment *data_env = get_environment(); XDR reply_stream; - - xdr_ndmp_data_connect_request(request_stream, &request); -#ifdef DEBUG - printf("Printing from the data connect open \n"); - printf("Request message received : \ - addr_type : %d \n ",request.addr.addr_type); -#endif session_info = get_session_info(txn->client_session.session_id); enter_critical_section(session_info->s_lock); + reply.error = NDMP_NO_ERR; + reply.env.env_len = data_env->env_len; - if (session_info-> data_state != NDMP_DATA_STATE_IDLE ){ - reply.error = NDMP_ILLEGAL_STATE_ERR; - } - else{ - if(request.addr.addr_type== NDMP_ADDR_LOCAL ){ - session_info->data_state = NDMP_DATA_STATE_CONNECTED; - // change the state to connected + reply.env.env_val = (ndmp_pval*)malloc(8*sizeof(ndmp_pval) ); + + if (session_info-> data_state != NDMP_DATA_STATE_ACTIVE || session_info-> data_state != NDMP_DATA_STATE_HALTED){ + reply.error = NDMP_NO_ERR; + if (data_env->env_len != 0) { + + for (i = 0; i < data_env->env_len; i++) { + reply.env.env_val[i].name = (char*) malloc(64*sizeof(char)); + reply.env.env_val[i].value = (char*) malloc(64*sizeof(char)); } - else{ - // send illegal argument err - reply.error = NDMP_ILLEGAL_ARGS_ERR ; - } + for (i = 0; i < data_env->env_len; i++) { + reply.env.env_val[i].name = data_env->env_val[i].name; + reply.env.env_val[i].value = data_env->env_val[i].value; + + printf("reply.env.env_val[i].name = %s\n reply.env.env_val[i].value = %s\n\n", + reply.env.env_val[i].name, reply.env.env_val[i].value); + } + } + else + reply.env.env_val = NULL; } + else + reply.error = NDMP_ILLEGAL_STATE_ERR; set_header(header, &reply_header, reply.error); - txn->reply.length = xdr_sizeof((xdrproc_t) xdr_ndmp_header, &reply_header); - txn->reply.length += xdr_sizeof((xdrproc_t)xdr_ndmp_data_connect_reply, &reply); + txn->reply.length = xdr_sizeof((xdrproc_t) + xdr_ndmp_header, &reply_header); + txn->reply.length += xdr_sizeof((xdrproc_t) + xdr_ndmp_data_get_env_reply, &reply); + + xdrmem_create(&reply_stream, + txn->reply.message, txn->reply.length,XDR_ENCODE); - xdrmem_create(&reply_stream, txn->reply.message, txn->reply.length,XDR_ENCODE); xdr_ndmp_header(&reply_stream, &reply_header); + if (reply.error == NDMP_NO_ERR) - xdr_ndmp_data_connect_reply(&reply_stream, &reply); + xdr_ndmp_data_get_env_reply(&reply_stream, &reply); else - txn->reply.length -= xdr_sizeof((xdrproc_t) xdr_ndmp_data_connect_reply, &reply); + txn->reply.length -= xdr_sizeof((xdrproc_t) + xdr_ndmp_data_get_env_reply, &reply); exit_critical_section(session_info->s_lock); } diff --git a/ndmp/src/ndmp_msg.h b/ndmp/src/ndmp_msg.h index 6d59c6c..1ffb494 100644 --- a/ndmp/src/ndmp_msg.h +++ b/ndmp/src/ndmp_msg.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its functions written by Shrinidhi + * unless specified otherwise. + */ + #ifndef __H__NDMP_XDR__ #define __H__NDMP_XDR__ diff --git a/ndmp/src/test/makefile b/ndmp/src/test/makefile index 4cd12a7..1feeae8 100644 --- a/ndmp/src/test/makefile +++ b/ndmp/src/test/makefile @@ -5,6 +5,9 @@ # later), or the GNU General Public License, version 2 (GPLv2), in all # cases as published by the Free Software Foundation. + # This file and its components written by Shrinidhi + # unless specified otherwise. + ROOT = ../../.. SRC = testndmp.c diff --git a/utils/src/hexdump.c b/utils/src/hexdump.c index f297aa4..a749fc2 100644 --- a/utils/src/hexdump.c +++ b/utils/src/hexdump.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include "hexdump.h" void hexdump(void *buffer, unsigned int size) diff --git a/utils/src/hexdump.h b/utils/src/hexdump.h index b3d869d..c508e2d 100644 --- a/utils/src/hexdump.h +++ b/utils/src/hexdump.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #ifndef __H_HEXDUMP__ #define __H_HEXDUMP__ diff --git a/utils/src/locks.c b/utils/src/locks.c index 58abb19..27f6238 100644 --- a/utils/src/locks.c +++ b/utils/src/locks.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include #include diff --git a/utils/src/locks.h b/utils/src/locks.h index 1817117..358432d 100644 --- a/utils/src/locks.h +++ b/utils/src/locks.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #ifndef __H_LOCKS__ #define __H_LOCKS__ #include diff --git a/utils/src/makefile b/utils/src/makefile index 89fe9f5..8866b2f 100644 --- a/utils/src/makefile +++ b/utils/src/makefile @@ -1,3 +1,13 @@ + # Copyright (c) 2008-2012 Red Hat, Inc. http://www.redhat.com + # This file is part of glfs-ndmp. + # This file is licensed to you under your choice of the GNU Lesser + # General Public License, version 3 or any later version (LGPLv3 or + # later), or the GNU General Public License, version 2 (GPLv2), in all + # cases as published by the Free Software Foundation. + + # This file and its components written by Shrinidhi + # unless otherwise specified. + CFLAGS = -g -I . all: queue.o locks.o hexdump.o (cd test; make) diff --git a/utils/src/queue.c b/utils/src/queue.c index 0151afa..e9d3eaa 100644 --- a/utils/src/queue.c +++ b/utils/src/queue.c @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #include #include #include diff --git a/utils/src/queue.h b/utils/src/queue.h index 2f0bfea..71a4f8d 100644 --- a/utils/src/queue.h +++ b/utils/src/queue.h @@ -7,6 +7,11 @@ * cases as published by the Free Software Foundation. */ +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + #ifndef __H__QUEUE__ #define __H__QUEUE__ /* diff --git a/utils/src/test/makefile b/utils/src/test/makefile index 7593f7e..3fc0b57 100644 --- a/utils/src/test/makefile +++ b/utils/src/test/makefile @@ -4,7 +4,11 @@ # General Public License, version 3 or any later version (LGPLv3 or # later), or the GNU General Public License, version 2 (GPLv2), in all # cases as published by the Free Software Foundation. + + # This file and its components written by Shrinidhi + # unless otherwise specified. + CFLAGS = -I../ -g CC = gcc