Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5760258
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: C/C++

2009-07-11 13:44:01

昨天晚上闲来无事,就想起之前的端口转发工具datapipe用着不爽,就打算把它重写。
debian-wangyao:~/Test/libevent/proxy$ ./datapipe
Usage: ./datapipe localport remoteport remotehost
debian-wangyao:~/Test/libevent/proxy$ ./proxy_epoll
Usage: proxy -l [localaddr]:port -r remoteaddr:port
debian-wangyao:~/Test/libevent/proxy$ ./proxy_libevent
Usage: proxy -l [localaddr]:port -r remoteaddr:port

昨天晚上加今天早上,写了两个版本的,一个是epoll的,一个是libevent的。

文件:proxy.tar.gz
大小:5KB
下载:下载
把libevent的代码贴出来:
proxy_libevent.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#include <event.h>
#include <evutil.h>

struct conn_info
{
    struct event *local_event;
    struct event *remote_event;
    int local_sock;
    int remote_sock;
};

void readEv(int fd, short event, void* arg);
void acceptEv(int fd, short event, void* arg);
void GoDaemon(void);
void read_address(const char *str, struct sockaddr_in *sin);

int main(int argc, char* argv[])
{
    int opt;
    extern char *optarg;
    struct sockaddr_in local_addr;
    struct sockaddr_in remote_addr;
    int len = sizeof(struct sockaddr_in);
    int set_local=0, set_remote=0;
    //GetOpt

    if(argc<2)
    {
         fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
     exit(1);
    }

    while((opt = getopt(argc, argv, "hl:r:")) != EOF)
    {
        switch (opt)
        {
        case 'l':
            read_address(optarg, &local_addr);
            set_local=1;
            break;
        case 'r':
            read_address(optarg, &remote_addr);
            if (remote_addr.sin_addr.s_addr == INADDR_ANY)
            {
     fprintf(stderr, "invalid remote address: %s\n", optarg);
                fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
     exit(1);
            }
            set_remote=1;
            break;
        case 'h':
        default:
            fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
            return -1;
        }
    }

    if( !(set_local && set_remote) )
    {
            fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
            exit(-1);
    }

    int sock = 0;
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        exit(-1);
    }

    int yes = 1;
    if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0 )
    {
        perror("setsockopt");
        exit(-1);
    }

    if (bind(sock, (struct sockaddr*)&local_addr, len) < 0)
    {
        perror("bind");
        exit(-1);
    }

    if ( listen(sock, 32) < 0 )
    {
        perror("listen");
        exit(-1);
    }
   
    evutil_make_socket_nonblocking(sock);

    GoDaemon();

    event_init();
    struct event *ev = (struct event*)malloc(sizeof(struct event));
    event_set(ev, sock, EV_READ | EV_PERSIST, acceptEv, &remote_addr);
    event_add(ev, NULL);
    event_dispatch();

    return 1;
}

