/* ----------------------------------------------------------
epsocket.h by biscuit@actoz.com
for Linux 2.6.x
v2.1 06/25/2004
- Do ¿¡¼, int addrlen ÃʱâÈ ÇÏÁö ¾Ê¾Æ »ý±ä¹®Á¦ ¼öÁ¤ int addrlen=sizeof(addr);
- Do ¿¡¼, OnEventÀÇ °á°úó¸® ¼öÁ¤
v2.0 06/24/2004
- Idle Ãß°¡
- OnAccept¿¡¼ setsockopt·Î ¼ÒÄϹöÆÛ Á¶Á¤
v1.0 06/19/2004 first release
---------------------------------------------------------- */
#ifndef __EP_SOCKET_H__
#define __EP_SOCKET_H__
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <map>
#include <iostream>
#include <algorithm>
#include "ep.h"
#define EP_ERROR_NONE 1
#define EP_ERROR_READ_CLOSE 0
#define EP_ERROR_READ_GEN -1
#define EP_ERROR_WRITE_GEN -2
#define EP_ERROR -3
#define EP_ERROR_SOCKET -4
#define EP_ERROR_BIND -5
#define EP_ERROR_LISTEN -6
#define EP_ERROR_LISTEN_ALREADY -7
#define EP_ERROR_READ_OVERFLOW -21
#define EP_ERROR_WRITE_OVERFLOW -22
#define EP_ERROR_GEN -99
#define MAX_ADDR 24
#define MAX_PENDING 200
#define MAX_EVENTS 500
#define SIZE_OSBUF 8192
using namespace std;
template <class T>
class TEpollSocket
{
private :
int fd_listen;
map<int, T*> mapClient;
TEpoll *epoll;
int SetNonBlocking(int fd);
virtual int OnEvent(TEpollEvent &event);
virtual int OnAccept(const int fd, const char *ipaddr);
virtual int OnDisconnect(const int fd);
public :
TEpollSocket(const int size);
~TEpollSocket();
int Listen(const unsigned nport);
int Do(int nwait);
int Idle(void);
};
class TEpollClient
{
protected :
int fd;
char addr[MAX_ADDR];
public :
TEpollClient(const int fd, const char *addr)
{
this->fd = fd;
strcpy(this->addr, addr);
};
virtual int OnRead(void) = NULL;
virtual int OnWrite(void) = NULL;
virtual int OnError(const int nerror) = NULL;
virtual int OnIdle(void){};
};
template <typename T>
TEpollSocket<T>::TEpollSocket(const int size)
{
epoll = new TEpoll(size);
fd_listen = 0;
}
template <typename T>
TEpollSocket<T>::~TEpollSocket()
{
T *tmpClient;
while(! mapClient.empty() ){
tmpClient = mapClient.begin()->second;
delete tmpClient;
mapClient.erase(mapClient.begin());
}
if(fd_listen) close(fd_listen);
delete epoll;
}
template <typename T>
int TEpollSocket<T>::SetNonBlocking(int fd)
{
int value;
value = fcntl(fd, F_GETFL, 0);
value |= O_NONBLOCK;
fcntl(fd, F_SETFL, value);
return value;
}
template <typename T>
int TEpollSocket<T>::Listen(const unsigned nport)
{
if(fd_listen) return EP_ERROR_LISTEN_ALREADY;
struct sockaddr_in server_addr, client_addr;
int one=1, addrlen = sizeof(struct sockaddr_in);
if ((fd_listen = socket(PF_INET, SOCK_STREAM, 0)) < 0) return EP_ERROR_SOCKET;
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(nport);
setsockopt(fd_listen, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
if((bind(fd_listen, (struct sockaddr *)&server_addr, sizeof(server_addr))) < 0 ){
close(fd_listen);
return EP_ERROR_BIND;
}
if(listen(fd_listen, MAX_PENDING) < 0){
close(fd_listen);
return EP_ERROR_LISTEN;
}
// Epoll¿¡ Ãß°¡
epoll->Add(fd_listen);
return EP_ERROR_NONE;
}
template <typename T>
int TEpollSocket<T>::Do(int nwait)
{
int i, n, result;
int fd_client;
TEpollEvent events[MAX_EVENTS];
struct sockaddr_in addr;
char cliaddr[MAX_ADDR];
int addrlen;
if(! epoll->is_epoll_init){
perror("epoll init error\n");
exit(-1);
}
n = epoll->Do(events, MAX_EVENTS, nwait);
for(i=0; i<n; ++i){
// check new connection
if(fd_listen == events[i].data.fd){
// checking epoll_listensocket_list
fd_client = accept(events[i].data.fd, (struct sockaddr *) &addr, (socklen_t *) &addrlen);
if(fd_client < 0){
continue;
}
strcpy(cliaddr,inet_ntoa(addr.sin_addr));
OnAccept(fd_client, cliaddr);
} else {
if(OnEvent(events[i]) < 1)
OnDisconnect(events[i].data.fd);
break;
}
}
}
return n;
}
template <typename T>
int TEpollSocket<T>::OnAccept(const int fd, const char *ipaddr)
{
int send_buf = SIZE_OSBUF;
int recv_buf = SIZE_OSBUF;
SetNonBlocking(fd);
setsockopt(fd, IPPROTO_TCP, SO_SNDBUF, (char *)&send_buf, sizeof(send_buf));
setsockopt(fd, IPPROTO_TCP, SO_RCVBUF, (char *)&recv_buf, sizeof(recv_buf));
epoll->Add(fd);
mapClient[fd] = new T (fd, ipaddr);
return mapClient.size();
}
template <typename T>
int TEpollSocket<T>::OnEvent(TEpollEvent &event)
{
T *tmpClient = mapClient[event.data.fd];
if(! tmpClient) return 1; // ¿¡·¯´Â ¾Æ´Ï´Ù
int nread, nwrite;
char buf[1024];
if( event.events & EPOLLIN ){
nread = tmpClient->OnRead();
if( nread < 1) return tmpClient->OnError(nread);
}
if( event.events & EPOLLOUT){
nread = tmpClient->OnWrite();
if( nread < 1) return tmpClient->OnError(nread);
}
if( event.events & EPOLLERR){
return tmpClient->OnError(EP_ERROR_GEN);
}
return 1;
}
template <typename T>
int TEpollSocket<T>::OnDisconnect(const int fd)
{
T *tmpClient = mapClient[fd];
if(! tmpClient) return -1;
mapClient.erase(fd);
epoll->Delete(fd);
close(fd);
delete tmpClient;
return mapClient.size();
}
template <typename T>
int TEpollSocket<T>::Idle(void)
{
map<int, T *>::const_iterator it = mapClient.begin();
while(it != mapClient.end()){
it++ ->second->OnIdle();
}
return mapClient.size();
}
#endif