Нужен исходник прокси сервера, пробрасывающего запросы от клиента (FireFox) к вышестоящему HTTP прокси и обратно.
Смотрел исходники tcptunnel. В принципе, то, что надо, только он однопользовательский, по этому не подходит. Городить поток для каждого клиента тоже не вариант.
Смотрел исходники ArashPartow/proxy. По функционалу подходит полностью, но нужно на WinAPI.
Вот код:
//
// tcpproxy_server.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2007 Arash Partow ([url]http://www.partow.net[/url])
// URL: [url]http://www.partow.net/programming/tcpproxy/index.html[/url]
//
// Distributed under the Boost Software License, Version 1.0.
//
//
// Description
// ~~~~~~~~~~~
// The objective of the TCP proxy server is to act as an
// intermediary in order to 'forward' TCP based connections
// from external clients onto a singular remote server.
//
// The communication flow in the direction from the client to
// the proxy to the server is called the upstream flow, and the
// communication flow in the direction from the server to the
// proxy to the client is called the downstream flow.
// Furthermore the up and down stream connections are
// consolidated into a single concept known as a bridge.
//
// In the event either the downstream or upstream end points
// disconnect, the proxy server will proceed to disconnect the
// other end point and eventually destroy the associated
// bridge.
//
// The following is a flow and structural diagram depicting the
// various elements (proxy, server and client) and how they
// connect and interact with each other.
//
// ---> upstream ---> +---------------+
// +---->------> |
// +-----------+ | | Remote Server |
// +---------> [x]--->----+ +---<---[x] |
// | | TCP Proxy | | +---------------+
// +-----------+ | +--<--[x] Server <-----<------+
// | [x]--->--+ | +-----------+
// | Client | |
// | <-----<----+
// +-----------+
// <--- downstream <---
//
//
#include <cstdlib>
#include <cstddef>
#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
namespace tcp_proxy
{
namespace ip = boost::asio::ip;
class bridge : public boost::enable_shared_from_this<bridge>
{
public:
typedef ip::tcp::socket socket_type;
typedef boost::shared_ptr<bridge> ptr_type;
bridge(boost::asio::io_service& ios)
: downstream_socket_(ios),
upstream_socket_ (ios)
{}
socket_type& downstream_socket()
{
// Client socket
return downstream_socket_;
}
socket_type& upstream_socket()
{
// Remote server socket
return upstream_socket_;
}
void start(const std::string& upstream_host, unsigned short upstream_port)
{
// Attempt connection to remote server (upstream side)
upstream_socket_.async_connect(
ip::tcp::endpoint(
boost::asio::ip::address::from_string(upstream_host),
upstream_port),
boost::bind(&bridge::handle_upstream_connect,
shared_from_this(),
boost::asio::placeholders::error));
}
void handle_upstream_connect(const boost::system::error_code& error)
{
if (!error)
{
// Setup async read from remote server (upstream)
upstream_socket_.async_read_some(
boost::asio::buffer(upstream_data_,max_data_length),
boost::bind(&bridge::handle_upstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
// Setup async read from client (downstream)
downstream_socket_.async_read_some(
boost::asio::buffer(downstream_data_,max_data_length),
boost::bind(&bridge::handle_downstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
private:
/*
Section A: Remote Server --> Proxy --> Client
Process data recieved from remote sever then send to client.
*/
// Read from remote server complete, now send data to client
void handle_upstream_read(const boost::system::error_code& error,
const size_t& bytes_transferred)
{
if (!error)
{
async_write(downstream_socket_,
boost::asio::buffer(upstream_data_,bytes_transferred),
boost::bind(&bridge::handle_downstream_write,
shared_from_this(),
boost::asio::placeholders::error));
}
else
close();
}
// Write to client complete, Async read from remote server
void handle_downstream_write(const boost::system::error_code& error)
{
if (!error)
{
upstream_socket_.async_read_some(
boost::asio::buffer(upstream_data_,max_data_length),
boost::bind(&bridge::handle_upstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
// *** End Of Section A ***
/*
Section B: Client --> Proxy --> Remove Server
Process data recieved from client then write to remove server.
*/
// Read from client complete, now send data to remote server
void handle_downstream_read(const boost::system::error_code& error,
const size_t& bytes_transferred)
{
if (!error)
{
async_write(upstream_socket_,
boost::asio::buffer(downstream_data_,bytes_transferred),
boost::bind(&bridge::handle_upstream_write,
shared_from_this(),
boost::asio::placeholders::error));
}
else
close();
}
// Write to remote server complete, Async read from client
void handle_upstream_write(const boost::system::error_code& error)
{
if (!error)
{
downstream_socket_.async_read_some(
boost::asio::buffer(downstream_data_,max_data_length),
boost::bind(&bridge::handle_downstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
// *** End Of Section B ***
void close()
{
boost::mutex::scoped_lock lock(mutex_);
if (downstream_socket_.is_open())
{
downstream_socket_.close();
}
if (upstream_socket_.is_open())
{
upstream_socket_.close();
}
}
socket_type downstream_socket_;
socket_type upstream_socket_;
enum { max_data_length = 8192 }; //8KB
unsigned char downstream_data_[max_data_length];
unsigned char upstream_data_ [max_data_length];
boost::mutex mutex_;
public:
class acceptor
{
public:
acceptor(boost::asio::io_service& io_service,
const std::string& local_host, unsigned short local_port,
const std::string& upstream_host, unsigned short upstream_port)
: io_service_(io_service),
localhost_address(boost::asio::ip::address_v4::from_string(local_host)),
acceptor_(io_service_,ip::tcp::endpoint(localhost_address,local_port)),
upstream_port_(upstream_port),
upstream_host_(upstream_host)
{}
bool accept_connections()
{
try
{
session_ = boost::shared_ptr<bridge>(new bridge(io_service_));
acceptor_.async_accept(session_->downstream_socket(),
boost::bind(&acceptor::handle_accept,
this,
boost::asio::placeholders::error));
}
catch(std::exception& e)
{
std::cerr << "acceptor exception: " << e.what() << std::endl;
return false;
}
return true;
}
private:
void handle_accept(const boost::system::error_code& error)
{
if (!error)
{
session_->start(upstream_host_,upstream_port_);
if (!accept_connections())
{
std::cerr << "Failure during call to accept." << std::endl;
}
}
else
{
std::cerr << "Error: " << error.message() << std::endl;
}
}
boost::asio::io_service& io_service_;
ip::address_v4 localhost_address;
ip::tcp::acceptor acceptor_;
ptr_type session_;
unsigned short upstream_port_;
std::string upstream_host_;
};
};
}
int main(int argc, char* argv[])
{
if (argc != 5)
{
std::cerr << "usage: tcpproxy_server <local host ip> <local port> <forward host ip> <forward port>" << std::endl;
return 1;
}
const unsigned short local_port = static_cast<unsigned short>(::atoi(argv[2]));
const unsigned short forward_port = static_cast<unsigned short>(::atoi(argv[4]));
const std::string local_host = argv[1];
const std::string forward_host = argv[3];
boost::asio::io_service ios;
try
{
tcp_proxy::bridge::acceptor acceptor(ios,
local_host, local_port,
forward_host, forward_port);
acceptor.accept_connections();
ios.run();
}
catch(std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
/*
* [Note] On posix systems the tcp proxy server build command is as follows:
* c++ -pedantic -ansi -Wall -Werror -O3 -o tcpproxy_server tcpproxy_server.cpp -L/usr/lib -lstdc++ -lpthread -lboost_thread -lboost_system
*/
Может кто сможет подсказать, набросать, как то же самое сделать на WinAPI?
С небольшими правками (массив sockets использовался неверно):
// Program by KMiNT21
// (c) KMiNT21 - Ukraine, Zaporizhzhya. mailto: kmint21@mail.ru
// Undeground InformatioN Center [UInC] - http://www.uinc.ru
// Если Вы хотите прочесть мою статью "Пишем прокси сервер" с подробнейшим
// комментированием этого исходника или "Синхронные и асинхронные сокеты
// в Windows", то идете на сервере www.uinc.ru в раздел статьи -
// (www.uinc.ru/articles). Первая - будет там в ближайшие дни (а возможно,
// уже там присутствует), а врорая уже есть. Все комментарии шлите на mail.
#pragma comment( lib, "ws2_32.lib" )
#include <windows.h>
#include <map>
// НАСТРОЙКА ПАРАМЕТРОВ
#define IN_PORT 5150
#define OUT_IP "127.0.0.1"
#define OUT_PORT 8079
#define MAX_DATA 100
//#define MAXCONN 1000
#define IDE_MSG 110
#define WM_ASYNC_CLIENTEVENT WM_USER+1
#define WM_ASYNC_PROXYEVENT WM_USER+10
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void ConnectToProxy(SOCKET);
SOCKET hListenSockTCP = INVALID_SOCKET;
SOCKADDR_IN myaddrTCP, proxyaddrTCP;
char buf[MAX_DATA];
//SOCKET sockets[MAXCONN];
std::map<SOCKET, SOCKET> sockets;
std::map<SOCKET, SOCKET> rsockets;
HWND hwndMain;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow)
{
WSADATA stWSADataTCPIP;
if (WSAStartup(0x0101, &stWSADataTCPIP)) MessageBox(0, __TEXT("WSAStartup error !"), __TEXT("NET ERROR!!!"), 0);
//ZeroMemory(sockets, sizeof(sockets));
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.hInstance = hInst;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = __TEXT("CProxy");
wc.lpszMenuName = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClass(&wc)) return 0;
hwndMain = CreateWindow(__TEXT("CProxy"), __TEXT("ProxyExample"), WS_MINIMIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_MAXIMIZEBOX | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_THICKFRAME, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
ShowWindow(hwndMain, SW_SHOW);
hListenSockTCP = socket(AF_INET, SOCK_STREAM, 0);
myaddrTCP.sin_family = AF_INET;
myaddrTCP.sin_addr.s_addr = htonl(INADDR_ANY);
myaddrTCP.sin_port = htons(IN_PORT);
if (bind(hListenSockTCP, (LPSOCKADDR)&myaddrTCP, sizeof(struct sockaddr))) { MessageBox(hwndMain, __TEXT("This port in use!"), __TEXT("BIND TCP ERROR!!!"), 0); }
if (listen(hListenSockTCP, 5)) MessageBox(hwndMain, __TEXT("listen error!"), __TEXT("ERROR!!!"), 0);
WSAAsyncSelect(hListenSockTCP, hwndMain, WM_ASYNC_CLIENTEVENT, FD_ACCEPT | FD_READ | FD_CLOSE);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
return 0;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
WORD WSAEvent;
int i;
DWORD currentsock;
switch (msg)
{
case WM_COMMAND:
break;
case WM_DESTROY:
PostQuitMessage(0); // 10xu4yourtime
break;
case WM_ASYNC_CLIENTEVENT: // Сообщения про события сокетов, подключенных к клиенту...
currentsock = wParam;
WSAEvent = WSAGETSELECTEVENT(lParam);
switch (WSAEvent)
{
case FD_CLOSE:
shutdown(sockets[currentsock], 1);
closesocket(currentsock);
return 0;
case FD_READ:
// ПЕРЕНАПРАВЛЕНИЕ ДАННЫХ (redirect). Берем от клиента, посылаем на сервер.
i = recv(currentsock, buf, MAX_DATA, 0);
send(sockets[currentsock], buf, i, 0); // и отправляем...
return 0;
case FD_ACCEPT:
ConnectToProxy(accept(hListenSockTCP, NULL, NULL));
return 0;
}
break;
case WM_ASYNC_PROXYEVENT:
// Найдем соответствующий дескриптор.
currentsock = rsockets[wParam];
WSAEvent = WSAGETSELECTEVENT(lParam);
switch (WSAEvent)
{
// Произошло подключение к удаленному хосту
case FD_CONNECT:
i = WSAGETSELECTERROR(lParam);
if (i != 0)
{
shutdown(currentsock, 1);
closesocket(sockets[currentsock]);
sockets[currentsock] = INVALID_SOCKET;
}
return 0;
// Сервер нас отрубает ...
case FD_CLOSE:
shutdown(currentsock, 1);
closesocket(sockets[currentsock]);
sockets[currentsock] = INVALID_SOCKET;
return 0;
// Перенаправление данных клиенту
case FD_READ:
i = recv(sockets[currentsock], buf, MAX_DATA, 0);
send(currentsock, buf, i, 0);
return 0;
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// Connect to PROXY Connect to PROXY Connect to PROXY Connect to PROXY Connect to PROXY Connect to PROXY
void ConnectToProxy(SOCKET nofsock)
{
SOCKADDR_IN rmaddr;
rmaddr.sin_family = AF_INET;
rmaddr.sin_addr.s_addr = inet_addr(OUT_IP);
rmaddr.sin_port = htons(OUT_PORT);
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
sockets[nofsock] = s;
rsockets[s] = nofsock;
if (INVALID_SOCKET == s)
MessageBox(0, __TEXT("INVALID_SOCKET"), __TEXT("ERROR!!!"), 0);
WSAAsyncSelect(s, hwndMain, WM_ASYNC_PROXYEVENT, FD_CONNECT | FD_READ | FD_CLOSE);
connect(s, (struct sockaddr *)&rmaddr, sizeof(rmaddr));
return; // Connect OK
}
Можно считать, что задача решена. Сделал в проекте 2 конфигурации - для варианта на boost и варианта на winapi. Окно сделал невидимым.
P.S.: Хотел переписать с использованием WsaEventSelect, но WSAWaitForMultipleEvents накладывает ограничение: количество подключений <= WSA_MAXIMUM_WAIT_EVENTS (64). Это ограничение можно обойти, если запускать WSAWaitForMultipleEvents в новом потоке для подключений >= WSA_MAXIMUM_WAIT_EVENTS?
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Сделал построчное чтение с файла с помощью wifstream и getlineНа маленьких файлах все хорошо
Добрый день всем! В ходе работы с многопоточностью в C++ у меня возникли некоторые проблемыЯ качаю некоторые данные(файлы небольшого размера)...
В другом вопросе обнаружилось, что деление нуля на переменную, содержащую вещественный ноль, в результате даёт значение -nan