void acceptEv(int fd, short event, void* arg)
{
    struct sockaddr_in *rmt_addr = arg;
    
    struct sockaddr_in addr;
    int sockaddr_len = sizeof(struct sockaddr_in);
    int local_sock, remote_sock;

    local_sock = accept(fd, (struct sockaddr *)&addr, &sockaddr_len);
    if (local_sock == -1)
    {
        perror("accept");
        return;
    }

    /* Connect to remote host */
    if ((remote_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        close(local_sock);
        return;
    }
    if (connect(remote_sock, (struct sockaddr *)rmt_addr, sizeof(struct sockaddr_in)) < 0)
    {
        perror("connect");
        close(local_sock);
        close(remote_sock);
        return;
    }

    evutil_make_socket_nonblocking(local_sock);
    evutil_make_socket_nonblocking(remote_sock);

    struct event *ev_local = (struct event*)malloc(sizeof(struct event));
    struct event *ev_remote = (struct event*)malloc(sizeof(struct event));

    struct conn_info *pair = malloc(sizeof(struct conn_info));
    pair->local_sock = local_sock;
    pair->remote_sock = remote_sock;
    pair->local_event = ev_local;
    pair->remote_event = ev_remote;

    event_set(ev_local, local_sock, EV_READ | EV_PERSIST, readEv, pair);
    event_set(ev_remote, remote_sock, EV_READ | EV_PERSIST, readEv, pair);
    event_add(ev_local, NULL);
    event_add(ev_remote, NULL);
}

void CloseConn(struct conn_info *pair)
{
        event_del(pair->local_event);
        event_del(pair->remote_event);

        close(pair->local_sock);
        close(pair->remote_sock);

        free(pair->local_event);
        free(pair->remote_event);
}

void readEv(int fd, short event, void* arg)
{
    int other_fd = 0;
#define MAX_DATA_LEN 65535
    char data[MAX_DATA_LEN]={0};
    int nrecv, nsend,total_send;

    struct conn_info *pair = arg;

    if (fd == pair->local_sock)
    {
        other_fd = pair->remote_sock;
        //fprintf(stderr, "### Local[%d]->Remote[%d] ###\n", fd, other_fd);
    }
    else
    {
        other_fd = pair->local_sock;
        //fprintf(stderr, "### Remote[%d]->Local[%d] ###\n", fd, other_fd);
    }

    nrecv = recv(fd, data, MAX_DATA_LEN, 0);
    if (nrecv == -1)
    {
        if( (errno == EAGAIN)||(errno==EWOULDBLOCK) )
            return;
        else
        {
            CloseConn(pair);
            return;
        }
    }
    else if (nrecv == 0 )
    {
        CloseConn(pair);
        return;
    }

    total_send = 0;
    while (total_send!=nrecv)
    {
        nsend = send(other_fd, data+total_send, nrecv-total_send, 0);
        if (nsend == -1)
        {
            perror("send");
            CloseConn(pair);
            return;
        }
        total_send += nsend;
    }
}

void GoDaemon(void)
{
    pid_t fs;

    if(getppid() != 1)
    {
        fs = fork();

        if(fs > 0)
            exit(0); /* parent */

        if(fs < 0)
        {
            perror("fork");
            exit(1);
        }
        setsid();
    }

    chdir("/");

    /* redirect stdin/stdout/stderr to /dev/null */
    close(0);
    close(1);
    close(2);

    open("/dev/null", O_RDWR);
    dup(0);
    dup(0);

    return;
}

void read_address(const char *str, struct sockaddr_in *sin)
{
  char host[128], *p;
  struct hostent *hp;
  short port;

  strcpy(host, str);
  if ((p = strchr(host, ':')) == NULL)
  {
    fprintf(stderr, "invalid address: %s\n", host);
    fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
    exit(1);
  }
  *p++ = '\0';
  port = (short) atoi(p);
  if (port < 1)
  {
    fprintf(stderr, "invalid port: %s\n", p);
    fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
    exit(1);
  }

  memset(sin, 0, sizeof(struct sockaddr_in));
  sin->sin_family = AF_INET;
  sin->sin_port = htons(port);
  if (host[0] == '\0')
  {
    sin->sin_addr.s_addr = INADDR_ANY;
    return;
  }

  //IPv4 Address
  sin->sin_addr.s_addr = inet_addr(host);
  //Domain Name
  if (sin->sin_addr.s_addr == INADDR_NONE)
  {
    /* not dotted-decimal */
    if ((hp = gethostbyname(host)) == NULL)
    {
      fprintf(stderr, "can't resolve address: %s\n", host);
      exit(1);
    }

    sin->sin_addr.s_addr = (*(unsigned int *)hp->h_addr);
  }
}

阅读(4267) | 评论(2) | 转发(0) |
0

上一篇:debian U盘自动挂载

下一篇:Linux网络子系统

给主人留下些什么吧!~~

xixidechengbao2010-01-07 11:49:49

话说 main中的event 为嘛也要动态申请呢

xixidechengbao2010-01-07 11:49:49

话说 main中的event 为嘛也要动态申请呢