用法: prog.exe address1:port1 address2:port2
程序将从本地端口的port1接收的数据发往 address1:port1, 同时address1:port1发出的数据将转发会原始的发送者。
- #ifndef __WIN32__
- #include <time.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #define S_CLOSE close
- #define S_READ read
- #define S_WRITE write
- #else
- #include <winsock2.h>
- #define socklen_t int
- #define S_CLOSE(s) closesocket(s)
- #define S_READ(fd, buf, len) recv(fd, buf, len, 0)
- #define S_WRITE(fd, buf, len) send(fd, buf, len, 0)
- #endif
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <set>
-
- #define UDPF_KEEP 0x00000001
-
- struct udpiocb {
- int flags;
- int udpio_fd;
- time_t last_active;
- struct sockaddr_in udpio_addr;
- };
-
- bool operator < (const struct udpiocb & a, const struct udpiocb & b)
- {
- struct sockaddr_in addr_a, addr_b;
- addr_a = a.udpio_addr;
- addr_b = b.udpio_addr;
- if (addr_a.sin_port == addr_b.sin_port)
- return (addr_a.sin_addr.s_addr < addr_b.sin_addr.s_addr);
- return (addr_a.sin_port < addr_b.sin_port);
- }
-
- static std::set<udpiocb> udpio_list;
-
- int udpio_add(u_long addr, u_short port)
- {
- int error;
- struct udpiocb iocb;
- struct sockaddr_in addr_in1;
- int s_udp = socket(PF_INET, SOCK_DGRAM, 0);
- assert(s_udp != -1);
- addr_in1.sin_family = AF_INET;
- addr_in1.sin_port = htons(port);
- addr_in1.sin_addr.s_addr = htonl(INADDR_ANY);
- error = bind(s_udp, (struct sockaddr *)&addr_in1, sizeof(addr_in1));
- assert(error == 0);
- iocb.flags = UDPF_KEEP;
- iocb.udpio_fd = s_udp;
- iocb.udpio_addr = addr_in1;
- iocb.udpio_addr.sin_addr.s_addr = addr;
- udpio_list.insert(iocb);
- return 0;
- }
-
- int udpio_final(void)
- {
- std::set<udpiocb>::const_iterator iter;
- iter = udpio_list.begin();
- while (iter != udpio_list.end()) {
- S_CLOSE(iter->udpio_fd);
- ++iter;
- }
- return 0;
- }
-
- int udpio_realloc(const struct sockaddr_in & addr)
- {
- struct udpiocb iocb;
- iocb.flags = 0;
- iocb.udpio_addr = addr;
- std::set<udpiocb>::iterator iter;
- iter = udpio_list.find(iocb);
- if (iter != udpio_list.end()) {
- iocb = *iter;
- time(&iocb.last_active);
- udpio_list.erase(iter);
- udpio_list.insert(iocb);
- return iocb.udpio_fd;
- }
- iocb.udpio_fd = socket(AF_INET, SOCK_DGRAM, 0);
- time(&iocb.last_active);
- udpio_list.insert(iocb);
- return iocb.udpio_fd;
- }
-
- int udpio_event(fd_set * readfds, fd_set * writefds, fd_set * errorfds)
- {
- int fd, len;
- char buf[4096];
- int addr_len1;
- struct sockaddr_in addr_in1;
- std::set<udpiocb>::iterator iter;
- iter = udpio_list.begin();
- while (iter != udpio_list.end()) {
- if (FD_ISSET(iter->udpio_fd, readfds)) {
- addr_len1 = sizeof(addr_in1);
- len = recvfrom(iter->udpio_fd, buf, sizeof(buf), 0,
- (struct sockaddr *)&addr_in1, &addr_len1);
- fd = udpio_realloc(addr_in1);
- sendto(fd, buf, len, 0, (struct sockaddr *)&(iter->udpio_addr),
- sizeof(iter->udpio_addr));
- }
- ++iter;
- }
- return 0;
- }
-
- int udpio_collect(time_t current)
- {
- int count = udpio_list.size();
- std::set<udpiocb>::iterator iter;
- iter = udpio_list.begin();
- while (iter != udpio_list.end()) {
- if (iter->last_active + 60 < current &&
- (iter->flags & UDPF_KEEP) == 0) {
- closesocket(iter->udpio_fd);
- udpio_list.erase(iter++);
- continue;
- }
- ++iter;
- }
- if (udpio_list.size() != count)
- printf("udpio collect: %d %d\n", udpio_list.size(), count);
- assert (udpio_list.size() <= count);
- return count - udpio_list.size();
- }
-
- int udpio_fd_set(fd_set * readfds, fd_set * writefds, fd_set * errorfds)
- {
- int fd_max = 0;
- std::set<udpiocb>::const_iterator iter;
- iter = udpio_list.begin();
- while (iter != udpio_list.end()) {
- FD_SET(iter->udpio_fd, readfds);
- fd_max = (fd_max < iter->udpio_fd? iter->udpio_fd: fd_max);
- ++iter;
- }
- return fd_max;
- }
-
- int udp_switch(void)
- {
- int count;
- struct fd_set readfds, writefds, errorfds;
-
- time_t t_last, t_current;
- size_t c_active = udpio_list.size();
-
- time(&t_last);
- for ( ; ; ) {
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&errorfds);
-
- int max_fd = udpio_fd_set(&readfds, &writefds, &errorfds);
-
- struct timeval timeout = {1, 1};
- count = select(max_fd + 1, &readfds, &writefds, &errorfds, &timeout);
- if (count == -1) {
- printf("select error: %d \n", count);
- continue;
- }
-
- if (count == 0) {
- continue;
- }
-
- if (c_active != udpio_list.size() &&
- time(&t_current) != t_last) {
- udpio_collect(t_current);
- t_last = t_current;
- c_active = udpio_list.size();
- }
-
- printf("udpio event\n");
- udpio_event(&readfds, &writefds, &errorfds);
- }
- return 0;
- }
-
-
- int main(int argc, char * argv[])
- {
- int error;
- char buf[512];
-
- WSADATA data;
- WSAStartup(0x201, &data);
-
- int count = 0;
- for (int i = 1; i < argc; i++) {
- char * pdot = NULL;
- strncpy(buf, argv[i], sizeof(buf));
- buf[sizeof(buf) - 1] = 0;
- pdot = strchr(buf, ':');
- if (pdot == NULL)
- continue;
- *pdot++ = 0;
- int port = atoi(pdot);
- if (port == 0 || port == -1)
- continue;
- udpio_add(inet_addr(buf), port);
- count++;
- }
-
- if (count > 0)
- udp_switch();
- udpio_final();
- return 0;
- }
(pagx) |