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

📄 server.c

📁 xmlrpc,用 XML表示得远程过程调用,基于web上得远程计算
💻 C
📖 第 1 页 / 共 2 页
字号:
	strcpy(z,r->server->filespath);
	strcat(z,r->uri);

	p=z+strlen(z)-1;
	if (*p=='/')
	{
		endingslash=TRUE;
		*p='\0';
	};

#ifdef ABYSS_WIN32
	p=z;
	while (*p)
	{
		if ((*p)=='/')
			*p='\\';

		p++;
	};
#endif	/* ABYSS_WIN32 */

	if (!FileStat(z,&fs))
	{
		ResponseStatusErrno(r);
		return TRUE;
	};

	if (fs.st_mode & S_IFDIR)
	{
		/* Redirect to the same directory but with the ending slash
		** to avoid problems with some browsers (IE for examples) when
		** they generate relative urls */
		if (!endingslash)
		{
			strcpy(z,r->uri);
			p=z+strlen(z);
			*p='/';
			*(p+1)='\0';
			ResponseAddField(r,"Location",z);
			ResponseStatus(r,302);
			ResponseWrite(r);
			return TRUE;
		};

#ifdef ABYSS_WIN32
		*p='\\';
#else
		*p='/';
#endif	/* ABYSS_WIN32 */
		p++;

		i=r->server->defaultfilenames.size;
		while (i-->0)
		{
  			*p='\0';		
  			strcat(z,(char *)(r->server->defaultfilenames.item[i]));
  			if (FileStat(z,&fs))
  				if (!(fs.st_mode & S_IFDIR))
					if (DateFromLocal(&objdate,fs.st_mtime))
						return ServerFileHandler(r,z,&objdate);
					else
						return ServerFileHandler(r,z,NULL);
		};

		*(p-1)='\0';
		
		if (!FileStat(z,&fs))
		{
			ResponseStatusErrno(r);
			return TRUE;
		};

		if (DateFromLocal(&objdate,fs.st_mtime))
			return ServerDirectoryHandler(r,z,&objdate);
		else
			return ServerDirectoryHandler(r,z,NULL);

	}
	else
		if (DateFromLocal(&objdate,fs.st_mtime))
			return ServerFileHandler(r,z,&objdate);
		else
			return ServerFileHandler(r,z,NULL);
}

abyss_bool ServerCreate(TServer *srv,
                        const char *name,
                        uint16 port,
                        const char *filespath,
                        const char *logfilename)
{
	srv->name=strdup(name);
	srv->port=port;
	srv->defaulthandler=ServerDefaultHandlerFunc;
	srv->filespath=strdup(filespath);
	srv->keepalivetimeout=15;
	srv->keepalivemaxconn=30;
	srv->timeout=15;
	srv->advertise=TRUE;
#ifdef _UNIX
	srv->pidfile=srv->uid=srv->gid=(-1);
#endif	/* _UNIX */

	ListInit(&srv->handlers);
	ListInitAutoFree(&srv->defaultfilenames);

	if (logfilename)
		return LogOpen(srv,logfilename);
	else
	{
		srv->logfile=(-1);
		return TRUE;
	};
}

void ServerFree(TServer *srv)
{
	free(srv->name);
	free(srv->filespath);
	ListFree(&srv->handlers);
	ListInitAutoFree(&srv->defaultfilenames);
	LogClose(srv);
}

void ServerFunc(TConn *c)
{
	TSession r;
	uint32 i,ka;
	abyss_bool treated;
	URIHandler *hl=(URIHandler *)(c->server)->handlers.item;

	ka=c->server->keepalivemaxconn;

	while (ka--)
	{
		RequestInit(&r,c);

		/* Wait to read until timeout */
		if (!ConnRead(c,c->server->keepalivetimeout))
			break;

		if (RequestRead(&r))
		{
			/* Check if it is the last keepalive */
			if (ka==1)
				r.keepalive=FALSE;

			r.cankeepalive=r.keepalive;

			if (r.status==0)
				if (r.versionmajor>=2)
					ResponseStatus(&r,505);
				else if (!RequestValidURI(&r))
					ResponseStatus(&r,400);
				else
				{
					i=c->server->handlers.size;
					treated=FALSE;

					while (i>0)
					{
						i--;
						if ((hl[i])(&r))
						{
							treated=TRUE;
							break;
						};
					};

					if (!treated)
						((URIHandler)(c->server->defaulthandler))(&r);
				};
		};
       		
		HTTPWriteEnd(&r);

		if (!r.done)
			ResponseError(&r);

		SessionLog(&r);

		if (!(r.keepalive && r.cankeepalive))
			break;

		/**************** Must adjust the read buffer *****************/
		ConnReadInit(c);		
	};

	RequestFree(&r);
	SocketClose(&(c->socket));
}

void ServerInit(TServer *srv)
{
	/********* Must check errors from these functions *************/
	if (!SocketInit())
		TraceExit("Can't initialize TCP sockets\n");;

	if (!SocketCreate(&srv->listensock))
		TraceExit("Can't create a socket\n");;

	if (!SocketBind(&srv->listensock,NULL,srv->port))
		TraceExit("Can't bind\n");

	if (!SocketListen(&srv->listensock,MAX_CONN))
		TraceExit("Can't listen\n");
};

/* With pthread configuration, our connections run as threads of a
   single address space, so we manage a pool of connection
   descriptors.  With fork configuration, our connections run as
   separate processes with their own memory, so we don't have the
   pool.
*/

static abyss_bool const usingPthreadsForConnections = 
#ifdef _THREAD
TRUE;
#else
FALSE;
#endif



static void 
ServerRunThreaded(TServer *srv)
{
	uint32 i;
	TSocket s,ns;
	TIPAddr peerIpAddr;
	TConn *c;

	/* Connection array from Heap. Small systems might not
	 * have the "stack_size" required to have the array of
	 * connections right on it */
	c = (TConn *)malloc( sizeof( TConn ) * MAX_CONN );

	for (i=0;i<MAX_CONN;i++)
		c[i].inUse = FALSE;

	s=srv->listensock;

	while( 1 )
	{
		/* collect all threads resources for closed connections */
		for (i=0;i<MAX_CONN;i++)
		{
			if( c[i].inUse && ( c[i].connected == FALSE ) )
			{
				ConnClose( &c[i] );
				c[i].inUse = FALSE;
			}
		}
		
		for (i=0; i<MAX_CONN && c[i].inUse; ++i);

		if (i==MAX_CONN)
		{
            /* Every connection descriptor was in use. */
			ThreadWait(2000);
			continue;
		};

		if (SocketAccept(&s,&ns,&peerIpAddr))
		{
            abyss_bool success;
			c[i].inUse = TRUE;
			success = ConnCreate2(&c[i], srv, ns, peerIpAddr, &ServerFunc, 
                                  ABYSS_BACKGROUND);
            if (success)
			{
				ConnProcess(&c[i]);
			}
			else
			{
				SocketClose(&ns);
				c[i].inUse = FALSE;
			}
		}
		else
			TraceMsg("Socket Error=%d\n", SocketError());
	}
	/* We never get here, but it's conceptually possible for someone to 
       terminate a server normally, so... 
    */
	free( c );
}



static void 
ServerRunForked(TServer *srv)
{
	TSocket s,ns;
	TConn c;
	TIPAddr ip;

	s=srv->listensock;

	while (1)
	{
		if (SocketAccept(&s,&ns,&ip))
		{
            abyss_bool success;
            success = ConnCreate2(&c, 
                                  srv, ns, ip, ServerFunc, ABYSS_BACKGROUND);

                /* ConnCreate2() forks.  Child does not return. */
            if (success)
                ConnProcess(&c);

            SocketClose(&ns); /* Close parent's copy of socket */
		}
		else
			TraceMsg("Socket Error=%d\n", SocketError());
	};
}



