FrontPage|FindPage|TitleIndex|RecentChanges|RSS source_epsocket_v2.h
 
/* ----------------------------------------------------------

 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  

last modified 2004-06-25 17:53:33
EditText|FindPage|DeletePage|LikePages|