ssh_socket support for 2 fd + Proxyhost command
Этот коммит содержится в:
родитель
7886326aa8
Коммит
f31a14b793
@ -282,7 +282,8 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_CIPHERS_S_C,
|
||||
SSH_OPTIONS_COMPRESSION_C_S,
|
||||
SSH_OPTIONS_COMPRESSION_S_C,
|
||||
SSH_OPTIONS_HOSTKEYCHECK
|
||||
SSH_OPTIONS_HOSTKEYCHECK,
|
||||
SSH_OPTIONS_PROXYCOMMAND
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -142,6 +142,7 @@ struct ssh_session_struct {
|
||||
int ssh2;
|
||||
int ssh1;
|
||||
int StrictHostKeyChecking;
|
||||
char *ProxyCommand;
|
||||
};
|
||||
|
||||
int ssh_handle_packets(ssh_session session, int timeout);
|
||||
|
@ -33,9 +33,11 @@ int ssh_socket_init(void);
|
||||
ssh_socket ssh_socket_new(ssh_session session);
|
||||
void ssh_socket_free(ssh_socket s);
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(ssh_socket s);
|
||||
socket_t ssh_socket_get_fd_in(ssh_socket s);
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(ssh_socket s, const char *path);
|
||||
void ssh_execute_command(const char *command, socket_t in, socket_t out);
|
||||
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command);
|
||||
#endif
|
||||
void ssh_socket_close(ssh_socket s);
|
||||
int ssh_socket_read(ssh_socket s, void *buffer, int len);
|
||||
@ -43,6 +45,8 @@ int ssh_socket_write(ssh_socket s,const void *buffer, int len);
|
||||
int ssh_socket_is_open(ssh_socket s);
|
||||
int ssh_socket_fd_isset(ssh_socket s, fd_set *set);
|
||||
void ssh_socket_fd_set(ssh_socket s, fd_set *set, int *fd_max);
|
||||
void ssh_socket_set_fd_in(ssh_socket s, socket_t fd);
|
||||
void ssh_socket_set_fd_out(ssh_socket s, socket_t fd);
|
||||
int ssh_socket_completeread(ssh_socket s, void *buffer, uint32_t len);
|
||||
int ssh_socket_completewrite(ssh_socket s, const void *buffer, uint32_t len);
|
||||
int ssh_socket_wait_for_data(ssh_socket s, ssh_session session, uint32_t len);
|
||||
@ -58,8 +62,9 @@ int ssh_socket_data_writable(ssh_socket s);
|
||||
|
||||
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks);
|
||||
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, int fd, int revents, void *s);
|
||||
void ssh_socket_register_pollcallback(ssh_socket s, struct ssh_poll_handle_struct *p);
|
||||
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle(ssh_socket s);
|
||||
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_in(ssh_socket s);
|
||||
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_out(ssh_socket s);
|
||||
|
||||
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr);
|
||||
|
||||
#endif /* SOCKET_H_ */
|
||||
|
@ -86,7 +86,7 @@ static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) {
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
struct pollfd pfd;
|
||||
int fd = ssh_socket_get_fd(s);
|
||||
int fd = ssh_socket_get_fd_in(s);
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
|
@ -41,7 +41,8 @@ enum ssh_config_opcode_e {
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL,
|
||||
SOC_HOSTKEYCHECK,
|
||||
SOC_KNOWNHOSTS
|
||||
SOC_KNOWNHOSTS,
|
||||
SOC_PROXYCOMMAND
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
@ -61,6 +62,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "protocol", SOC_PROTOCOL },
|
||||
{ "stricthostkeychecking", SOC_HOSTKEYCHECK },
|
||||
{ "userknownhostsfile", SOC_KNOWNHOSTS },
|
||||
{ "proxycommand", SOC_PROXYCOMMAND },
|
||||
{ NULL, SOC_UNSUPPORTED }
|
||||
};
|
||||
|
||||
@ -294,6 +296,12 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p);
|
||||
}
|
||||
break;
|
||||
case SOC_PROXYCOMMAND:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
|
||||
}
|
||||
break;
|
||||
case SOC_UNSUPPORTED:
|
||||
fprintf(stderr, "Unsupported option: %s, line: %d\n", keyword, count);
|
||||
break;
|
||||
|
@ -624,6 +624,14 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
session->StrictHostKeyChecking = *(int*)value;
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_PROXYCOMMAND:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(session, __FUNCTION__);
|
||||
return -1;
|
||||
} else {
|
||||
session->ProxyCommand = strdup(value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||
return -1;
|
||||
|
@ -247,7 +247,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){
|
||||
return SSH_ERROR;
|
||||
if(session->socket==NULL)
|
||||
return SSH_ERROR;
|
||||
fd=ssh_socket_get_fd(session->socket);
|
||||
fd=ssh_socket_get_fd_in(session->socket);
|
||||
/* TODO: adapt for windows */
|
||||
if(fd<0)
|
||||
return SSH_ERROR;
|
||||
|
@ -463,10 +463,18 @@ int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||
* @return 0 on success, < 0 on error
|
||||
*/
|
||||
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) {
|
||||
ssh_poll_handle p=ssh_socket_get_poll_handle(s);
|
||||
if(p==NULL)
|
||||
ssh_poll_handle p_in, p_out;
|
||||
int ret;
|
||||
p_in=ssh_socket_get_poll_handle_in(s);
|
||||
if(p_in==NULL)
|
||||
return -1;
|
||||
return ssh_poll_ctx_add(ctx,p);
|
||||
ret = ssh_poll_ctx_add(ctx,p_in);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
p_out=ssh_socket_get_poll_handle_out(s);
|
||||
if(p_in != p_out)
|
||||
ret = ssh_poll_ctx_add(ctx,p_out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -228,6 +228,7 @@ void ssh_free(ssh_session session) {
|
||||
SAFE_FREE(session->host);
|
||||
SAFE_FREE(session->sshdir);
|
||||
SAFE_FREE(session->knownhosts);
|
||||
SAFE_FREE(session->ProxyCommand);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (session->wanted_methods[i]) {
|
||||
@ -292,7 +293,7 @@ socket_t ssh_get_fd(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ssh_socket_get_fd(session->socket);
|
||||
return ssh_socket_get_fd_in(session->socket);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,16 +354,19 @@ void ssh_set_fd_except(ssh_session session) {
|
||||
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||
*/
|
||||
int ssh_handle_packets(ssh_session session, int timeout) {
|
||||
ssh_poll_handle spoll;
|
||||
ssh_poll_handle spoll_in,spoll_out;
|
||||
ssh_poll_ctx ctx;
|
||||
if(session==NULL || session->socket==NULL)
|
||||
return SSH_ERROR;
|
||||
enter_function();
|
||||
spoll=ssh_socket_get_poll_handle(session->socket);
|
||||
ctx=ssh_poll_get_ctx(spoll);
|
||||
spoll_in=ssh_socket_get_poll_handle_in(session->socket);
|
||||
spoll_out=ssh_socket_get_poll_handle_out(session->socket);
|
||||
ctx=ssh_poll_get_ctx(spoll_in);
|
||||
if(ctx==NULL){
|
||||
ctx=ssh_get_global_poll_ctx(session);
|
||||
ssh_poll_ctx_add(ctx,spoll);
|
||||
ssh_poll_ctx_add(ctx,spoll_in);
|
||||
if(spoll_in != spoll_out)
|
||||
ssh_poll_ctx_add(ctx,spoll_out);
|
||||
}
|
||||
ssh_poll_ctx_dopoll(ctx,timeout);
|
||||
leave_function();
|
||||
|
275
libssh/socket.c
275
libssh/socket.c
@ -40,6 +40,9 @@
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
extern const char **environ;
|
||||
#endif
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@ -61,7 +64,8 @@ enum ssh_socket_states_e {
|
||||
};
|
||||
|
||||
struct ssh_socket_struct {
|
||||
socket_t fd;
|
||||
socket_t fd_in;
|
||||
socket_t fd_out;
|
||||
int last_errno;
|
||||
int data_to_read; /* reading now on socket will
|
||||
not block */
|
||||
@ -72,7 +76,8 @@ struct ssh_socket_struct {
|
||||
ssh_buffer in_buffer;
|
||||
ssh_session session;
|
||||
ssh_socket_callbacks callbacks;
|
||||
ssh_poll_handle poll;
|
||||
ssh_poll_handle poll_in;
|
||||
ssh_poll_handle poll_out;
|
||||
};
|
||||
|
||||
static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len);
|
||||
@ -105,7 +110,8 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s->fd = -1;
|
||||
s->fd_in = -1;
|
||||
s->fd_out= -1;
|
||||
s->last_errno = -1;
|
||||
s->session = session;
|
||||
s->in_buffer = buffer_new();
|
||||
@ -122,7 +128,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
s->data_to_read = 0;
|
||||
s->data_to_write = 0;
|
||||
s->data_except = 0;
|
||||
s->poll=NULL;
|
||||
s->poll_in=s->poll_out=NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
return s;
|
||||
}
|
||||
@ -149,16 +155,9 @@ int ssh_socket_pollcallback(ssh_poll_handle p, socket_t fd, int revents, void *v
|
||||
/* Check if we are in a connecting state */
|
||||
if(s->state==SSH_SOCKET_CONNECTING){
|
||||
s->state=SSH_SOCKET_ERROR;
|
||||
ssh_poll_free(p);
|
||||
s->poll=p=NULL;
|
||||
getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err,&errlen);
|
||||
s->last_errno=err;
|
||||
#ifdef _WIN32
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
s->fd=-1;
|
||||
ssh_socket_close(s);
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err,
|
||||
s->callbacks->userdata);
|
||||
@ -209,7 +208,7 @@ int ssh_socket_pollcallback(ssh_poll_handle p, socket_t fd, int revents, void *v
|
||||
ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state");
|
||||
s->state = SSH_SOCKET_CONNECTED;
|
||||
ssh_poll_set_events(p,POLLOUT | POLLIN | POLLERR);
|
||||
ssh_sock_set_blocking(ssh_socket_get_fd(s));
|
||||
ssh_sock_set_blocking(ssh_socket_get_fd_in(s));
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
|
||||
return 0;
|
||||
@ -232,21 +231,32 @@ int ssh_socket_pollcallback(ssh_poll_handle p, socket_t fd, int revents, void *v
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh_socket_register_pollcallback(ssh_socket s, ssh_poll_handle p){
|
||||
ssh_poll_set_callback(p,ssh_socket_pollcallback,s);
|
||||
s->poll=p;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief returns the poll handle corresponding to the socket,
|
||||
* @brief returns the input poll handle corresponding to the socket,
|
||||
* creates it if it does not exist.
|
||||
* @returns allocated and initialized ssh_poll_handle object
|
||||
*/
|
||||
ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s){
|
||||
if(s->poll)
|
||||
return s->poll;
|
||||
s->poll=ssh_poll_new(s->fd,0,ssh_socket_pollcallback,s);
|
||||
return s->poll;
|
||||
ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){
|
||||
if(s->poll_in)
|
||||
return s->poll_in;
|
||||
s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s);
|
||||
if(s->fd_in == s->fd_out && s->poll_out == NULL)
|
||||
s->poll_out=s->poll_in;
|
||||
return s->poll_in;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief returns the output poll handle corresponding to the socket,
|
||||
* creates it if it does not exist.
|
||||
* @returns allocated and initialized ssh_poll_handle object
|
||||
*/
|
||||
ssh_poll_handle ssh_socket_get_poll_handle_out(ssh_socket s){
|
||||
if(s->poll_out)
|
||||
return s->poll_out;
|
||||
s->poll_out=ssh_poll_new(s->fd_out,0,ssh_socket_pollcallback,s);
|
||||
if(s->fd_in == s->fd_out && s->poll_in == NULL)
|
||||
s->poll_in=s->poll_out;
|
||||
return s->poll_out;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@ -259,36 +269,32 @@ void ssh_socket_free(ssh_socket s){
|
||||
ssh_socket_close(s);
|
||||
buffer_free(s->in_buffer);
|
||||
buffer_free(s->out_buffer);
|
||||
if(s->poll)
|
||||
ssh_poll_free(s->poll);
|
||||
SAFE_FREE(s);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(ssh_socket s, const char *path) {
|
||||
struct sockaddr_un sunaddr;
|
||||
|
||||
socket_t fd;
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
||||
|
||||
s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (s->fd < 0) {
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(s->fd, F_SETFD, 1) == -1) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
if (fcntl(fd, F_SETFD, 1) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(s->fd, (struct sockaddr *) &sunaddr,
|
||||
if (connect(fd, (struct sockaddr *) &sunaddr,
|
||||
sizeof(sunaddr)) < 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_socket_set_fd(s,fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -299,37 +305,81 @@ int ssh_socket_unix(ssh_socket s, const char *path) {
|
||||
void ssh_socket_close(ssh_socket s){
|
||||
if (ssh_socket_is_open(s)) {
|
||||
#ifdef _WIN32
|
||||
closesocket(s->fd);
|
||||
closesocket(s->fd_in);
|
||||
/* fd_in = fd_out under win32 */
|
||||
s->last_errno = WSAGetLastError();
|
||||
#else
|
||||
close(s->fd);
|
||||
close(s->fd_in);
|
||||
if(s->fd_out != s->fd_in && s->fd_out != -1)
|
||||
close(s->fd_out);
|
||||
s->last_errno = errno;
|
||||
#endif
|
||||
s->fd=-1;
|
||||
s->fd_in = s->fd_out = -1;
|
||||
}
|
||||
if(s->poll_in != NULL){
|
||||
if(s->poll_out == s->poll_in)
|
||||
s->poll_out = NULL;
|
||||
ssh_poll_free(s->poll_in);
|
||||
s->poll_in=NULL;
|
||||
}
|
||||
if(s->poll_out != NULL){
|
||||
ssh_poll_free(s->poll_out);
|
||||
s->poll_out=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief sets the file descriptor of the socket
|
||||
/**
|
||||
* @internal
|
||||
* @brief sets the file descriptor of the socket.
|
||||
* @param[out] s ssh_socket to update
|
||||
* @param[in] fd file descriptor to set
|
||||
* @warning this function updates boths the input and output
|
||||
* file descriptors
|
||||
*/
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
||||
s->fd = fd;
|
||||
if(s->poll)
|
||||
ssh_poll_set_fd(s->poll,fd);
|
||||
s->fd_in = s->fd_out = fd;
|
||||
if(s->poll_in)
|
||||
ssh_poll_set_fd(s->poll_in,fd);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief returns the file descriptor of the socket
|
||||
/**
|
||||
* @internal
|
||||
* @brief sets the input file descriptor of the socket.
|
||||
* @param[out] s ssh_socket to update
|
||||
* @param[in] fd file descriptor to set
|
||||
*/
|
||||
socket_t ssh_socket_get_fd(ssh_socket s) {
|
||||
return s->fd;
|
||||
void ssh_socket_set_fd_in(ssh_socket s, socket_t fd) {
|
||||
s->fd_in = fd;
|
||||
if(s->poll_in)
|
||||
ssh_poll_set_fd(s->poll_in,fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief sets the output file descriptor of the socket.
|
||||
* @param[out] s ssh_socket to update
|
||||
* @param[in] fd file descriptor to set
|
||||
*/
|
||||
void ssh_socket_set_fd_out(ssh_socket s, socket_t fd) {
|
||||
s->fd_out = fd;
|
||||
if(s->poll_out)
|
||||
ssh_poll_set_fd(s->poll_out,fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** \internal
|
||||
* \brief returns the input file descriptor of the socket
|
||||
*/
|
||||
socket_t ssh_socket_get_fd_in(ssh_socket s) {
|
||||
return s->fd_in;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief returns nonzero if the socket is open
|
||||
*/
|
||||
int ssh_socket_is_open(ssh_socket s) {
|
||||
return s->fd != -1;
|
||||
return s->fd_in != -1;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@ -342,7 +392,7 @@ static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = recv(s->fd,buffer, len, 0);
|
||||
rc = recv(s->fd_in,buffer, len, 0);
|
||||
#ifdef _WIN32
|
||||
s->last_errno = WSAGetLastError();
|
||||
#else
|
||||
@ -368,7 +418,7 @@ static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
|
||||
return -1;
|
||||
}
|
||||
|
||||
w = send(s->fd,buffer, len, 0);
|
||||
w = send(s->fd_out,buffer, len, 0);
|
||||
#ifdef _WIN32
|
||||
s->last_errno = WSAGetLastError();
|
||||
#else
|
||||
@ -376,8 +426,8 @@ static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
|
||||
#endif
|
||||
s->data_to_write = 0;
|
||||
/* Reactive the POLLOUT detector in the poll multiplexer system */
|
||||
if(s->poll){
|
||||
ssh_poll_set_events(s->poll,ssh_poll_get_events(s->poll) | POLLOUT);
|
||||
if(s->poll_out){
|
||||
ssh_poll_set_events(s->poll_out,ssh_poll_get_events(s->poll_out) | POLLOUT);
|
||||
}
|
||||
if (w < 0) {
|
||||
s->data_except = 1;
|
||||
@ -390,10 +440,10 @@ static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
|
||||
* \brief returns nonzero if the current socket is in the fd_set
|
||||
*/
|
||||
int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
|
||||
if(s->fd == -1) {
|
||||
if(s->fd_in == -1) {
|
||||
return 0;
|
||||
}
|
||||
return FD_ISSET(s->fd,set);
|
||||
return FD_ISSET(s->fd_in,set) || FD_ISSET(s->fd_out,set);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@ -401,11 +451,15 @@ int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
|
||||
*/
|
||||
|
||||
void ssh_socket_fd_set(ssh_socket s, fd_set *set, int *fd_max) {
|
||||
if (s->fd == -1)
|
||||
if (s->fd_in == -1)
|
||||
return;
|
||||
FD_SET(s->fd,set);
|
||||
if (s->fd >= *fd_max) {
|
||||
*fd_max = s->fd + 1;
|
||||
FD_SET(s->fd_in,set);
|
||||
FD_SET(s->fd_out,set);
|
||||
if (s->fd_in >= *fd_max) {
|
||||
*fd_max = s->fd_in + 1;
|
||||
}
|
||||
if (s->fd_out >= *fd_max) {
|
||||
*fd_max = s->fd_out + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,11 +656,14 @@ int ssh_socket_wait_for_data(ssh_socket s, ssh_session session, uint32_t len) {
|
||||
}
|
||||
|
||||
/* ssh_socket_poll */
|
||||
/** @brief polls the socket for activity
|
||||
* @bug this function should disappear in favor of the new polling mechanism
|
||||
*/
|
||||
int ssh_socket_poll(ssh_socket s, int *writeable, int *except) {
|
||||
ssh_session session = s->session;
|
||||
ssh_pollfd_t fd[1];
|
||||
ssh_pollfd_t fd[2];
|
||||
int rc = -1;
|
||||
|
||||
int n_fd;
|
||||
enter_function();
|
||||
|
||||
if (!ssh_socket_is_open(s)) {
|
||||
@ -614,19 +671,29 @@ int ssh_socket_poll(ssh_socket s, int *writeable, int *except) {
|
||||
*writeable = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd->fd = s->fd;
|
||||
fd->events = 0;
|
||||
if(s->fd_in == s->fd_out){
|
||||
n_fd=1;
|
||||
} else {
|
||||
n_fd=2;
|
||||
}
|
||||
fd[0].fd = s->fd_in;
|
||||
fd[0].events = 0;
|
||||
|
||||
if (!s->data_to_read) {
|
||||
fd->events |= POLLIN;
|
||||
fd[0].events |= POLLIN;
|
||||
}
|
||||
|
||||
if(n_fd == 2){
|
||||
fd[1].fd=s->fd_out;
|
||||
fd[1].events = 0;
|
||||
}
|
||||
|
||||
if (!s->data_to_write) {
|
||||
fd->events |= POLLOUT;
|
||||
fd[n_fd - 1].events |= POLLOUT;
|
||||
}
|
||||
|
||||
/* Make the call, and listen for errors */
|
||||
rc = ssh_poll(fd, 1, 0);
|
||||
rc = ssh_poll(fd, n_fd, 0);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
||||
leave_function();
|
||||
@ -634,13 +701,13 @@ int ssh_socket_poll(ssh_socket s, int *writeable, int *except) {
|
||||
}
|
||||
|
||||
if (!s->data_to_read) {
|
||||
s->data_to_read = fd->revents & POLLIN;
|
||||
s->data_to_read = fd[0].revents & POLLIN;
|
||||
}
|
||||
if (!s->data_to_write) {
|
||||
s->data_to_write = fd->revents & POLLOUT;
|
||||
s->data_to_write = fd[n_fd - 1].revents & POLLOUT;
|
||||
}
|
||||
if (!s->data_except) {
|
||||
s->data_except = fd->revents & POLLERR;
|
||||
s->data_except = fd[0].revents & POLLERR;
|
||||
}
|
||||
|
||||
*except = s->data_except;
|
||||
@ -689,9 +756,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s) {
|
||||
}
|
||||
|
||||
/* Is there some data pending? */
|
||||
if (buffer_get_rest_len(s->out_buffer) > 0 && s->poll) {
|
||||
if (buffer_get_rest_len(s->out_buffer) > 0 && s->poll_out) {
|
||||
/* force the poll system to catch pollout events */
|
||||
ssh_poll_set_events(s->poll, ssh_poll_get_events(s->poll) |POLLOUT);
|
||||
ssh_poll_set_events(s->poll_out, ssh_poll_get_events(s->poll_out) |POLLOUT);
|
||||
leave_function();
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
@ -811,14 +878,74 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
|
||||
ssh_socket_set_fd(s,fd);
|
||||
s->state=SSH_SOCKET_CONNECTING;
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle(s),POLLOUT);
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
|
||||
#ifdef _WIN32
|
||||
ssh_poll_add_events(ssh_socket_get_poll_handle(s),POLLWRNORM);
|
||||
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
|
||||
#endif
|
||||
leave_function();
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* @internal
|
||||
* @brief executes a command and redirect input and outputs
|
||||
* @param command command to execute
|
||||
* @param in input file descriptor
|
||||
* @param out output file descriptor
|
||||
*/
|
||||
void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
||||
const char *args[]={"/bin/sh","-c",command,NULL};
|
||||
/* redirect in and out to stdin, stdout and stderr */
|
||||
dup2(in, 0);
|
||||
dup2(out,1);
|
||||
dup2(out,2);
|
||||
close(in);
|
||||
close(out);
|
||||
execve(args[0],(char * const *)args,(char * const *)environ);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Open a socket on a ProxyCommand
|
||||
* This call will always be nonblocking.
|
||||
* @param s socket to connect.
|
||||
* @param command Command to execute.
|
||||
* @returns SSH_OK socket is being connected.
|
||||
* @returns SSH_ERROR error while executing the command.
|
||||
*/
|
||||
|
||||
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
|
||||
socket_t in_pipe[2];
|
||||
socket_t out_pipe[2];
|
||||
int pid;
|
||||
ssh_session session=s->session;
|
||||
enter_function();
|
||||
if(s->state != SSH_SOCKET_NONE)
|
||||
return SSH_ERROR;
|
||||
pipe(in_pipe);
|
||||
pipe(out_pipe);
|
||||
pid = fork();
|
||||
if(pid == 0){
|
||||
ssh_execute_command(command,out_pipe[0],in_pipe[1]);
|
||||
}
|
||||
close(in_pipe[1]);
|
||||
close(out_pipe[0]);
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]);
|
||||
ssh_socket_set_fd_in(s,in_pipe[0]);
|
||||
ssh_socket_set_fd_out(s,out_pipe[1]);
|
||||
s->state=SSH_SOCKET_CONNECTED;
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLIN | POLLERR);
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT);
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
|
||||
leave_function();
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
/* @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user