File: udptunnel.cpp

package info (click to toggle)
clanlib 1.0~svn3827-6
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 24,600 kB
  • sloc: cpp: 101,591; xml: 6,410; makefile: 1,743; ansic: 463; perl: 424; php: 247; sh: 53
file content (141 lines) | stat: -rw-r--r-- 3,478 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
	ClanLib UDP Tunnel example
	
	This program demonstrates how to use the CL_Socket and CL_IPAddress classes.
	It is also excellent to send UDP packets via a third host when playing UT. :)
*/

#include <ClanLib/core.h>
#include <ClanLib/network.h>
#include <iostream>

#ifdef WIN32
#include <windows.h>
#endif

std::map<CL_IPAddress, CL_Socket> forward_sockets;

int main(int argc, char **argv)
{
	std::cout << "ClanLib UDP Tunnel, copyright (c) 2001 Magnus Norddahl / Clansoft" << std::endl;
	std::cout << std::endl;
	
	if (argc < 4)
	{
		std::cout << "Syntax: " << argv[0] << " <listen port> <server ip> <server port>" << std::endl;
		std::cout << std::endl;
		return 255;
	}
	
	std::string listen_port = argv[1];
	std::string server_ip = argv[2];
	std::string server_port = argv[3];

	try
	{
		char data[64*1024];
	
#ifdef WIN32
		CL_SetupCore::set_instance(GetModuleHandle(NULL));
#endif
		CL_SetupCore setup_core;
		CL_SetupNetwork setup_network;
	
		CL_IPAddress dest(server_ip, server_port);

		CL_IPAddress listen_addr;
		listen_addr.set_port(listen_port);

		CL_Socket listen_sock(CL_Socket::udp);
		listen_sock.bind(listen_addr);

#ifdef WIN32 // we need more power on the warp engines for win32
		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
#endif

		std::cout << "Tunnel is ready." << std::endl;
		
		while (true)
		{
			fd_set rfds;
			FD_ZERO(&rfds);
			
			int highest_fd = listen_sock.get_socket();
			
			FD_SET(listen_sock.get_socket(), &rfds);
			
			std::map<CL_IPAddress, CL_Socket>::iterator it;
			for (it = forward_sockets.begin(); it != forward_sockets.end(); it++)
			{
				int sock = it->second.get_socket();
				if (sock > highest_fd) highest_fd = sock;
				
				FD_SET(sock, &rfds);
			}
			
			int result = select(highest_fd+1, &rfds, 0, 0, 0);
			if (result < 0) throw CL_Error("Select failed!");
			
			if (FD_ISSET(listen_sock.get_socket(), &rfds)) // incoming data from a client
			{
				try
				{
					// accept data:
					CL_IPAddress from;
					int data_size = listen_sock.recv(data, 64*1024, from);
			
					// first find out if we already know the client:
					it = forward_sockets.find(from);
					if (it == forward_sockets.end()) // new client, create new forward socket for it
					{
						std::cout << "New client connected!" << std::endl;
					
						CL_Socket new_sock(CL_Socket::udp);
						new_sock.bind(CL_IPAddress());
						forward_sockets[from] = new_sock;

						it = forward_sockets.find(from);
					}
				
					// forward the data:
					result = it->second.send(data, data_size, dest);
				}
				catch (CL_Error err)
				{
					std::cout << "Error while forwarding from client to server " << err.message.c_str() << std::endl;
				}
			}

			for (it = forward_sockets.begin(); it != forward_sockets.end(); it++)
			{
				const CL_IPAddress &src = it->first;
				CL_Socket &forward_sock = it->second;

				try
				{
					int sock = forward_sock.get_socket();
				
					if (FD_ISSET(sock, &rfds)) // incoming data from the server
					{
						// accept data:
						CL_IPAddress from;
						int data_size = forward_sock.recv(data, 64*1024, from);
					
						// forward to client:
						listen_sock.send(data, data_size, src);
					}
				}
				catch (CL_Error err)
				{
					std::cout << "Error while forwarding from server to client " << err.message.c_str() << std::endl;
				}
			}
		}
	}
	catch (CL_Error error)
	{
		std::cout << "Error: " << error.message.c_str() << std::endl;
	}
	
	return 0;
}