//
// daytime.cpp
// ~~~~~~~~~~~
// Demonstrates a service that runs as a daytime server. To
// test the service telnet to 127.0.0.1 on port 13.
//
// To register: daytime /register
// To unregister: daytime /unregister
// To debug: daytime /debug
// To start: net start DaytimeService
// To stop: net stop DaytimeService
// To pause: net pause DaytimeService
// To continue: net continue DaytimeService
//
#include <owl/pch.h>
#include <classlib/time.h>
#include <winsock.h>
#include <string.h>
#include "service.h"
class TDaytimeService : public TService
{
public:
const char* GetName() const { return "DaytimeService"; }
const char* GetDisplayName() const { return "Daytime Service"; }
bool Init();
void Run();
void Cleanup();
void PauseBegin();
void PauseEnd();
private:
SOCKET Socket;
};
bool TDaytimeService::Init()
{
// load the winsock dll
//
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData))
{
Log("Unable to load Winsock DLL");
return false;
}
// create a socket for accepting connections
//
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket == INVALID_SOCKET)
{
Log("Unable to create socket");
return false;
}
// bind the socket to the port
//
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(IPPORT_DAYTIME);
if (bind(Socket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
Log("Unable to bind socket");
closesocket(Socket);
return false;
}
// mark the socket as a listener
//
if (listen(Socket, SOMAXCONN) == SOCKET_ERROR)
{
Log("Unable to mark socket for listening");
closesocket(Socket);
return false;
}
return true;
}
void TDaytimeService::Run()
{
SOCKET accepted;
while (!CheckStop())
{
// wait for a period for something to accept from the socket
//
struct fd_set readfds;
struct timeval timeout;
FD_ZERO(&readfds);
FD_SET(Socket, &readfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
int n = select(FD_SETSIZE, &readfds, 0, 0, &timeout);
// select failed, log the error and exit
//
if (n < 0)
{
Log("Call to select failed");
SetStatus(SERVICE_STOPPED, 1);
return;
}
// select timed out
//
if (n == 0)
continue;
// Accept the waiting connection
//
accepted = accept(Socket, 0, 0);
if (accepted == INVALID_SOCKET)
{
Log("Call to accept failed");
SetStatus(SERVICE_STOPPED, 1);
return;
}
// Send the day and time down the socket
//
string dateString = TTime().AsString();
send(accepted, dateString.c_str(), dateString.length(), 0);
closesocket(accepted);
}
}
void TDaytimeService::Cleanup()
{
closesocket(Socket);
WSACleanup();
}
void TDaytimeService::PauseBegin()
{
Log("DaytimeService pausing.");
}
void TDaytimeService::PauseEnd()
{
Log("DaytimeService continuing.");
}
int main(int argc, char* argv[])
{
TDaytimeService service;
if (argc > 1 && stricmp(argv[1], "/register") == 0)
service.Register();
else if (argc > 1 && stricmp(argv[1], "/unregister") == 0)
service.Unregister();
else if (argc > 1 && stricmp(argv[1], "/debug") == 0)
service.Start(argc, argv);
else
service.Start();
return 0;
}