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

📄 client.c

📁 神龙卡开发原代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com> * 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>#elif __ECOS#include <netinet/in.h>#include <sys/select.h>#include <cyg/kernel/kapi.h>#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"#define GR_CLOSE_FIX	1	/* dirty hack attempts to fix GrClose hang bug*/#define SHM_BLOCK_SIZE	4096#ifndef __ECOS/* exported global data */int 	   nxSocket = -1;	/* The network socket descriptor */#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;/* 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;#endif/* * Queue an event in FIFO for later retrieval. */static voidQueueEvent(GR_EVENT *ep){	EVENT_LIST *	elp;	EVENT_LIST *	prevelp;        ACCESS_PER_THREAD_DATA()	elp = malloc(sizeof(EVENT_LIST));	if (elp) {		elp->event = *ep;		elp->next = NULL;		/* add as last entry on list*/		if (!evlist) {			evlist = elp;			return;		}		prevelp = evlist;		while (prevelp->next)			prevelp = prevelp->next;		prevelp->next = elp;	}}/* * Retrieve first event in FIFO event queue. */static voidGetNextQueuedEvent(GR_EVENT *ep){        ACCESS_PER_THREAD_DATA()	*ep = evlist->event;	evlist = evlist->next;}/* * 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. Returns 0 on success or -1 on * failure. */static int GrReadBlock(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\n", i);			return -1;		}		v += i;	}	return 0;}/* * Read a byte of data from the server. */static int GrReadByte(){	unsigned char c;	if(GrReadBlock(&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. */static void GrCheckForClientData(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;		GrReadBlock(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. */static int GrCheckBlockType(short packettype){	short		b;	GR_EVENT	event;	while (GrReadBlock(&b,sizeof(b)) != -1) {		if (b == packettype)			return b;		if (b == GrNumGetNextEvent) {			/*EPRINTF("nxclient %d: Storing event (expected %d)\n",				getpid(), packettype);*/#if 0			/* We only need to handle one event, since the next			 * event won't arrive until the next GrPrepareSelect()			 * has been called, and by then we have already			 * handled this event in GrServiceSelect(). If			 * GrPrepareSelect() is never called, then we should			 * never get here either, so that is cool too.			 */			GrReadBlock(&storedevent_data,				    sizeof(storedevent_data));			GrCheckForClientData(&storedevent_data);			storedevent = 1;#endif			/* read event and queue it for later processing*/			GrReadBlock(&event, sizeof(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 GrReadBlock but * make sure the response is of the right kind, e.g. store the event that * may have sneaked into the stream. */static int GrTypedReadBlock(void *b, int n, int type){	int r;   	r = GrCheckBlockType(type);	if (r != type)		return -1;	return GrReadBlock(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. */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;		}	}}/** * GrFlush: * * Flush the message buffer of any messages it may contain. */void GrFlush(void){	nxFlushReq(0L,1);}/** * GrOpen: * @Returns: the fd of the connection to the server or -1 on failure * * Open a connection to the graphics server. */int GrOpen(void){	size_t 		size;	nxOpenReq	req;	int		tries;	int		ret = 0;#if ELKS	struct sockaddr_na name;#define ADDR_FAM AF_NANO#elif defined(__ECOS)	struct sockaddr_in name;#define ADDR_FAM AF_INET#else	struct sockaddr_un name;#define ADDR_FAM AF_UNIX#endif	ACCESS_PER_THREAD_DATA()		if (nxSocket == -1) {		if((nxSocket = socket(ADDR_FAM, SOCK_STREAM, 0)) == -1) {			nxSocket = -1;			return -1;		}        } else {            return nxSocket;        }#if ELKS	name.sun_family = AF_NANO;	name.sun_no = GR_NUMB_SOCKET;	size = sizeof(struct sockaddr_na);#elif defined(__ECOS)	name.sin_family = AF_INET;	name.sin_port = htons(6600);                    /* Nano-X server port*/	name.sin_addr.s_addr = inet_addr("127.0.0.1");  /* Loopback address*/	size = sizeof(struct sockaddr_in);#else	name.sun_family = AF_UNIX;	strcpy(name.sun_path, GR_NAMED_SOCKET);	size = (offsetof(struct sockaddr_un, sun_path) +		strlen(name.sun_path) + 1);#endif	/*	 * Try to open the connection for up to a second,	 * waiting 1/10 second between attempts.	 */	for (tries=1; tries<=10; ++tries) {		struct timespec req;		ret = connect(nxSocket, (struct sockaddr *) &name, size);		if (ret >= 0)			break;		req.tv_sec = 0;		req.tv_nsec = 100000000L;		nanosleep(&req, NULL);		EPRINTF("nxclient: retry connect attempt %d\n", tries);	}	if (ret == -1) {		close(nxSocket);		nxSocket = -1;		return -1;	}	/*	 * 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) {		printf("Oops! nxFlushReq() timed out, cowardly chickening "								"out!\n");		exit(127);	}}#endif/** * GrClose: * * Close the graphics device, flushing any waiting messages. *//* Vladimir Cotfas: hang in GrFlush() --> nxFlushReq(0L,1); */void GrClose(void){	ACCESS_PER_THREAD_DATA()#if GR_CLOSE_FIX	/* allow 1 second to flush*/	void * oldSignalHandler = signal(SIGALRM, mySignalhandler);	alarm(1);#endif	AllocReq(Close);	GrFlush();#if GR_CLOSE_FIX	alarm(0);	signal(SIGALRM, oldSignalHandler);#endif	close(nxSocket);	nxSocket = -1;}/** * GrDefaultErrorHandler: * @ep: the error event structure *  * The default error handler which 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 on stderr describing what error * occurred and what function it occured in, then exits. */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);	}}/** * GrSetErrorHandler: * @fncb: the function to call to handle error events * @Returns: the address of the previous error handler * * 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. */GR_FNCALLBACKEVENTGrSetErrorHandler(GR_FNCALLBACKEVENT fncb){	ACCESS_PER_THREAD_DATA()	GR_FNCALLBACKEVENT orig = ErrorFunc;	ErrorFunc = fncb;	return orig;}/** * GrDelay: * @msecs: number of milliseconds to delay * * This function suspends execution of the program for the specified * number of milliseconds. */voidGrDelay(GR_TIMEOUT msecs){	struct timeval timeval;	timeval.tv_sec = msecs / 1000;	timeval.tv_usec = msecs % 1000;	select(0, NULL, NULL, NULL, &timeval);}/** * GrGetScreenInfo: * @sip: pointer to a GR_SCREEN_INFO structure * * Fills in the specified GR_SCREEN_INFO structure. */void GrGetScreenInfo(GR_SCREEN_INFO *sip){	AllocReq(GetScreenInfo);	GrTypedReadBlock(sip, sizeof(GR_SCREEN_INFO),GrNumGetScreenInfo);}/** * GrGetSysColor: * @index: an index into the server's colour look up table * @Returns: the colour found at the specified index

⌨️ 快捷键说明

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