Chìa khóa để làm việc chuyển tiếp cổng libssh2 đã phát hiện ra rằng về cơ bản nó chỉ cung cấp cho bạn dữ liệu đi vào cổng đó. Bạn phải gửi dữ liệu lên cổng cục bộ mà bạn mở:
(Lưu ý, mã này chưa hoàn thành, không có kiểm tra lỗi và việc tạo luồng chỉ không đúng, nhưng nó đưa ra một phác thảo chung về cách thực hiện điều này.)
void reverse_port_forward(CMainDlg* dlg, addrinfo * hubaddr, std::string username, std::string password, int port)
{
int iretval;
unsigned long mode = 1;
int last_socket_err = 0;
int other_port = 0;
fd_set read_set, write_set;
SOCKET sshsock = socket(AF_INET, SOCK_STREAM, 0);
iretval = connect(sshsock, hubaddr->ai_addr, hubaddr->ai_addrlen);
if (iretval != 0)
::PostQuitMessage(0);
LIBSSH2_SESSION * session = NULL;
session = libssh2_session_init();
iretval = libssh2_session_startup(session, sshsock);
if (iretval)
::PostQuitMessage(0);
iretval = libssh2_userauth_password(session, username.c_str(), password.c_str());
dlg->m_track_status(dlg, 1, 0, "Authorized");
LIBSSH2_LISTENER* listener = NULL;
listener = libssh2_channel_forward_listen_ex(session, "127.0.0.1", port, &other_port, 1);
if (!listener)
::PostQuitMessage(0);
LIBSSH2_CHANNEL* channel = NULL;
ioctlsocket(sshsock, FIONBIO, &mode);
libssh2_session_set_blocking(session, 0); // non-blocking
int err = LIBSSH2_ERROR_EAGAIN;
while (err == LIBSSH2_ERROR_EAGAIN)
{
channel = libssh2_channel_forward_accept(listener);
if (channel) break;
err = libssh2_session_last_errno(session);
boost::this_thread::yield();
}
if (channel)
{
char buf[MAX_BUF_LEN];
char* chunk;
long bytes_read = 0;
long bytes_written = 0;
int total_set = 0;
timeval wait;
wait.tv_sec = 0;
wait.tv_usec = 2000;
sockaddr_in localhost;
localhost.sin_family = AF_INET;
localhost.sin_addr.s_addr = inet_addr("127.0.0.1");
localhost.sin_port = htons(5900);
SOCKET local_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ioctlsocket(local_sock, FIONBIO, &mode);
iretval = connect(local_sock, (sockaddr*) &localhost, sizeof(localhost));
if (iretval == SOCKET_ERROR)
iretval = WSAGetLastError();
while (1)
{
bytes_read = libssh2_channel_read(channel, buf, MAX_BUF_LEN);
if (bytes_read >= 0){
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_SET(local_sock, &write_set);
// wait until the socket can be written to
while (select(0, &read_set, &write_set, NULL, &wait) < 1)
boost::this_thread::yield();
if (FD_ISSET(local_sock, &write_set))
{
FD_CLR(local_sock, &write_set);
chunk = buf;
// everything may not get written in this call because we're non blocking. So
// keep writing more data until we've emptied the buffer pointer.
while ((bytes_written = send(local_sock, chunk, bytes_read, 0)) < bytes_read)
{
// if it couldn't write anything because the buffer is full, bytes_written
// will be negative which won't help our pointer math much
if (bytes_written > 0)
{
chunk = buf + bytes_written;
bytes_read -= bytes_written;
if (bytes_read == 0)
break;
}
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_SET(local_sock, &write_set);
// wait until the socket can be written to
while (select(0, &read_set, &write_set, NULL, &wait) < 1)
boost::this_thread::yield();
}
}
}
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_SET(local_sock, &read_set);
select(0, &read_set, &write_set, NULL, &wait);
if (FD_ISSET(local_sock, &read_set))
{
FD_CLR(local_sock, &read_set);
bytes_read = recv(local_sock, buf, MAX_BUF_LEN, 0);
if (bytes_read >= 0)
{
while ((bytes_written = libssh2_channel_write_ex(channel, 0, buf, bytes_read)) == LIBSSH2_ERROR_EAGAIN)
boost::this_thread::yield();
}
}
boost::this_thread::yield();
} // while
} // if channel
}
PS Để làm cho tác phẩm này yêu cầu các bản dựng mới nhất của SVN của libssh2. Đã xảy ra lỗi trong các phiên bản trước để giữ cho chuyển tiếp cổng không thể sử dụng được.
Dường như anh ta yêu cầu một cổng chuyển tiếp, nhưng chức năng của bạn rõ ràng có tiêu đề là "reverse_port_forward". Mã ví dụ này có mang một cổng cục bộ đến cổng máy chủ hay cổng máy chủ đến cổng cục bộ không? – Ralphleon