📄 server.c
字号:
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 + -