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

📄 client.c

📁 一个linux下的根文件系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 1999, 2000, 2002, 2003 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 2002, 2003 by Koninklijke Philips Electronics N.V. * Copyright (c) 1999, 2000 Alex Holden <alex@linuxhacker.org> * Copyright (c) 1991 David I. Bell * Copyright (c) 2000 Vidar Hokstad * Copyright (c) 2000 Morten Rolland <mortenro@screenmedia.no> * * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * Client routines to do graphics with windows and graphics contexts. * * Rewritten heavily for speed by Greg Haerr * * Whenever you add a new API entry point, please comment it in the same way * as the rest of the functions in this file. Also add your functions to the * appropriate section(s) in doc/nano-X/nano-X-sections.txt and regenerate the * documentation by running make in the doc/nano-X/ directory. If you do not * have the necessary tools (gtk-doc and the docbook-tools) to rebuild the * documentation, just skip that step and we will do it for you. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <stddef.h>#include <signal.h>#include <errno.h>#include <time.h>#if HAVE_SHAREDMEM_SUPPORT#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#endif#include <sys/time.h>#include <sys/socket.h>#if ELKS#include <linuxmt/na.h>#include <linuxmt/time.h>#define ADDR_FAM AF_NANO#elif __ECOS#include <netinet/in.h>#include <arpa/inet.h>#include <sys/select.h>#include <cyg/kernel/kapi.h>#define ADDR_FAM AF_INET#define _NO_SVR_MAPPING#define getpid()	((int)cyg_thread_self())#else#include <sys/un.h>#if hpux#include <sys/time.h>#else#ifdef __GLIBC__#include <sys/select.h>#endif#endif#endif#include "nano-X.h"#include "serv.h"#include "nxproto.h"#include "lock.h"#ifndef ADDR_FAM/** * Default to unix socket for client/server. * @internal */#define ADDR_FAM AF_UNIX#endif#define GR_CLOSE_FIX	1	/* dirty hack attempts to fix GrClose hang bug*//** * The granularity of the shared memory allocation.  The requested size * will be rounded up to a multiple of this many bytes. * * @internal */#define SHM_BLOCK_SIZE	4096#ifndef __ECOS/* exported global data */int 	   nxSocket = -1;	/* The network socket descriptor */LOCK_DECLARE(nxGlobalLock);	/* global lock for threads safety*/#if HAVE_SHAREDMEM_SUPPORTchar *	   nxSharedMem = 0;	/* Address of shared memory segment*/static int nxSharedMemSize;	/* Size in bytes of shared mem segment*/#endifstatic int regfdmax = -1;	/* GrRegisterInput globals*/static fd_set regfdset;/** * Human-readable error strings. */char *nxErrorStrings[] = {	GR_ERROR_STRINGS};static EVENT_LIST *	evlist;/* * The following is the user defined function for handling errors. * If this is not set, then the default action is to close the connection * to the server, describe the error, and then exit.  This error function * will only be called when the client asks for events. */static GR_FNCALLBACKEVENT ErrorFunc = GrDefaultErrorHandler;#else /* __ECOS*//* * eCos uses a thread data pointer to store all statics in... */int ecos_nanox_client_data_index = CYGNUM_KERNEL_THREADS_DATA_MAX;#endifstatic void QueueEvent(GR_EVENT *ep);static void GetNextQueuedEvent(GR_EVENT *ep);static void _GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout);static int  _GrPeekEvent(GR_EVENT * ep);/** * Read n bytes of data from the server into block *b.  Make sure the data * you are about to read are actually of the correct type - e.g. make a * check for the first block of data you read as a response to a command * with the Typed version of this function. * * @param b Destination for read. * @param n Number of bytes to read. * @return  0 on success or -1 on failure. * @internal */static intReadBlock(void *b, int n){	int i = 0;	char *v;        ACCESS_PER_THREAD_DATA()	v = (char *) b;	nxFlushReq(0L,0);	while(v < ((char *) b + n)) {		i = read(nxSocket, v, ((char *) b + n - v));		if ( i <= 0 ) {			if ( i == 0 ) {				/* We should maybe produce an event here,				 * if possible.				 */				EPRINTF("nxclient: lost connection to Nano-X "					"server\n");				exit(1);			}			if ( errno == EINTR || errno == EAGAIN )				continue;			EPRINTF("nxclient: bad readblock %d, errno %d\n", i, errno);			return -1;		}		v += i;	}	return 0;}/** * Read a byte of data from the server. * * @return The unsigned character read from the server, or -1 on error. * * @internal */static intReadByte(void){	unsigned char c;	if(ReadBlock(&c, 1) == -1)		return -1;	else return (int) c;}/** * Check if this is a CLIENT_DATA event, in which case we need to read the * data for the event into a buffer and set the event data pointer to the * address of it (or NULL if the malloc() fails). We also don't try to read * any data if datalen is 0. * * @param evp Event to check * * @internal */static voidCheckForClientData(GR_EVENT *evp){	GR_EVENT_CLIENT_DATA *event;	if(evp->type == GR_EVENT_TYPE_CLIENT_DATA) {		event = (GR_EVENT_CLIENT_DATA *)evp;		if(!event->datalen) {			event->data = NULL;			return;		}		if(!(event->data = malloc(event->datalen))) return;		ReadBlock(event->data, event->datalen);	}}/** * Check if the data we are about to read is of the correct type. This * must be done in order to avoid reading an event as part of the response * from the server to a command that requires a reply. * * @param packettype Expected type. * @return           packettype on success, -1 on error. * * @internal */static intCheckBlockType(short packettype){	short		b;	GR_EVENT	event;	while (ReadBlock(&b,sizeof(b)) != -1) {		if (b == packettype)			return b;		if (b == GrNumGetNextEvent) {			/*DPRINTF("nxclient %d: Storing event (expected %d)\n",				getpid(), packettype);*/			/* read event and queue it for later processing*/			ReadBlock(&event, sizeof(event));			CheckForClientData(&event);			QueueEvent(&event);		} else {			EPRINTF("nxclient %d: Wrong packet type %d "				"(expected %d)\n", getpid(),b, packettype);		}	}	EPRINTF("nxclient %d: Corrupted packet\n", getpid());	return -1;}/** * Actually read a response from the server, much like the ReadBlock but * make sure the response is of the right kind, e.g. store the event that * may have sneaked into the stream. * * @param b    Destination for read data. * @param n    Number of bytes to read. * @param type The required packet type. * @return     0 on success or -1 on failure. * * @internal */static intTypedReadBlock(void *b, int n, int type){	int r;   	r = CheckBlockType(type);	if (r != type)		return -1;	return ReadBlock(b, n);}/** * Check if the passed event is an error event, and call the error handler if * there is one. After calling the handler (if it returns), the event type is * set to a non-event so that we don't return an error event through the * GetEvent() mechanism. This solution is simpler than creating a client-side * event queue. * * @param ep The event to check. * * @internal */static voidCheckErrorEvent(GR_EVENT *ep){        ACCESS_PER_THREAD_DATA()	if (ep->type == GR_EVENT_TYPE_ERROR) {	    if (ErrorFunc) {			/* call error handler*/			ErrorFunc(ep);			/* then convert to null event*/			ep->type = GR_EVENT_TYPE_NONE;		}	}}/** * Open a connection to the graphics server. * * @return the fd of the connection to the server or -1 on failure * * @ingroup nanox_general */int GrOpen(void){	size_t 		size;	nxOpenReq	req;	int		tries;	int		ret = 0;#if ADDR_FAM == AF_NANO	struct sockaddr_na name;#elif ADDR_FAM == AF_INET	struct sockaddr_in name;	struct hostent *he;	/* allow specification of remote nano-X server address*/	char *sockaddr = getenv("NXDISPLAY");	if (!sockaddr)		sockaddr = "127.0.0.1";		/* loopback address*/#elif ADDR_FAM == AF_UNIX	struct sockaddr_un name;	/* allow override of named UNIX socket (default /tmp/.nano-X)*/	char *sockname = getenv("NXDISPLAY");	if (!sockname)		sockname = GR_NAMED_SOCKET;#else#error "ADDR_FAM not defined to AF_NANO, AF_INET or AF_UNIX"#endif	ACCESS_PER_THREAD_DATA()		/* check already open*/	if (nxSocket >= 0)        	return nxSocket;	/* try to get socket*/	if ((nxSocket = socket(ADDR_FAM, SOCK_STREAM, 0)) == -1)		return -1;	/* initialize global critical section lock*/	LOCK_INIT(&nxGlobalLock);#if ADDR_FAM == AF_NANO	name.sun_family = AF_NANO;	name.sun_no = GR_ELKS_SOCKET;		/* AF_NANO socket 79*/	size = sizeof(struct sockaddr_na);#elif ADDR_FAM == AF_INET	name.sin_family = AF_INET;	name.sin_port = htons(GR_NUM_SOCKET);	/* AF_INET socket 6600*/	if (!(he = gethostbyname(sockaddr))) {		EPRINTF("nxclient: Can't resolve address for server %s\n", sockaddr);		close(nxSocket);		nxSocket = -1;		return -1;	}	name.sin_addr = *(struct in_addr *)he->h_addr_list[0];	size = sizeof(struct sockaddr_in);#elif ADDR_FAM == AF_UNIX	name.sun_family = AF_UNIX;	strcpy(name.sun_path, sockname);	size = (offsetof(struct sockaddr_un, sun_path) +		strlen(name.sun_path) + 1);#endif	/*	 * Try to open the connection ten times,	 * waiting 0.1 or 2.0 seconds between attempts.	 */	for (tries=1; tries<=10; ++tries) {		struct timespec req;		ret = connect(nxSocket, (struct sockaddr *) &name, size);		if (ret >= 0)			break;#if ADDR_FAM == AF_INET		req.tv_sec = 0;		req.tv_nsec = 100000000L;#else		req.tv_sec = 2;		req.tv_nsec = 0;#endif		nanosleep(&req, NULL);		EPRINTF("nxclient: retry connect attempt %d\n", tries);	}	if (ret == -1) {		close(nxSocket);		nxSocket = -1;		return -1;	}	setbuf(stdout, NULL);	setbuf(stderr, NULL);	/*	 * By Performing the 'GrOpen' without allocating a buffer, just	 * shuffeling the struct over the wire, we can postpone the	 * allocation of the client size command buffer, which will never be	 * allocated if the first command after GrOpen() is	 * GrReqShmCmds() which allocates a replacement shared memory	 * segment.	 * So: Calling GrReqShmCmds() right after GrOpen will prevent the	 * traditional command queue buffer from being allocated from	 * the process heap - and only the shared memory segment is	 * allocated.	 */	req.reqType = GrNumOpen;	req.hilength = 0;	req.length = sizeof(req);	/* associate the process ID with the client*/	req.pid = getpid();	nxWriteSocket((char *)&req,sizeof(req));	return nxSocket;}#if GR_CLOSE_FIXstatic voidmySignalhandler(int sig){	if (sig == SIGALRM) {		EPRINTF("Oops! nxFlushReq() timed out, exiting\n");		exit(127);	}}#endif/* Vladimir Cotfas: hang in GrFlush() --> nxFlushReq(0L,1); *//** * Close the graphics device.  Flushes any waiting messages. * * @ingroup nanox_general */void GrClose(void){	ACCESS_PER_THREAD_DATA()#if GR_CLOSE_FIX	/* allow 1 second to flush*/	void * oldSignalHandler = signal(SIGALRM, mySignalhandler);	alarm(1);#endif	LOCK(&nxGlobalLock);	AllocReq(Close);	GrFlush();	UNLOCK(&nxGlobalLock);#if GR_CLOSE_FIX	alarm(0);	signal(SIGALRM, oldSignalHandler);#endif	close(nxSocket);	nxSocket = -1;	LOCK_FREE(&nxGlobalLock);}/** * Flush the message buffer of any messages it may contain. * * @ingroup nanox_general */void GrFlush(void){	nxFlushReq(0L,1);  #ifdef NOTUSED	GR_EVENT event;	/* And stick any incoming events on the local queue */	while (_GrPeekEvent(&event)) {		_GrGetNextEventTimeout(&event, 0L);		QueueEvent(&event);	}#endif}/** * The default error handler.  This is called when the server reports an * error event and the client hasn't set up a handler of it's own. * * Generates a human readable error message describing what error * occurred and what function it occured in, then exits. * * @param ep The error event structure. * * @ingroup nanox_general */void GrDefaultErrorHandler(GR_EVENT *ep){	if (ep->type == GR_EVENT_TYPE_ERROR) {		EPRINTF("nxclient %d: Error (%s) ", getpid(), ep->error.name);		EPRINTF(nxErrorStrings[ep->error.code], ep->error.id);		GrClose();		exit(1);	}}/** * Sets an error handling routine that will be called on any errors from * the server (assuming the client has asked to receive them). If zero is * used as the argument, errors will be returned as regular events instead. * * @param fncb the function to call to handle error events * @return     the address of the previous error handler * * @ingroup nanox_general */GR_FNCALLBACKEVENTGrSetErrorHandler(GR_FNCALLBACKEVENT fncb){	GR_FNCALLBACKEVENT orig;	ACCESS_PER_THREAD_DATA()	LOCK(&nxGlobalLock);	orig = ErrorFunc;	ErrorFunc = fncb;	UNLOCK(&nxGlobalLock);	return orig;}/** * This function suspends execution of the program for the specified * number of milliseconds. * * @param msecs Number of milliseconds to delay. * * @ingroup nanox_timer

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -