?? srvctrl.c
字號(hào):
/********************************************************************
** WebSrv -- SrvCtrl.c
**
** Steven Lee 2002.11
********************************************************************/
#include <Windows.h>
#include <string.h>
#include <TCHAR.h>
#include <stdio.h>
#ifdef _DEBUG
//#define _LOG_USERS
//#define _DEBUG_VIEW_REQUEST
//#define _DEBUG_VIEW_RESPONSE
//#define _DEBUG_VIEW_RESHEAD
#endif
#include "SrvCtrl.h"
#include "WinSockEx.h"
#include "WebSrvDefs.h"
#define MAX_MSG_NUM 16
SERVERINFOS g_server; //server messages
DWORD g_dwMaxUsers; //max users number
DWORD g_dwCurUsers = 0; //current users number
TCHAR g_szWebRoot[MAX_PATH]; //server root directory
HANDLE g_hLogFile = INVALID_HANDLE_VALUE; //server logfile
void InitSrvCtrl()
{
g_server.bTerminate = FALSE;
g_server.hSrvSocket = INVALID_SOCKET;
g_server.nPort = DEFAULT_SRV_PORT;
g_server.hSrvThread = NULL;
g_dwMaxUsers = DEFAULT_MAX_USERS;
g_dwCurUsers = 0;
_tcscpy( g_szWebRoot,_T(".\\wwwroot") );
g_hLogFile = CreateFile( _T(".\\WebSrv.log"),GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL );
}
void ReleaseSrvCtrl()
{
if( g_hLogFile != INVALID_HANDLE_VALUE )
CloseHandle( g_hLogFile );
}
BOOL WINAPI ConsoleCtrlEvent( DWORD dwCtrlType )
{
switch( dwCtrlType )
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
StopServer(5000);
ReleaseWinSocket();
ReleaseSrvCtrl();
break;
}
return TRUE;
}
BOOL StartServer(LPTSTR lpszError)
{
DWORD dwThrdID;
g_server.hSrvSocket = CreateSrvSocket( g_server.nPort,lpszError );
if( g_server.hSrvSocket == INVALID_SOCKET )
return FALSE;
g_server.hSrvThread = CreateThread( NULL,0,(LPTHREAD_START_ROUTINE)SrvThrdProc,
(LPVOID)&g_server,0,&dwThrdID );
if( g_server.hSrvThread == NULL )
{
if( lpszError != NULL )
_stprintf( lpszError,_T("create server thread failed\n") );
CloseSrvSocket( g_server.hSrvSocket );
return FALSE;
}
g_server.bTerminate = FALSE;
LogServerMessage( _T("Server Started"),INVALID_SOCKET );
return TRUE;
}
BOOL StopServer(DWORD dwTimeOut)
{
g_server.bTerminate = TRUE;
if( g_server.hSrvThread != NULL )
{
if( WaitForSingleObject( g_server.hSrvThread,dwTimeOut ) != WAIT_OBJECT_0 )
{
TerminateThread( g_server.hSrvThread,1 );
return FALSE;
}
CloseHandle( g_server.hSrvThread );
g_server.hSrvThread = NULL;
}
LogServerMessage( _T("Server Stopped"),INVALID_SOCKET );
return TRUE;
}
DWORD WINAPI SrvThrdProc(LPVOID lpParam)
{
LPSERVERINFOS lpSrvInfos = (LPSERVERINFOS)lpParam;
fd_set fds;
struct timeval timeout;
int nErr;
SOCKET hSocket;
struct sockaddr_in client;
int nAddrLen = sizeof(struct sockaddr_in);
HANDLE hClientThrd;
DWORD dwCltThrdId;
timeout.tv_sec = 0;
timeout.tv_usec = 500;
while( !lpSrvInfos->bTerminate )
{
FD_ZERO(&fds);
FD_SET(lpSrvInfos->hSrvSocket,&fds);
nErr = select( lpSrvInfos->hSrvSocket + 1,&fds,NULL,NULL,&timeout );
if( nErr == WSAEINVAL )
continue;
else if( nErr == SOCKET_ERROR )
return 1;
if( FD_ISSET(lpSrvInfos->hSrvSocket,&fds) )
{
hSocket = accept( lpSrvInfos->hSrvSocket,(struct sockaddr*)&client,&nAddrLen );
if( hSocket == INVALID_SOCKET )
{
_tprintf( _T("socket accept failed!existing...\n") );
break;
}
if( (g_dwMaxUsers > 0) && (g_dwCurUsers >= g_dwMaxUsers) )
{
closesocket( hSocket );
continue;
}
hClientThrd = CreateThread( NULL,0,(LPTHREAD_START_ROUTINE)CltThrdProc,
(LPVOID)hSocket,0,&dwCltThrdId );
if( hClientThrd == NULL )
{
_tprintf( _T("cannot create client thread.\n") );
break;
}
CloseHandle( hClientThrd );
}
}
TerminateSrvSocket( lpSrvInfos->hSrvSocket );
lpSrvInfos->hSrvSocket = INVALID_SOCKET;
lpSrvInfos->bTerminate = TRUE;
Sleep(1000);
return 0;
}
DWORD WINAPI CltThrdProc(LPVOID lpParam)
{
SOCKET hSocket = (SOCKET)lpParam;
fd_set fds;
int nErr;
int nRecvLen;
struct timeval timeout;
TCHAR szRecvBuf[MAX_SOCKET_BUF];
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
g_dwCurUsers++;
#ifdef _LOG_USERS
LogServerMessage( _T("User Log In"),hSocket );
#endif
while( !g_server.bTerminate )
{
FD_ZERO(&fds);
FD_SET(hSocket,&fds);
nErr = select( hSocket + 1,&fds,NULL,NULL,&timeout );
if( nErr == WSAEINVAL )
continue;
else if( nErr == SOCKET_ERROR )
break;
if( FD_ISSET(hSocket,&fds) )
{
ZeroMemory( szRecvBuf,MAX_SOCKET_BUF );
nRecvLen = ReadFromSocket( hSocket,szRecvBuf,
MAX_SOCKET_BUF * sizeof(TCHAR),NULL );
if( nRecvLen <= 0 )
break;
#ifdef _DEBUG_VIEW_REQUEST
printf( "\nRequest Message:\n" );
_tprintf( szRecvBuf );
#endif
if( !SendSrvResponse( hSocket,szRecvBuf ) )
break;
}
}
#ifdef _LOG_USERS
LogServerMessage( _T("User Log Out"),hSocket );
#endif
closesocket( hSocket );
g_dwCurUsers--;
return 0;
}
BOOL ServerRunning()
{
return !g_server.bTerminate;
}
UINT SetServerPort(UINT nPort)
{
if( (g_server.hSrvSocket == INVALID_SOCKET) && (nPort > 0) )
g_server.nPort = nPort;
return g_server.nPort;
}
int SetMaxUsers(int dwMax)
{
if( dwMax > 0 )
g_dwMaxUsers = dwMax;
return g_dwMaxUsers;
}
BOOL GetHTTPFileName(LPCTSTR lpszHeader,LPSTR lpszHTTPFile,SOCKET s)
{
LPSTR lpStart,lpEnd;
TCHAR lpStrTmp[MAX_PATH];
int i;
if( _tcsnicmp( lpszHeader,_T("Get"),3 ) != 0 )
{
LogServerMessage( _T("Unknown HTTP Message Format."),s );
return FALSE;
}
lpStart = _tcschr( lpszHeader,_T('/') );
lpEnd = _tcschr( lpStart,_T(' ') );
ZeroMemory( lpStrTmp,MAX_PATH * sizeof(TCHAR) );
_tcsncpy( lpStrTmp,lpStart,lpEnd - lpStart );
if( _tcslen( lpStrTmp ) == 1 )
_stprintf( lpszHTTPFile,_T("%s\\Index.html"),g_szWebRoot );
else
{
for( i=0;i<(lpEnd - lpStart);i++ )
if( lpStrTmp[i] == _T('/') )
lpStrTmp[i] = _T('\\');
_stprintf( lpszHTTPFile,_T("%s%s"),g_szWebRoot,lpStrTmp );
}
return TRUE;
}
BOOL GetHTTPVersion(LPCTSTR lpszHeader,int* lpnMajor,int* lpnMinor)
{
LPTSTR lpStart,lpEnd;
TCHAR szNumber[10];
lpStart = _tcsrchr( lpszHeader,_T('/') );
lpEnd = _tcsrchr( lpszHeader,_T('.') );
if( lpStart && lpEnd )
{
lpStart++;
ZeroMemory( szNumber,10 * sizeof(TCHAR) );
_tcsncpy( szNumber,lpStart,lpEnd - lpStart );
*lpnMajor = atoi( szNumber );
lpEnd++;
*lpnMinor = atoi( lpEnd );
return TRUE;
}
return FALSE;
}
BOOL ReqHTTPFileExists(LPTSTR lpszFile)
{
LPTSTR lpExt;
if( GetFileAttributes(lpszFile) != (DWORD)-1 )
return TRUE;
lpExt = _tcsrchr( lpszFile,_T('.') );
if( lpExt != NULL )
{
if( _tcsicmp(lpExt,_T(".htm")) == 0 )
_tcscat( lpszFile,_T("l") );
else if( (_tcsicmp(lpExt,_T(".html")) == 0) && (_tcslen(lpszFile) > 0) )
lpszFile[_tcslen(lpszFile) - 1] = _T('\0');
return GetFileAttributes(lpszFile) != (DWORD)-1;
}
return FALSE;
}
BOOL SendSrvResponse(SOCKET hSocket,LPTSTR pszRecv)
{
const TCHAR seps[] = _T("\r\n");
TCHAR szResponse[MAX_SOCKET_BUF];
TCHAR szHTTPFile[MAX_PATH];
PCHAR strTok;
BOOL bFileOK = FALSE;
HANDLE hFile;
DWORD dwFileSize,dwToRead,dwRead;
HTTPHEADER httpHead;
int nVerMajor,nVerMinor;
strTok = _tcstok( pszRecv,seps );
if( (!GetHTTPFileName( strTok,szHTTPFile,hSocket ))
|| (!GetHTTPVersion(strTok,&nVerMajor,&nVerMinor) ) )
httpHead.httpRes = RES_BADREQ;
else
{
if( !HTTPVersionSupport( nVerMajor,nVerMinor ) )
httpHead.httpRes = RES_NOTSUPPORT;
else if( !ReqHTTPFileExists( szHTTPFile ) )
httpHead.httpRes = RES_NOTFOUND;
else
{
httpHead.httpRes = RES_OK;
bFileOK = TRUE;
}
}
if( bFileOK )
{
GetContentType( szHTTPFile,httpHead.szContentType );
hFile = CreateFile( szHTTPFile,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );
if( hFile == INVALID_HANDLE_VALUE )
return FALSE;
dwFileSize = GetFileSize( hFile,NULL );
if( dwFileSize == INVALID_FILE_SIZE )
{
CloseHandle( hFile );
return FALSE;
}
httpHead.dwData = dwFileSize;
FillHTTPResHeader(szResponse,MAX_SOCKET_BUF,&httpHead);
SendToSocket( hSocket,szResponse,_tcslen(szResponse) * sizeof(TCHAR),NULL );
dwToRead = MAX_SOCKET_BUF;
while( dwFileSize > 0 )
{
ZeroMemory( szResponse,MAX_SOCKET_BUF * sizeof(TCHAR) );
if( !ReadFile( hFile,szResponse,dwToRead * sizeof(TCHAR),&dwRead,NULL ) )
{
LogServerMessage( _T("Error when read file."),INVALID_SOCKET );
CloseHandle( hFile );
return FALSE;
}
SendToSocket( hSocket,szResponse,dwRead,NULL );
dwFileSize -= dwRead;
}
CloseHandle( hFile );
}
else
{
if( FillHTTPResHeader( szResponse,MAX_SOCKET_BUF,&httpHead ) > 0 )
SendToSocket( hSocket,szResponse,strlen(szResponse),NULL );
}
#ifdef _DEBUG_VIEW_RESPONSE
printf( "\nResponse Message:\n" );
printf( szResponse );
printf( "\n" );
#endif
return FALSE;
}
DWORD FillHTTPResHeader(LPTSTR lpszResponse,int nSize,LPHTTPHEADER lpHeader)
{
static const TCHAR* lpcsResMsg[] = {
_T("200 OK\r\n"),
_T("301 Moved Permanently\r\n"),
_T("400 Bad Request\r\n"),
_T("404 Not Found\r\n"),
_T("505 HTTP Version Not Supported\r\n")
};
TCHAR szBuffer[MAX_PATH];
ZeroMemory( lpszResponse,nSize * sizeof(TCHAR) );
_tcscpy( lpszResponse,_T("HTTP/1.1 ") );
_tcscat( lpszResponse,lpcsResMsg[lpHeader->httpRes] );
_tcscat( lpszResponse,_T("Steven Lee--WebSrv/1.01\r\n") );
_tcscat( lpszResponse,_T("Connection: close\r\n") );
if( lpHeader->httpRes == RES_OK )
{
_tcscat( lpszResponse,_T("Accept-Ranges: bytes\r\n") );
_stprintf( szBuffer,_T("Content-Length: %d\r\n"),lpHeader->dwData );
_tcscat( lpszResponse,szBuffer );
_stprintf( szBuffer,_T("Content-Type: %s\r\n\r\n"),lpHeader->szContentType );
_tcscat( lpszResponse,szBuffer );
}
#ifdef _DEBUG_VIEW_RESHEAD
_tprintf( _T("%s\n"),lpszResponse );
#endif
return _tcslen( lpszResponse );
}
#define N_CONTENT_TYPE 7
void GetContentType(LPCTSTR lpszReqFile,LPTSTR lpszType)
{
static const TCHAR* lpcsType[N_CONTENT_TYPE * 2] = {
_T("htm"),_T("text/html"),
_T("html"),_T("text/html"),
_T("txt"),_T("text/html"),
_T("jpg"),_T("image/jpeg"),
_T("bmp"),_T("image/bitmap"),
_T("gif"),_T("image/gif"),
_T("swf"),_T("application/x-shockwave-flash")
};
int i;
LPTSTR lpszExtPos = _tcsrchr( lpszReqFile,_T('.') );
_tcscpy( lpszType,_T("*/*") );
lpszExtPos++;
for(i=0;i<N_CONTENT_TYPE;i++)
if( _tcsicmp(lpszExtPos,lpcsType[i * 2]) == 0 )
{
_tcscpy( lpszType,lpcsType[i * 2 + 1] );
break;
}
}
const DWORD GetUsersNumber()
{
return g_dwCurUsers;
}
void LogServerMessage(LPCTSTR szLog,SOCKET s)
{
TCHAR szBuffer[MAX_PATH];
SYSTEMTIME st;
TCHAR szIP[20];
DWORD dwWritten;
if( g_hLogFile == INVALID_HANDLE_VALUE )
return;
GetLocalTime( &st );
_stprintf( szBuffer,_T("[%d:%d:%d-%d]--"),st.wHour,
st.wMinute,st.wSecond,st.wMilliseconds );
_tcscat( szBuffer,szLog );
if( s != INVALID_SOCKET )
{
if( GetSocketIP( s,szIP,20 * sizeof(TCHAR) ) )
{
_tcscat( szBuffer,_T("--From ") );
_tcscat( szBuffer,szIP );
}
}
_tcscat( szBuffer,_T("\r\n") );
WriteFile( g_hLogFile,szBuffer,_tcslen(szBuffer) * sizeof(TCHAR),&dwWritten,NULL );
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -