Я разместил ваш код здесь, чтобы можно было его редактировать:
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#endif
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <sstream>
#include <string>
#ifdef assert
#undef assert
#endif
#define assert(x)\
if (!x) { \
std::clog << "[Error - __FUNCTION__] Asseration to: " << #x << " failed. line: " << __LINE__ << ", file: " << __FILE__ << "." << std::endl;\
std::exit(100);\
}
template<typename _Tp>
inline std::string toString(_Tp __p)
{
std::stringstream ss;
ss << __p;
std::string ret;
ss >> ret;
return ret;
}
struct Proxy;
typedef std::vector<Proxy*> ProxyVec;
struct Proxy
{
std::string name;
uint32_t port;
};
ProxyVec loadProxies(const std::string& fileName)
{
std::FILE *f = fopen(fileName.c_str(), "r");
if (!f) {
std::clog << "[Error - loadProxies] Cannot open: " << fileName << "." << std::endl;
delete f;
f = NULL;
return ProxyVec();
}
char buffer[1024];
ProxyVec ret;
int32_t __n = 0;
while (fgets(buffer, sizeof(buffer), f)) {
++__n;
std::string str(buffer);
if (str.find("\n") != std::string::npos)
str = str.substr(0, str.length()-1);
if (str.find("\r") != std::string::npos)
str = str.substr(0, str.length()-1);
size_t sep = str.rfind(":");
if (sep == std::string::npos) {
std::clog << "[Error - loadProxies] Cannot load proxy #" << __n << "." << std::endl;
continue;
}
std::string hostname = str.substr(0, sep);
uint32_t port = static_cast<uint32_t>(std::atoi(str.substr(sep+1, str.length()-sep).c_str()));
std::clog << "Loading proxy: " << hostname << ":" << port << "." << std::endl;
Proxy proxy;
proxy.name = hostname;
proxy.port = port;
ret.push_back(&proxy);
}
std::clog << "Loaded: " << __n << " proxies." << std::endl;
return ret;
}
class Socket
{
public:
Socket(boost::asio::io_service& service, const std::string& host,
const std::string& port, const std::string& targetHost, const std::string& targetPort);
~Socket();
void write(const std::string& message);
std::string receivedData() const;
bool connected() const;
void receive();
void handle();
private:
struct SocketData
{
SocketData(boost::asio::io_service& service, const std::string& _host, const std::string& _port,
const std::string& _targetHost, const std::string& _targetPort):
socket(service),
write(service),
read(service),
resolver(service),
buffers(),
host(_host),
port(_port),
targetHost(_targetHost),
targetPort(_targetPort),
connected(false)
{
}
boost::asio::ip::tcp::socket socket;
boost::asio::io_service::strand write, read;
boost::asio::ip::tcp::resolver resolver;
boost::array<char, 1024> buffers;
std::string host, port;
std::string targetHost, targetPort;
bool connected;
};
// FIXME: Use shared_ptr instead.
SocketData* d;
protected:
//handle resolve func
void handle_resolve(const boost::system::error_code&,
boost::asio::ip::tcp::resolver::iterator);
//handle connection func
void handle_connect(const boost::system::error_code&,
boost::asio::ip::tcp::resolver::iterator);
//handle write func
void handle_write(const boost::system::error_code&, size_t);
//handle read func
void handle_read(const boost::system::error_code&, size_t);
private:
void connectionThread();
};
Socket::Socket(boost::asio::io_service& service, const std::string& host, const std::string& port,
const std::string& targetHost, const std::string& targetPort)
: d(new SocketData(service, host, port, targetHost, targetPort))
{
boost::thread thread(boost::bind(&Socket::connectionThread, this));
// FIXME: This function is blocking. The constructur will never exit.
// Use thread_group.join_all() as last line in main() instead.
thread.join();
}
Socket::~Socket()
{
d->socket.close();
delete d;
d = NULL;
}
void Socket::connectionThread()
{
if (!d)
return;
if (d->connected)
return;
boost::asio::ip::tcp::resolver::query query(d->host, d->port);
d->resolver.async_resolve(query,
boost::bind(&Socket::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
void Socket::handle_resolve(const boost::system::error_code& e,
boost::asio::ip::tcp::resolver::iterator ep_iter)
{
if (!e) {
boost::asio::ip::tcp::endpoint iter = *ep_iter;
d->socket.async_connect(iter,
boost::bind(&Socket::handle_connect, this,
boost::asio::placeholders::error, ++ep_iter));
} else {
std::clog << "[Error - Socket::handle_resolve] " << e.message() << "." << std::endl;
}
}
void Socket::handle_connect(const boost::system::error_code& e,
boost::asio::ip::tcp::resolver::iterator ep_iter)
{
if (!e) {
std::cout << "[Notice - Socket::handle_connect] Connected to host." << std::endl;
d->connected = true;
write("CONNECT " + d->targetHost + ":" + d->targetPort + " HTTP/1.1\r\n\r\n");
receive();
} else if (ep_iter != boost::asio::ip::tcp::resolver::iterator()) {
d->socket.close();
boost::asio::ip::tcp::endpoint ep = *ep_iter;
d->socket.async_connect(ep,
boost::bind(&Socket::handle_connect, this,
boost::asio::placeholders::error, ++ep_iter));
} else {
std::clog << "[Error - Server::handle_connect] " << e.message() << "." << std::endl;
}
}
void Socket::handle_write(const boost::system::error_code& e,
size_t bytes)
{
assert(!e || bytes < 0);
}
void Socket::handle_read(const boost::system::error_code& e,
size_t bytes)
{
assert(!e || bytes < 0);
std::cout << receivedData() << std::endl;
receive();
}
void Socket::write(const std::string& message)
{
boost::asio::async_write(d->socket, boost::asio::buffer(message),
d->write.wrap(
boost::bind(&Socket::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
std::string Socket::receivedData() const
{
return std::string(d->buffers.data());
}
void Socket::receive()
{
d->socket.async_read_some(boost::asio::buffer(d->buffers),
d->read.wrap(
boost::bind(&Socket::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
void Socket::handle()
{
assert(!d->targetHost.empty());
assert(!d->targetPort.empty());
std::string str(d->buffers.data());
std::clog << "Received: " << str << "." << std::endl;
if (str.substr(0, 4) == "PING")
write("PO" + str.substr(2) + "\r\n");
else if (str.find("MODE") != std::string::npos)
write("JOIN #OTland\r\n");
else if (str.find("JOIN") != std::string::npos)
write("PRIVMSG #OTland :Hello\r\n");
}
bool Socket::connected() const
{
return d->connected;
}
void handler(const std::string& fileName, const std::string& host, const std::string& port, uint32_t threads);
int main(int argc, char **argv)
{
if (argc < 5) {
std::clog << "[Error - main] Usage: " << argv[0] << " <proxy_file> <host> <port> <threads>" << std::endl;
return 1;
}
std::string file(argv[1]);
std::string host(argv[2]);
std::string port(argv[3]);
uint32_t threads = static_cast<uint32_t>(std::atoi(argv[4]));
if (!threads)
threads = 1;
for (uint32_t __i = 0; __i < threads; ++__i)
// FIXME: Use the thread.join() there.
handler(file, host, port, threads);
}
typedef std::vector<Socket*> SocketVec;
void handler(const std::string& fileName, const std::string& host,
const std::string& port, uint32_t threads)
{
assert(!fileName.empty());
assert(!host.empty());
assert(!port.empty());
ProxyVec proxies = loadProxies(fileName);
assert(proxies.size());
SocketVec sockets;
for (ProxyVec::const_iterator it = proxies.begin(); it != proxies.end(); ++it) {
boost::asio::io_service io;
Socket socket(io, (*it)->name, toString((*it)->port), host, port);
// FIXME: socket is a local variable and it's address is invalid outside
// this loop -> memory leak -> seg-fault.
sockets.push_back(&socket);
}
for (SocketVec::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
if (!(*it)->connected())
continue;
(*it)->handle();
}
// FIXME: I'm not sure if I understand this architecture. A new thread is
// started with this function as handler ? Who waits until this new created
// thread is finished ? Where is the join() ?
(void) new boost::thread(boost::bind(handler, fileName, host, port, threads));
}