📄 comm.c
字号:
/* -*- Mode: C -*- * comm.c * * Description : NDMP common communication functions. * * Copyright (c) 1996,1997 PDC, Network Appliance. All Rights Reserved. * * $Id: comm.c,v 1.12 1998/05/26 03:52:11 tim Exp $ */#if !defined(lint) && !defined(SABER)static char rcsId[] __attribute__ ((unused)) = "@(#) $Id: comm.c,v 1.12 1998/05/26 03:52:11 tim Exp $";#endif#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/uio.h>#include "ndmp_common.h"#include "md5.h"typedef struct MsgInfo{ ndmp_header hdr; NdmpMsgHandler* handler; void* body;} MsgInfo;/* Connection data structure. */typedef struct Connection{ int sock; XDR xdrs; u_long mySequence; bool_t authorized; bool_t eof; MsgInfo msginfo; /* received request or reply message */ NdmpMsgHandler* msgHandlerTbl; u_short version; void* clientData;} Connection;static intndmp_readit(void* connectionHandle, caddr_t buf, int len);static intndmp_writeit(void* connectionHandle, caddr_t buf, int len);static intndmp_recv_msg(Connection* connection);static intndmp_process_messages(Connection* connection, bool_t reply_expected);static NdmpMsgHandler*ndmp_get_handler(Connection* connection, ndmp_message message);/* * ndmpCreateConnection * * Allocate and initialize a connection structure. * * Parameters: * handler_tbl (input) - message handlers. * * Returns: * 0 - error * connection pointer * * Notes: * The returned connection should be destroyed using * ndmpDestroyConnection(). */NdmpConnectionndmpCreateConnection(NdmpMsgHandler* msgHandlerTbl){ Connection* connection; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpCreateConnection\n"); connection = (Connection*)malloc(sizeof(Connection)); if (connection == 0) { Error(LOG_ERR, "system call (malloc): %s.\n", strerror(errno)); return(0); } connection->sock = -1; connection->mySequence = 0; connection->authorized = FALSE; connection->eof = FALSE; connection->msginfo.body = 0; connection->msgHandlerTbl = msgHandlerTbl; connection->version = NDMPVER; connection->clientData = 0; connection->xdrs.x_ops = 0; xdrrec_create(&connection->xdrs, 0, 0, (caddr_t)connection, ndmp_readit, ndmp_writeit); if (connection->xdrs.x_ops == 0) { Error(LOG_ERR, "xdrrec_create failed.\n"); close(connection->sock); return(0); } return((NdmpConnection)connection);}/* * ndmpDestroyConnection * * Shutdown a connection and release allocated resources. * * Parameters: * connectionHandle (Input) - connection handle. * * Returns: * void */voidndmpDestroyConnection(NdmpConnection connectionHandle){ Connection* connection = (Connection*)connectionHandle; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpDestroyConnection\n"); if (connection->sock >= 0) { (void)close(connection->sock); connection->sock = -1; } xdr_destroy(&connection->xdrs); free((void*)connection);}/* * ndmpClose * Close a connection. * * Parameters: * connectionHandle (Input) - connection handle. * * Returns: * void */voidndmpClose(NdmpConnection connectionHandle){ Connection* connection = (Connection*)connectionHandle; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpClose\n"); if (connection->sock >= 0) { (void)close(connection->sock); connection->sock = -1; } connection->eof = TRUE;}/* * ndmpRun * * Creates a socket for listening and accepting connections * from NDMP clients. * Accepts connections and passes each connection to the connection * handler. * If the dofork parameter is TRUE, a child process is forked and the * connection handler is run in the context of the child process. * * Parameters: * port (input) - NDMP server port. * If 0, the port number will be retrieved from * the network service database. If not found there, * the default NDMP port number (from ndmp.x) * will be used. * dofork (input) - if TRUE, connection handler is run in the context * of a child process. * handler (input) - connection handler function. * * Returns: * void * * Notes: * This function does not return unless encountering an error * related to the listen socket. */voidndmpRun(u_long port, bool_t dofork, NdmpMsgHandler* msgHandlerTbl, NdmpConHandlerFunc* conHandlerFunc){ struct sockaddr_in sin; struct servent *sp; int server_socket; int on = 1; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpRun\n"); /* * If no port number was specified, get * the port number from the network services database. */ if (port == 0) { if ((sp = getservbyname("ndmp", "tcp")) == 0) port = NDMPPORT; else port = sp->s_port; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { Error(LOG_ERR, "system call (socket): %s.\n", strerror(errno)); return; } (void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (bind(server_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) { Error(LOG_ERR, "system call (bind): %s.\n", strerror(errno)); close(server_socket); return; } if (listen(server_socket, 5) < 0) { Error(LOG_ERR, "system call (listen): %s.\n", strerror(errno)); close(server_socket); return; } Debug(DBG_CAT_CONN|DBG_FOC_FLOW, "ndmpd running\n"); for (;;) { struct sockaddr_in from; int from_len = sizeof(from); int ns; pid_t pid; if ((ns = accept(server_socket, (struct sockaddr *)&from, &from_len)) < 0) { Error(LOG_ERR, "system call (accept): %s.\n", strerror(errno)); continue; } Debug(DBG_CAT_CONN|DBG_FOC_FLOW, "Received connection from %s\n", inet_ntoa(from.sin_addr)); if (dofork == FALSE) { NdmpConnection connection; if ((connection = ndmpCreateConnection(msgHandlerTbl)) == 0) { close(ns); continue; } ((Connection*)connection)->sock = ns; (*conHandlerFunc)(connection); ndmpDestroyConnection(connection); continue; } pid = fork(); if (pid < 0) { Error(LOG_ERR, "system call (fork): %s.\n", strerror(errno)); (void)close(ns); continue; } if (pid == 0) { /* Child process. */ NdmpConnection connection; (void)close(server_socket); if ((connection = ndmpCreateConnection(msgHandlerTbl)) == 0) { (void)close(ns); exit(1); } ((Connection *)connection)->sock = ns; (*conHandlerFunc)(connection); ndmpDestroyConnection(connection); exit(0); } (void)close(ns); Debug(DBG_CAT_CONN|DBG_FOC_FLOW, "forked %d\n", pid); }}/* * ndmpConnect * * Establish a connection to an NDMP server. * * Parameters: * connection (input) - connection handle. * host (input) - NDMP server host name. * port (input) - NDMP server port number. * if 0, the port number is retrieved from the * network service database. If not found there, * the default NDMP port number (from ndmp.x) * will be used. * * Returns: * 0 - successful connection. * -1 - error. */intndmpConnect(NdmpConnection connection, char* host, u_long port){ struct sockaddr_in sin; struct hostent *hp; struct servent *sp; int sock; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpConnect: host:%s port:%d\n", host, port); if ((hp = gethostbyname(host)) == 0) { Error(LOG_ERR, "unknown host: %s\n", host); return(-1); } if (port == 0) { if ((sp = getservbyname("ndmp", "tcp")) == 0) port = NDMPPORT; else port = sp->s_port; } memset((void*)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr; sin.sin_port = htons(port); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { Error(LOG_ERR, "system call (socket): %s\n", strerror(errno)); return(-1); } if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { Error(LOG_ERR, "system call (connect): %s\n", strerror(errno)); close(sock); return(-1); } ((Connection*)connection)->sock = sock; return(0);}/* * ndmpPoll * * Poll for message data on the connection socket and * process received messages. * * Parameters: * connection (input) - connection handle * block (input) - If TRUE, wait for data. * * Returns: * 1 - messages received and processed. * 0 - block FALSE and no data available. * -1 - Error; connection no longer established. */intndmpPoll(NdmpConnection connectionHandle, bool_t block){ Connection *connection = (Connection *)connectionHandle; struct pollfd fds[1]; int timeout; int ret; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpPoll: block:%s\n", block == TRUE ? "TRUE" : "FALSE"); if (block) timeout = -1; else timeout = 0; fds[0].fd = connection->sock; fds[0].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI; ret = poll(fds, 1, timeout); if (ret == 0) return(0); if (ret < 0) { connection->eof = TRUE; (void)close(connection->sock); connection->sock = -1; return(-1); } return(ndmpProcessRequests(connectionHandle));}/* * ndmpProcessRequests * * Reads the next request message into the stream buffer. * Processes messages until the stream buffer is empty. * * Parameters: * connectionHandle (input) - connection handle. * * Returns: * 0 - 1 or more messages successfully processed. * -1 - error; connection no longer established. */intndmpProcessRequests(NdmpConnection connectionHandle){ Connection *connection = (Connection *)connectionHandle; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpProcessRequests\n"); if (ndmp_process_messages(connection, 0) < 0) return(-1); return(0);} /* * ndmpSendRequest * * Send an NDMP request message. * * Parameters: * connectionHandle (input) - connection pointer. * message (input) - message number. * err (input) - error code to place in header. * request_data (input) - message body. * reply_msg (output) - reply message. If 0, reply will be * discarded. * * Returns: * 0 - successful send. * -1 - error. * otherwise - error from reply header. * * Notes: * - The reply body is only returned if the error code is NDMP_NO_ERR. */intndmpSendRequest(NdmpConnection connectionHandle, ndmp_message message, ndmp_error err, void* request_data, void** reply){ Connection *connection = (Connection *)connectionHandle; ndmp_header header; NdmpMsgHandler *handler; struct timeval time; Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpSendRequest: message:0x%x\n", message); /* Lookup info necessary for processing this request. */ if (!(handler = ndmp_get_handler(connection, message))) { Error(LOG_ERR,"sending message 0x%x: not supported.\n", message); return(-1); } gettimeofday(&time, 0); header.sequence = ++(connection->mySequence); header.time_stamp = time.tv_sec; header.message_type = NDMP_MESSAGE_REQUEST; header.message = message; header.reply_sequence = 0; header.error = err; connection->xdrs.x_op = XDR_ENCODE; if (!xdr_ndmp_header(&connection->xdrs, &header)) { Error(LOG_ERR, "sending message 0x%x: encoding request header.\n", message); xdrrec_endofrecord(&connection->xdrs, 1); return(-1); } if (err == NDMP_NO_ERR && handler->xdr_request && request_data) { if (!(*handler->xdr_request)(&connection->xdrs, request_data)) { Error(LOG_ERR, "sending message 0x%x: encoding request body.\n", message); xdrrec_endofrecord(&connection->xdrs, 1); return(-1); } } xdrrec_endofrecord(&connection->xdrs, 1); if (handler->xdr_reply == 0) return(0); /* * Process messages until the reply to this request has been * processed. */ for (;;) { int r; r = ndmp_process_messages(connection, TRUE); /* connection error? */ if (r < 0) return(-1); /* no reply received? */ if (r == 0) continue; /* reply received? */ if (r == 1) { if (message != connection->msginfo.hdr.message) { Error(LOG_ERR, "received unexpected reply 0x%x.\n", connection->msginfo.hdr.message); ndmpFreeMessage(connectionHandle); return(-1); } if (reply != 0) *reply = connection->msginfo.body; else ndmpFreeMessage(connectionHandle); return(connection->msginfo.hdr.error); } /* error handling reply */ return(-1); } return(0);}/* * ndmpSendReply * Send an NDMP reply message. * * Parameters: * connectionHandle (input) - connection pointer. * err (input) - error code to place in header. * reply (input) - reply message body. * * Returns: * 0 - successful send. * -1 - error. * * Notes: * - The body is only sent if the error code is NDMP_NO_ERR. */intndmpSendReply(NdmpConnection connectionHandle, ndmp_error err, void* reply){ Connection *connection = (Connection *)connectionHandle; ndmp_header header; struct timeval time; gettimeofday(&time, 0); Debug(DBG_CAT_COMM|DBG_FOC_FLOW, "ndmpSendReply: message:0x%x\n", connection->msginfo.hdr.message); header.sequence = ++(connection->mySequence); header.time_stamp = time.tv_sec; header.message_type = NDMP_MESSAGE_REPLY; header.message = connection->msginfo.hdr.message; header.reply_sequence = connection->msginfo.hdr.sequence; header.error = err; connection->xdrs.x_op = XDR_ENCODE; if (!xdr_ndmp_header(&connection->xdrs, &header)) { Error(LOG_ERR, "sending message 0x%x: encoding reply header.\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -