/* Copyright (C) 2003 Frédéric Giudicelli (contact_nos@yahoo.com). All rights reserved. This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "SOCK_SERVER.h" #include #include #include "svintl.h" ServerConf::ServerConf(const ServerConf &other) { *this = other; } ServerConf::ServerConf() { m_LocalPort = 0; } ServerConf::~ServerConf() { } void ServerConf::set_BindAddress(const mString & BindAddress) { m_BindAddress = BindAddress; } const mString & ServerConf::get_BindAddress() const { return m_BindAddress; } void ServerConf::set_LocalPort(unsigned int LocalPort) { m_LocalPort = LocalPort; } unsigned int ServerConf::get_LocalPort() const { return m_LocalPort; } void ServerConf::set_ServerName(const mString & ServerName) { m_ServerName = ServerName; } const mString & ServerConf::get_ServerName() const { return m_ServerName; } bool ServerConf::operator=(const ServerConf &other) { m_BindAddress = other.m_BindAddress; m_LocalPort = other.m_LocalPort; m_ServerName = other.m_ServerName; return true; } bool ServerConf::operator==(const ServerConf &other) const { if(!(m_BindAddress == other.m_BindAddress)) return false; if(m_LocalPort != other.m_LocalPort) return false; if(!(m_ServerName == other.m_ServerName)) return false; return true; } void ServerConf::Load(const Config & Conf) { m_BindAddress = Conf.get_BindAddress(); m_LocalPort = Conf.get_LocalPort(); } SOCK_SERVER::SOCK_SERVER(int NumThreadsPool) { m_NumThreadsPool = NumThreadsPool; TotalSentBytes = 0; TotalRecvBytes = 0; TotalConnectionsCtr = 0; StartTime = 0; hThreadAccept.Create(ThreadProcAccept, this); NewpkiThread * newThread; //We create the initial threads for(int i=0; iCreate(ThreadProcConnection, this); AllThreads.push_back(newThread); } } } SOCK_SERVER::~SOCK_SERVER() { Stop(); size_t i; for(i=0; iAllThreads.size(); i++) { me_this->AllThreads[i]->Start(); } do { //Get socket state do { me_this->AcceptLock.EnterCS(); FD_ZERO(&rfds); FD_SET(me_this->SocketHandle, &rfds); tv.tv_sec = 0; tv.tv_usec = 100; sockt_state = select(me_this->SocketHandle + 1, &rfds, NULL, NULL, &tv); me_this->AcceptLock.LeaveCS(); } while(sockt_state == 0 && !me_this->ShouldStop()); //Is there a connection available if(!me_this->ShouldStop() && sockt_state > 0) { tempsock = accept(me_this->SocketHandle, (sockaddr *)&sockin, &size); if(tempsock != SOCKET_ERROR) { me_this->ActiveConnectionsLock.EnterCS(); //We don't make the user wait //We close his connection right away if(me_this->ActiveConnectionsList.size() >= (size_t)me_this->m_NumThreadsPool) { closesocket(tempsock); } else { me_this->WaitingConnectionsLock.EnterCS(); me_this->WaitingConnectionsList.push_back(tempsock); me_this->TotalConnectionsCtr++; me_this->WaitingConnectionsLock.LeaveCS(); } me_this->ActiveConnectionsLock.LeaveCS(); } else { LogInFile(SOCKET_LOG, _sv("%s : Could not accept a client"), me_this->m_Conf.get_ServerName().c_str()); } } } while(!me_this->ShouldStop() && sockt_state > 0); } void SOCK_SERVER::ThreadProcConnection(const NewpkiThread * Thread, void * Param) { SOCK_SERVER * me_this = (SOCK_SERVER *)Param; if(!me_this) return; long EntriesCount; SOCKET hSocket; sockaddr peername; sockaddr_in sockin; socklen_t namelen=sizeof(peername); mString clientip; unsigned int clientport; hSocket = 0; while(!me_this->ShouldStop()) { do { me_this->WaitingConnectionsLock.EnterCS(); EntriesCount = me_this->WaitingConnectionsList.size(); if(EntriesCount) { hSocket = me_this->WaitingConnectionsList.front(); me_this->WaitingConnectionsList.pop_front(); if(!hSocket) EntriesCount = 0; } me_this->WaitingConnectionsLock.LeaveCS(); if(!EntriesCount) { NewpkiThread::Sleep(500); } } while(!EntriesCount && !me_this->ShouldStop()); if(me_this->ShouldStop()) { if(EntriesCount) closesocket(hSocket); return; } if(getpeername(hSocket, &peername, &namelen)==SOCKET_ERROR) { LogInFile(SOCKET_LOG, _sv("%s : getpeername has failed"), me_this->m_Conf.get_ServerName().c_str()); closesocket(hSocket); continue; } memcpy(&sockin,&peername,sizeof(peername)); clientip = inet_ntoa(sockin.sin_addr); if(!clientip.size()) { LogInFile(SOCKET_LOG, _sv("%s : Unknown IP"), me_this->m_Conf.get_ServerName().c_str()); closesocket(hSocket); continue; } clientport = ntohs(sockin.sin_port); LogInFile(SOCKET_LOG, _sv("%s : Connection of %s:%d"), me_this->m_Conf.get_ServerName().c_str(), clientip.c_str(), clientport); me_this->AddActiveConnection(hSocket); me_this->OnConnection(clientip.c_str(), hSocket); me_this->DelActiveConnection(hSocket); LogInFile(SOCKET_LOG, _sv("%s : The client has closed the connection (%s:%d)"), me_this->m_Conf.get_ServerName().c_str(), clientip.c_str(), clientport); closesocket(hSocket); } } void SOCK_SERVER::Stop() { if(!Stopped) { Stopped = true; //We kill the active sockets KillActiveConnections(); LogInFile(SOCKET_LOG, _sv("%s : Stopping socket server..."), m_Conf.get_ServerName().c_str()); AcceptLock.EnterCS(); if(SocketHandle > 0) { closesocket(SocketHandle); SocketHandle = 0; } NewpkiDebug(LOG_LEVEL_DEBUG, m_Conf.get_ServerName().c_str(), _sv("Waiting for accept thread termination")); hThreadAccept.Stop(); NewpkiDebug(LOG_LEVEL_DEBUG, m_Conf.get_ServerName().c_str(), _sv("Accept thread terminated")); AcceptLock.LeaveCS(); size_t i; for(i=0; iStop(); NewpkiDebug(LOG_LEVEL_DEBUG, m_Conf.get_ServerName().c_str(), _sv("Connection thread #%d terminated"), i); } LogInFile(SOCKET_LOG, _sv("%s : Socket server is stopped"), m_Conf.get_ServerName().c_str()); } } void SOCK_SERVER::AddRecvBytes(unsigned long bytes) { StatsLock.EnterCS(); TotalRecvBytes += bytes; StatsLock.LeaveCS(); } void SOCK_SERVER::AddSentBytes(unsigned long bytes) { StatsLock.EnterCS(); TotalSentBytes += bytes; StatsLock.LeaveCS(); } void SOCK_SERVER::AddActiveConnection(SOCKET hSocket) { ActiveConnectionsLock.EnterCS(); TotalConnectionsCtr++; ActiveConnectionsList.push_back(hSocket); ActiveConnectionsLock.LeaveCS(); } void SOCK_SERVER::DelActiveConnection(SOCKET hSocket) { unsigned int i; ActiveConnectionsLock.EnterCS(); for(i=0; i 60) { result_len = (long)(len_datas / (len_secs/60)); if(result_len) { unit = "m"; } else { if(len_secs>3600) { result_len = (long)(len_datas / (len_secs/3600)); if(result_len) { unit = "h"; } } } } } return unit; } void SOCK_SERVER::PrintStats(bool CurrConnectionsStats) { time_t StopTime; time_t Duration; unsigned long avg_send; unsigned long avg_recv; unsigned long avg_conn; mString strDuration; unsigned long days; unsigned long hours; unsigned long mins; unsigned long secs; char * avg_send_unit; char * avg_recv_unit; char * avg_conn_unit; time(&StopTime); Duration = StopTime - StartTime; if(!Duration) { avg_send = 0; avg_recv = 0; avg_conn = 0; avg_send_unit = "s"; avg_recv_unit = "s"; avg_conn_unit = "s"; days = 0; hours = 0; mins = 0; secs = 0; } else { avg_send_unit = GetTimeUnit(TotalSentBytes + PkiClient::GetSentBytes(), Duration, avg_send); avg_recv_unit = GetTimeUnit(TotalRecvBytes + PkiClient::GetRecvBytes(), Duration, avg_recv); avg_conn_unit = GetTimeUnit(TotalConnectionsCtr, Duration, avg_conn); days = Duration/86400; Duration -= days*86400; hours = Duration/3600; Duration -= hours*3600; mins = Duration/60; secs = Duration - (mins*60); } strDuration.sprintf(_sv("%.2ld day(s) %.2ld hour(s) %.2ld minute(s) %.2ld seconde(s)"), days, hours, mins, secs); LogInFile(SOCKET_LOG, _sv("%s : Connections statistics:\n\tDuration: %s\n\tTotal connections: %ld\n\tTotal sent bytes: %ld\n\tTotal received bytes: %ld\n\tAverage number of connections: %ld connections/%s\n\tAverage reception bandwidth: %ld bytes/%s\n\tAverage send bandwidth: %ld bytes/%s"), m_Conf.get_ServerName().c_str(), strDuration.c_str(), TotalConnectionsCtr, TotalSentBytes, TotalRecvBytes, avg_conn, avg_conn_unit, avg_recv, avg_recv_unit, avg_send, avg_send_unit); if(CurrConnectionsStats) { ActiveConnectionsLock.EnterCS(); LogInFile(SOCKET_LOG, _sv("\tNumber of active connections: %d\n"), ActiveConnectionsList.size()); ActiveConnectionsLock.LeaveCS(); WaitingConnectionsLock.EnterCS(); LogInFile(SOCKET_LOG, _sv("\tNumber of waiting connections: %d\n"), WaitingConnectionsList.size()); WaitingConnectionsLock.LeaveCS(); } } bool SOCK_SERVER::ShouldStop() { return Stopped; } const ServerConf & SOCK_SERVER::GetConf() { return m_Conf; } bool SOCK_SERVER::DoListen() { sockaddr_in sockin; struct hostent * hostinf; char ip[30]; int i; memset(&sockin, 0, sizeof(sockin)); sockin.sin_family = AF_INET; sockin.sin_port = htons ((unsigned short)m_Conf.get_LocalPort()); if(m_Conf.get_BindAddress().size()) { hostinf = gethostbyname(m_Conf.get_BindAddress().c_str()); if(!hostinf || !hostinf->h_length) { LogInFile(SOCKET_LOG, _sv("%s : Unknown bind host %s"), m_Conf.get_ServerName().c_str(), m_Conf.get_BindAddress().c_str()); return false; } sprintf(ip, "%d.%d.%d.%d", (unsigned char)hostinf->h_addr_list[0][0], (unsigned char)hostinf->h_addr_list[0][1], (unsigned char)hostinf->h_addr_list[0][2], (unsigned char)hostinf->h_addr_list[0][3]); sockin.sin_addr.s_addr=inet_addr(ip); } else { sockin.sin_addr.s_addr = htonl(INADDR_ANY); } SocketHandle = socket(PF_INET, SOCK_STREAM, 0); if(SocketHandle == SOCKET_ERROR) { LogInFile(SOCKET_LOG, _sv("%s : Could not create the socket"), m_Conf.get_ServerName().c_str()); return false; } i = 1; if(setsockopt(SocketHandle, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i)) < 0) { LogInFile(SOCKET_LOG, _sv("%s : Could not set socket option: SO_REUSEADDR"), m_Conf.get_ServerName().c_str()); return false; } if(bind(SocketHandle,(sockaddr *)&sockin, sizeof(sockin)) == SOCKET_ERROR) { LogInFile(SOCKET_LOG, _sv("%s : Could not bind the socket"), m_Conf.get_ServerName().c_str()); return false; } if(listen(SocketHandle, 1) == SOCKET_ERROR) { LogInFile(SOCKET_LOG, _sv("%s : Could not listen on the socket"), m_Conf.get_ServerName().c_str()); return false; } LogInFile(SOCKET_LOG, _sv("%s : Socket server started"), m_Conf.get_ServerName().c_str()); OnServerStarted(); return true; }