testiocpecho.cpp 4.4 KB
/*
 * Copyright 2008 Stephen Liu
 * For license terms, see the file COPYING along with this library.
 */

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <assert.h>

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include "spwin32iocp.hpp"
#include "spiocpserver.hpp"
#include "spiocplfserver.hpp"

#include "spsession.hpp"
#include "spbuffer.hpp"
#include "spmsgdecoder.hpp"
#include "sprequest.hpp"
#include "sphandler.hpp"
#include "sputils.hpp"
#include "spgetopt.h"

#pragma comment(lib,"ws2_32")
#pragma comment(lib,"mswsock")
#pragma comment(lib,"advapi32")

class SP_EchoHandler : public SP_Handler {
public:
	SP_EchoHandler(){}
	virtual ~SP_EchoHandler(){}

	// return -1 : terminate session, 0 : continue
	virtual int start( SP_Request * request, SP_Response * response ) {
		request->setMsgDecoder( new SP_MultiLineMsgDecoder() );
		response->getReply()->getMsg()->append(
			"Welcome to line echo server, enter 'quit' to quit.\r\n" );

		return 0;
	}

	// return -1 : terminate session, 0 : continue
	virtual int handle( SP_Request * request, SP_Response * response ) {
		SP_MultiLineMsgDecoder * decoder = (SP_MultiLineMsgDecoder*)request->getMsgDecoder();
		SP_CircleQueue * queue = decoder->getQueue();

		int ret = 0;
		for( ; NULL != queue->top(); ) {
			char * line = (char*)queue->pop();

			if( 0 != strcasecmp( line, "quit" ) ) {
				response->getReply()->getMsg()->append( line );
				response->getReply()->getMsg()->append( "\r\n" );
			} else {
				response->getReply()->getMsg()->append( "Byebye\r\n" );
				ret = -1;
			}

			free( line );
		}

		return ret;
	}

	virtual void error( SP_Response * response ) {}

	virtual void timeout( SP_Response * response ) {}

	virtual void close() {}
};

class SP_EchoHandlerFactory : public SP_HandlerFactory {
public:
	SP_EchoHandlerFactory() {}
	virtual ~SP_EchoHandlerFactory() {}

	virtual SP_Handler * create() const {
		return new SP_EchoHandler();
	}
};

void IncreaseConnections()
{
	SetProcessWorkingSetSize( GetCurrentProcess(),
			10 * 1024 * 1024, 400 * 1024 * 1024 );

	DWORD minSize = 0, maxSize = 0;
	GetProcessWorkingSetSize( GetCurrentProcess(), &minSize, &maxSize );
	printf( "WorkingSetSize min %d(%d), max %d(%d)\n",
			minSize, minSize / 4096, maxSize, maxSize / 4096 );

	HKEY hKey;

	/* http://support.microsoft.com/default.aspx?scid=kb;EN-US;314053 */
	printf("Writing to registry... \n");
	if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
			"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Winsock", 0,
			KEY_WRITE, &hKey ) != ERROR_SUCCESS ) {
		printf( "RegOpenKeyEx fail, errno %d\n", GetLastError() );
	} else {
		DWORD dwCon = 0xfffffe;
		if( RegSetValueEx( hKey, "TcpNumConnections", 0, REG_DWORD,
				(const BYTE *) &dwCon, sizeof(dwCon) ) != ERROR_SUCCESS ) {
			printf( "RegSetValueEx fail, errno %d\n", GetLastError() );
		}
		RegCloseKey( hKey );
	}
}

int main( int argc, char * argv[] )
{
	int port = 3333, maxThreads = 4, maxConnections = 20000;
	int timeout = 120, reqQueueSize = 10000;
	const char * serverType = "lf";

	extern char *optarg ;
	int c ;

	while( ( c = getopt ( argc, argv, "p:t:o:c:q:s:v" )) != EOF ) {
		switch ( c ) {
			case 'p' :
				port = atoi( optarg );
				break;
			case 't':
				maxThreads = atoi( optarg );
				break;
			case 'c':
				maxConnections = atoi( optarg );
				break;
			case 'o':
				timeout = atoi( optarg );
				break;
			case 'q':
				reqQueueSize = atoi( optarg );
				break;
			case 's':
				serverType = optarg;
				break;
			case '?' :
			case 'v' :
				printf( "Usage: %s [-p <port>] [-t <threads>] [-c <connections>] "
						"[-o <timeout>] [-q <queue size>] [-s <hahs|lf>]\n", argv[0] );
				exit( 0 );
		}
	}

	if( 0 != sp_initsock() ) assert( 0 );

	//Warning: This modifies your operating system. Use it at your own risk.
	//IncreaseConnections();

	sp_syslog( LOG_DEBUG, "server type %s", serverType );

	if( 0 == strcasecmp( serverType, "hahs" ) ) {
		SP_IocpServer server( "", port, new SP_EchoHandlerFactory() );
		server.setTimeout( timeout );
		server.setMaxThreads( maxThreads );
		server.setReqQueueSize( reqQueueSize, "Byebye\r\n" );
		server.setMaxConnections( maxConnections );
		server.runForever();
	} else {
		SP_IocpLFServer server( "", port, new SP_EchoHandlerFactory() );
		server.setTimeout( timeout );
		server.setMaxThreads( maxThreads );
		server.setReqQueueSize( reqQueueSize, "Byebye\r\n" );
		server.setMaxConnections( maxConnections );
		server.runForever();
	}

	return 0;
}