void 
ServerRun(TServer * const serverP) {
    if (usingPthreadsForConnections)
        ServerRunThreaded(serverP);
    else
        ServerRunForked(NULL);
}



/* ServerRunOnce() supplied by Brian Quinlan of ActiveState. */

/* Bryan Henderson found this to be completely wrong on 2001.11.29
   and changed it so it does the same thing as ServerRun(), but only
   once.

   The biggest problem it had was that when it forked the child (via
   ConnCreate(), both the parent and the child read the socket and
   processed the request!
*/


static void
closeParentSocketCopy(TSocket * socketP) {
/*----------------------------------------------------------------------------
   If we're doing forked connections, close the indicated socket because it
   is the parent's copy and the parent doesn't need it.  If we're doing
   threaded connections, then there's no such thing as a parent's copy, so
   nothing to close.
-----------------------------------------------------------------------------*/
#ifndef _THREAD
    SocketClose(socketP);
#endif
}


void ServerRunOnce2(TServer *           const srv,
                    enum abyss_foreback const foregroundBackground)
{
      TConn connection;
      TSocket listenSocket;
      TSocket connectedSocket;
      TIPAddr remoteAddr;
      abyss_bool succeeded;

      srv->keepalivemaxconn = 1;

      connection.connected = FALSE;
      connection.inUse = FALSE;

      listenSocket = srv->listensock;
      
      succeeded = SocketAccept(&listenSocket, &connectedSocket, &remoteAddr);
      if (succeeded) {
          abyss_bool success;
          success = ConnCreate2(&connection, 
                                srv, connectedSocket, remoteAddr, 
                                &ServerFunc,
                                foregroundBackground);
          if (success)
              ConnProcess(&connection);
          closeParentSocketCopy(&connectedSocket);
      } else
          TraceMsg("Socket Error=%d\n", SocketError());
}

void ServerRunOnce(TServer *srv)
{
    ServerRunOnce2(srv, ABYSS_BACKGROUND);
}

abyss_bool ServerAddHandler(TServer *srv,URIHandler handler)
{
	return ListAdd(&srv->handlers,handler);
}

void ServerDefaultHandler(TServer *srv,URIHandler handler)
{
	srv->defaulthandler=handler;
}

abyss_bool LogOpen(TServer *srv, const char *filename)
{
	if (FileOpenCreate(&(srv->logfile),filename,O_WRONLY | O_APPEND))
		if (MutexCreate(&(srv->logmutex)))
			return TRUE;
		else
		{
			FileClose(&(srv->logfile));
			srv->logfile=(-1);
		};

	TraceMsg("Can't open log file '%s'",filename);
	return FALSE;
}

void LogWrite(TServer *srv,char *c)
{
	if ((srv->logfile)==(-1))
		return;

	if (!MutexLock(&(srv->logmutex)))
		return;

	FileWrite(&(srv->logfile),c,strlen(c));
	FileWrite(&(srv->logfile),LBR,strlen(LBR));

	MutexUnlock(&(srv->logmutex));
}

void LogClose(TServer *srv)
{
	if ((srv->logfile)==(-1))
		return;

	FileClose(&(srv->logfile));
	MutexFree(&(srv->logmutex));
}

abyss_bool SessionLog(TSession *s)
{
	char z[1024];
	uint32 n;

	if (s->requestline == NULL)
		return FALSE;

	if (strlen(s->requestline)>1024-26-50)
		s->requestline[1024-26-50]='\0';

	n=sprintf(z,"%d.%d.%d.%d - %s - [",IPB1(s->conn->peerip),IPB2(s->conn->peerip),IPB3(s->conn->peerip),IPB4(s->conn->peerip),(s->user?s->user:""));

	DateToLogString(&s->date,z+n);

	sprintf(z+n+26,"] \"%s\" %d %d",s->requestline,s->status,s->conn->outbytes);

	LogWrite(s->server,z);
	return TRUE;
}

⌨️ 快捷键说明

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