diff --git a/NDMPServerDesignv5.odt b/NDMPServerDesignv5.odt deleted file mode 100644 index 5ead866..0000000 Binary files a/NDMPServerDesignv5.odt and /dev/null differ diff --git a/comm/src/comm.c b/comm/src/comm.c new file mode 100644 index 0000000..ed32f89 --- /dev/null +++ b/comm/src/comm.c @@ -0,0 +1,295 @@ +/* + * 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. + */ + +#include +#include + +/* + * comm_context: + * 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)); + retval->sessions = init_queue(); + retval->request_jobs = init_queue(); + retval->reply_jobs = init_queue(); + } + 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; i < n; i++) { + FD_SET(active_sessions[i]->session_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; + 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); + } + } +} + +/* + * 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); + 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; + + 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..88a3a19 --- /dev/null +++ b/comm/src/comm.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef __H__COMM__ +#define __H__COMM__ + +#define LISTEN_PORT 10000 +#define NUM_SESSIONS 512 +#define MAX_MESSAGE_SIZE 2048 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct client_endpoint { + struct sockaddr_in client; + int fd; +}; + +struct comm_message { + int is_tcp_connect; + char message[MAX_MESSAGE_SIZE]; + int length; +}; + +struct session { + int session_id; + struct client_endpoint client_info; +}; + +struct client_txn { + 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; +}; + +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/makefile b/comm/src/makefile new file mode 100644 index 0000000..e6dced7 --- /dev/null +++ b/comm/src/makefile @@ -0,0 +1,24 @@ +# 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 + (cd test; make); + +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 + (cd test; make clean); diff --git a/comm/src/test/makefile b/comm/src/test/makefile new file mode 100644 index 0000000..e01f0c3 --- /dev/null +++ b/comm/src/test/makefile @@ -0,0 +1,39 @@ +# 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 +CFLAGS = -g -I ../ -I../../../utils/src + +all: comm + +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 + +comm.o: ../comm.h ../comm.c + gcc -c $(CFLAGS) ../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 + +clean: + rm *.o testcomm diff --git a/comm/src/test/testcomm.c b/comm/src/test/testcomm.c new file mode 100644 index 0000000..35e7c9b --- /dev/null +++ b/comm/src/test/testcomm.c @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include +#include +#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 new file mode 100644 index 0000000..67e0a41 --- /dev/null +++ b/comm/src/worker.c @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#include +#include + +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) +{ + 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 + */ + +#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); + 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_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); + } + return -1 * (sent_bytes != reply.length); +} diff --git a/comm/src/worker.h b/comm/src/worker.h new file mode 100644 index 0000000..9762532 --- /dev/null +++ b/comm/src/worker.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#ifndef __H_WORKER__ +#define __H_WORKER__ + +#include +#include + +#define THREAD_POOL_SIZE 1 + +void create_thread_pool(int n); +void shutdown_thread_pool(); + +#endif 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/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..4f9e217 --- /dev/null +++ b/ndmp/src/files @@ -0,0 +1,9 @@ +makefile +ndmp_data.c +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..c578f21 --- /dev/null +++ b/ndmp/src/makefile @@ -0,0 +1,40 @@ + # 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 +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_data.o ndmp_msg.o + (cd test; make) + +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_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 + +clean: + rm *.o ndmp.h ndmp_xdr.c + (cd test; make clean) diff --git a/ndmp/src/ndmp.x b/ndmp/src/ndmp.x new file mode 100644 index 0000000..7649c79 --- /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..32d3c9f --- /dev/null +++ b/ndmp/src/ndmp_config.c @@ -0,0 +1,783 @@ +/* + * 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 functions written by Shrinidhi + * unless otherwise specified. + */ + +#include +#include +#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 + * 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<>; + * }; + */ + + 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) +{ + /* 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, + 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) +{ + /* /* 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, + 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); + + +} + +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 <>; + * }; + */ + + 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) +{ + /* /* 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, + 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) +{ + /* 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; + + 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) +{ + /* 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); + + 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); +} + +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_reply + * 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 new file mode 100644 index 0000000..38d7e98 --- /dev/null +++ b/ndmp/src/ndmp_connect.c @@ -0,0 +1,123 @@ +/* + * 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 */ + + struct ndmp_session_info *session_info; + + 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; // 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); +} diff --git a/ndmp/src/ndmp_data.c b/ndmp/src/ndmp_data.c new file mode 100644 index 0000000..22d3b3c --- /dev/null +++ b/ndmp/src/ndmp_data.c @@ -0,0 +1,789 @@ +/* + * 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_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_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 ; + } + } + + 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); + +#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; + + 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("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; + + 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;idata_state = NDMP_DATA_STATE_HALTED; + goto SEND ; + } + + mount_done = TRUE; + } + + char* backup_location; + + backup_location = (char*) malloc (strlen(mount_point) + strlen(full_ip) + strlen(client_path) +3 ); + + 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); + +#ifdef DEBUG + 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; + * }; + */ + + 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;idata_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_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 + +} + +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); +#ifdef DEBUG + printf("Data state: %d\n",session_info->data_state); +#endif +} + +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); + + exit_critical_section(session_info->s_lock); +} diff --git a/ndmp/src/ndmp_msg.c b/ndmp/src/ndmp_msg.c new file mode 100644 index 0000000..6994e6a --- /dev/null +++ b/ndmp/src/ndmp_msg.c @@ -0,0 +1,350 @@ +/* + * 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); +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 + * 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; + 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; + 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; + } +} + +void ndmp_error_message(struct client_txn *txn, + 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); +} + +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 = ""; + + 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; + + 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; +} + + +/* + * 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(); + + /* + * 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 + * 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 = IDLE; + retval->mover_state = IDLE; + 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; +} + +/* + * 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 new file mode 100644 index 0000000..1ffb494 --- /dev/null +++ b/ndmp/src/ndmp_msg.h @@ -0,0 +1,132 @@ +/* + * 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 functions written by Shrinidhi + * unless specified otherwise. + */ + +#ifndef __H__NDMP_XDR__ +#define __H__NDMP_XDR__ + +#include +#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 */ + struct queue_hdr *jobs; /* outstanding client requests */ + int is_terminated; +}; + +/* + * 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); + + +/* + * 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(); + +/* + * 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_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 new file mode 100644 index 0000000..1feeae8 --- /dev/null +++ b/ndmp/src/test/makefile @@ -0,0 +1,33 @@ + # 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 = ../../.. +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 \ + $(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 + + +testndmp: + gcc $(CFLAGS) -c testndmp.c + gcc $(CFLAGS) -o testndmp testndmp.o $(OBJS) $(LIBS) + +clean: + rm *.o testndmp \ No newline at end of file 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.c b/ndmp/src/test/testndmp.c new file mode 100644 index 0000000..6846793 --- /dev/null +++ b/ndmp/src/test/testndmp.c @@ -0,0 +1,23 @@ +/* + * 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; + 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 new file mode 100644 index 0000000..a749fc2 --- /dev/null +++ b/utils/src/hexdump.c @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#include "hexdump.h" + +void hexdump(void *buffer, unsigned int size) +{ + 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); + } + +} + +/* + * hexdump dumps two blocks of 8 bytes (hex equivalent) per line + * The bytes are counted from "whence" + * + */ + +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(' '); + } +} + +/* + * print the ASCII equivalent of the dump_hex function. If a character is + * unprintable, print "." instead. + */ + +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"); +} diff --git a/utils/src/hexdump.h b/utils/src/hexdump.h new file mode 100644 index 0000000..c508e2d --- /dev/null +++ b/utils/src/hexdump.h @@ -0,0 +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. + */ + +/* + * This file and its components written by Shrinidhi + * unless otherwise specified. + */ + +#ifndef __H_HEXDUMP__ +#define __H_HEXDUMP__ + +#include +#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..27f6238 --- /dev/null +++ b/utils/src/locks.c @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#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..358432d --- /dev/null +++ b/utils/src/locks.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#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/makefile b/utils/src/makefile new file mode 100644 index 0000000..8866b2f --- /dev/null +++ b/utils/src/makefile @@ -0,0 +1,26 @@ + # 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) + +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 + (cd test; make clean) diff --git a/utils/src/queue.c b/utils/src/queue.c new file mode 100644 index 0000000..e9d3eaa --- /dev/null +++ b/utils/src/queue.c @@ -0,0 +1,150 @@ +/* + * 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. + */ + +#include +#include +#include + +void enter_critical_section(struct lock* q_lock); +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(); + + 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); +} + +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* 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 ; +} + +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); +} + +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 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 new file mode 100644 index 0000000..71a4f8d --- /dev/null +++ b/utils/src/queue.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#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 + * + */ +#include + +struct queue_node { + void *elem; + struct queue_node *next; +}; + +struct queue_hdr { + 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 + */ +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..3fc0b57 --- /dev/null +++ b/utils/src/test/makefile @@ -0,0 +1,31 @@ + # 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 = -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..6359fee --- /dev/null +++ b/utils/src/test/mtestq.c @@ -0,0 +1,135 @@ +/* + * 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 "queue.h" +#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); +void 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); + + + +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; i < n; i++) + add_a_job(queue, i); +} + +void check_job_queue(struct queue_hdr *queue, int num_jobs, int num_threads) +{ + int i; + queue_size = 0; + pthread_t *threads = (pthread_t *) malloc( + num_threads * sizeof(pthread_t)); + + num_lock = get_lock(); + + for (i = 0; i < num_threads; i++) { + pthread_create(&threads[i], NULL, get_jobs, (void *) queue); + } + + for (i = 0; i < num_threads; i++) { + pthread_join(threads[i], NULL ); + } + + assert(queue_size == num_jobs); + +} + +void check_job_removal(struct queue_hdr *queue, int num_jobs, int num_threads) +{ + int i; + + struct thread_args args; + args.queue = queue; + args.num_jobs = num_jobs; + pthread_t *threads = (pthread_t *) malloc( + num_threads * sizeof(pthread_t)); + + assert(num_elems(queue) == num_jobs); + for (i = 0; i < num_threads; i++) { + pthread_create(&threads[i], NULL, get_and_remove_jobs, + (void *) &args); + } + + for (i = 0; i < num_threads; i++) { + pthread_join(threads[i], NULL); + } + assert(num_elems(queue) == 0); +} + +void *get_jobs(void *queue) +{ + struct queue_hdr *job_queue = (struct queue_hdr *) queue; + while (dequeue(job_queue) != NULL) { + enter_critical_section(num_lock); + queue_size++; + exit_critical_section(num_lock); + } + pthread_exit(NULL); +} + +void *get_and_remove_jobs(void *args) +{ + struct queue_hdr *job_queue = ((struct thread_args *) args)->queue; + int i, n; + + n = ((struct thread_args *) args)->num_jobs; + + for (i = 0; i < n; i++) { + if (get_elem(job_queue, &i, queue_cmp) != NULL) { + remove_elem(job_queue, &i, queue_cmp); + assert(get_elem(job_queue,&i,queue_cmp) == NULL); + } + } + return job_queue; +} + +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"); +} diff --git a/utils/src/test/testhexdump.c b/utils/src/test/testhexdump.c new file mode 100644 index 0000000..9e934ef --- /dev/null +++ b/utils/src/test/testhexdump.c @@ -0,0 +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. + */ + +#include "hexdump.h" +#include +#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..e92495a --- /dev/null +++ b/utils/src/test/testq.c @@ -0,0 +1,91 @@ +/* + * 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(); + set_up_job_queue(job_queue,n); + int ** elems = (int **) get_all_elems(job_queue); + for (i=0; i