FrontPage|FindPage|TitleIndex|RecentChanges|RSS source_epsocket.h
 
epsocket.h

/* ----------------------------------------------------------

 epsocket.h by biscuit@actoz.com 
 for Linux 2.6.x

 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 "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_GEN            -99

#define MAX_ADDR    24
#define MAX_PENDING 200
#define MAX_EVENTS  500

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);
};

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;

};

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 {
            switch(OnEvent(events[i])){
            case EP_ERROR_WRITE_GEN :
            case EP_ERROR_READ_GEN :
            case EP_ERROR_READ_CLOSE :
                OnDisconnect(events[i].data.fd);
                close(events[i].data.fd);
                epoll->Delete(events[i].data.fd);
                break;
            }
        }
    }

    return n;
}


template <typename T>
int TEpollSocket<T>::OnAccept(const int fd, const char *ipaddr)
{
    cout << "OnAccept\n";

    SetNonBlocking(fd);
    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 ){
        cout << "onRead\n";
        nread = tmpClient->OnRead();
        if( nread < 1) return tmpClient->OnError(nread);
    }
    if( event.events & EPOLLOUT){
        cout << "onWrite\n";
        nread = tmpClient->OnWrite();
        if( nread < 1) return tmpClient->OnError(nread);
    }
    if( event.events & EPOLLERR){
        cout << "onError\n";
        return tmpClient->OnError(EP_ERROR_GEN);
    }

    return 1;
}

template <typename T>
int TEpollSocket<T>::OnDisconnect(const int fd)
{
    cout << "OnDisconnect\n";

    T *tmpClient = mapClient[fd];
    if(! tmpClient) return -1;

    mapClient.erase(fd);
    delete tmpClient;

    return mapClient.size();
}

#endif

last modified 2004-06-24 12:34:30
EditText|FindPage|DeletePage|LikePages|