⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comm.c

📁 网络数据管理协议的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*                               -*- 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 + -