/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1992 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
//+---------------------------------------------------------------------------
//
// File: pop3svr.c
//
// Contents:
//
// Classes:
//
// Functions:
//
//----------------------------------------------------------------------------
#include "pop3srvp.h"
#pragma hdrstop
extern BOOL bServiceTerminating;
extern SOCKET sListener;
#define POP3_PORT 110
PCHAR Welcome = "+OK Welcome to the NT Example POP3 Server (POP3SRV)\r\n";
BOOL
AcceptClients (
HANDLE hCompletionPort
)
/*++
Routine Description:
This routine sets up a listening socket on the POP3 port, then
loops accepting incoming connections from clients. Whenever
it gets a connection, it sends the greeting message and starts
a read on the newly connected socket.
Arguments:
hCompletionPort - the completion port that the POP3SRV worker
threads are waiting on.
Return Value:
BOOL - FALSE if there was an error in starting the listening
socket.
--*/
{
SOCKET s;
SOCKADDR_IN sin;
int err;
BOOL bSuccess;
PCLIENT_CONTEXT lpClientContext;
DWORD dwBytesRead;
int zero;
//
// Create a listening socket that we'll use to accept incoming
// conections.
//
sListener = socket( AF_INET, SOCK_STREAM, 0 );
if ( sListener == INVALID_SOCKET ) {
return FALSE;
}
//
// Bind the socket to the POP3 well-known port.
//
sin.sin_family = AF_INET;
sin.sin_port = htons( POP3_PORT );
sin.sin_addr.s_addr = INADDR_ANY;
err = bind( sListener, (LPSOCKADDR)&sin, sizeof(sin) );
if ( err == SOCKET_ERROR ) {
closesocket( sListener );
return FALSE;
}
//
// Listen for incoming connections on the socket.
//
err = listen( sListener, 5 );
if ( err == SOCKET_ERROR ) {
closesocket( sListener );
return FALSE;
}
//
// Loop forever accepting connections from clients.
//
while ( TRUE ) {
s = accept( sListener, NULL, NULL );
if ( s == INVALID_SOCKET ) {
closesocket( sListener );
return FALSE;
}
//
// If the service if terminating, exit this thread.
//
if ( bServiceTerminating ) {
return FALSE;
}
//
// Allocate a socket context for the new connection. We use
// this context structure to track socket-level information
// about the client.
//
lpClientContext = LocalAlloc( 0, sizeof(*lpClientContext) );
if ( lpClientContext == NULL ) {
closesocket( s );
continue;
}
//
// Initialize the context structure.
//
lpClientContext->Socket = s;
lpClientContext->Context = CreatePop3Context( );
lpClientContext->Overlapped.Internal = 0;
lpClientContext->Overlapped.InternalHigh = 0;
lpClientContext->Overlapped.Offset = 0;
lpClientContext->Overlapped.OffsetHigh = 0;
lpClientContext->Overlapped.hEvent = NULL;
//
// Send the welcome banner.
//
err = send( s, Welcome, strlen(Welcome), 0 );
if ( err == SOCKET_ERROR ) {
LocalFree( lpClientContext );
closesocket( s );
continue;
}
// --- DavidTr: Slide 14(a) ----------------------------------------
//
// Associate the new socket with a completion port.
//
hCompletionPort = CreateIoCompletionPort(
(HANDLE)s,
hCompletionPort,
(DWORD)lpClientContext,
0
);
if ( hCompletionPort == NULL ) {
LocalFree( lpClientContext );
closesocket( s );
closesocket( sListener );
return FALSE;
}
// --- DavidTr: Slide 16 -------------------------------------------
//
// Disable send bufferring on the socket. Setting SO_SNDBUF
// to 0 causes winsock to stop bufferring sends and perform
// sends directly from our buffers, thereby reducing CPU
// usage.
//
zero = 0;
err = setsockopt( s, SOL_SOCKET, SO_SNDBUF, (char *)&zero, sizeof(zero) );
if ( err == SOCKET_ERROR ) {
LocalFree( lpClientContext );
closesocket( s );
closesocket( sListener );
return FALSE;
}
//
// Start an overlapped read on the socket. This read will
// complete in one of the worker threads, which will continue
// processing of the client.
//
lpClientContext->LastClientIo = ClientIoRead;
lpClientContext->BytesReadSoFar = 0;
bSuccess = ReadFile(
(HANDLE)s,
lpClientContext->Buffer,
sizeof(lpClientContext->Buffer),
&dwBytesRead,
&lpClientContext->Overlapped
);
if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
LocalFree( lpClientContext );
closesocket( s );
continue;
}
}
} // AcceptClients
VOID
CloseClient (
PCLIENT_CONTEXT lpClientContext,
BOOL bGraceful
)
/*++
Routine Description:
Terminates a connection with a client and frees up resources.
Arguments:
lpClientContext - a pointer to the context structure that contains
information about this client.
bGraceful - TRUE if the close should be graceful, FALSE otherwise.
Return Value:
None.
--*/
{
LINGER lingerStruct;
//
// If we're supposed to abort the connection, set the linger value
// on the socket to 0.
//
if ( !bGraceful ) {
lingerStruct.l_onoff = 1;
lingerStruct.l_linger = 0;
setsockopt( lpClientContext->Socket, SOL_SOCKET, SO_LINGER,
(char *)&lingerStruct, sizeof(lingerStruct) );
}
//
// Now close the socket handle. This will do an abortive or
// graceful close, as requested.
//
closesocket( lpClientContext->Socket );
//
// Free context structuyres.
//
LocalFree( lpClientContext->Context );
LocalFree( lpClientContext );
return;
} // CloseClient