mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-08-05 20:55:46 +03:00
Socket connect callback working...
Still need to make sure the connect syscall is correctly called
This commit is contained in:
@@ -50,7 +50,7 @@ typedef void (*ssh_callback_int) (int code, void *user);
|
|||||||
*/
|
*/
|
||||||
typedef int (*ssh_callback_data) (const void *data, size_t len, void *user);
|
typedef int (*ssh_callback_data) (const void *data, size_t len, void *user);
|
||||||
|
|
||||||
typedef void (*ssh_callback_int_int) (void *user, int code, int errno_code);
|
typedef void (*ssh_callback_int_int) (int code, int errno_code, void *user);
|
||||||
|
|
||||||
typedef int (*ssh_message_callback) (ssh_session, ssh_message message, void *user);
|
typedef int (*ssh_message_callback) (ssh_session, ssh_message message, void *user);
|
||||||
typedef int (*ssh_channel_callback_int) (ssh_channel channel, int code, void *user);
|
typedef int (*ssh_channel_callback_int) (ssh_channel channel, int code, void *user);
|
||||||
|
@@ -150,7 +150,8 @@ void ssh_regex_finalize(void);
|
|||||||
ssh_session ssh_session_new(void);
|
ssh_session ssh_session_new(void);
|
||||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
||||||
*bind_addr, int port, long timeout, long usec);
|
*bind_addr, int port, long timeout, long usec);
|
||||||
|
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||||
|
const char *bind_addr, int port);
|
||||||
/* in kex.c */
|
/* in kex.c */
|
||||||
extern const char *ssh_kex_nums[];
|
extern const char *ssh_kex_nums[];
|
||||||
int ssh_send_kex(ssh_session session, int server_kex);
|
int ssh_send_kex(ssh_session session, int server_kex);
|
||||||
|
@@ -58,5 +58,6 @@ void ssh_socket_set_callbacks(struct socket *s, ssh_socket_callbacks callbacks);
|
|||||||
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, int fd, int revents, void *s);
|
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, int fd, int revents, void *s);
|
||||||
void ssh_socket_register_pollcallback(struct socket *s, struct ssh_poll_handle_struct *p);
|
void ssh_socket_register_pollcallback(struct socket *s, struct ssh_poll_handle_struct *p);
|
||||||
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle(struct socket *s);
|
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle(struct socket *s);
|
||||||
|
int ssh_socket_connect(struct socket *s, const char *host, int port, const char *bind_addr);
|
||||||
|
|
||||||
#endif /* SOCKET_H_ */
|
#endif /* SOCKET_H_ */
|
||||||
|
@@ -355,6 +355,88 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Launches a nonblocking connect to an IPv4 or IPv6 host
|
||||||
|
* specified by its IP address or hostname.
|
||||||
|
*
|
||||||
|
* @returns A file descriptor, < 0 on error.
|
||||||
|
* @warning very ugly !!!
|
||||||
|
*/
|
||||||
|
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||||
|
const char *bind_addr, int port) {
|
||||||
|
socket_t s = -1;
|
||||||
|
int rc;
|
||||||
|
struct addrinfo *ai;
|
||||||
|
struct addrinfo *itr;
|
||||||
|
|
||||||
|
enter_function();
|
||||||
|
|
||||||
|
rc = getai(session,host, port, &ai);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||||
|
leave_function();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||||
|
/* create socket */
|
||||||
|
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||||
|
if (s < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Socket create failed: %s", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind_addr) {
|
||||||
|
struct addrinfo *bind_ai;
|
||||||
|
struct addrinfo *bind_itr;
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
|
||||||
|
|
||||||
|
rc = getai(session,bind_addr, 0, &bind_ai);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Failed to resolve bind address %s (%s)",
|
||||||
|
bind_addr,
|
||||||
|
gai_strerror(rc));
|
||||||
|
close(s);
|
||||||
|
s=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||||
|
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Binding local address: %s", strerror(errno));
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(bind_ai);
|
||||||
|
|
||||||
|
/* Cannot bind to any local addresses */
|
||||||
|
if (bind_itr == NULL) {
|
||||||
|
ssh_connect_socket_close(s);
|
||||||
|
s = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sock_set_nonblocking(s);
|
||||||
|
|
||||||
|
connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
leave_function();
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup ssh_session
|
* @addtogroup ssh_session
|
||||||
* @{ */
|
* @{ */
|
||||||
|
@@ -44,6 +44,15 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum ssh_socket_states_e {
|
||||||
|
SSH_SOCKET_NONE,
|
||||||
|
SSH_SOCKET_CONNECTING,
|
||||||
|
SSH_SOCKET_CONNECTED,
|
||||||
|
SSH_SOCKET_EOF,
|
||||||
|
SSH_SOCKET_ERROR,
|
||||||
|
SSH_SOCKET_CLOSED
|
||||||
|
};
|
||||||
|
|
||||||
struct socket {
|
struct socket {
|
||||||
socket_t fd;
|
socket_t fd;
|
||||||
int last_errno;
|
int last_errno;
|
||||||
@@ -51,6 +60,7 @@ struct socket {
|
|||||||
not block */
|
not block */
|
||||||
int data_to_write;
|
int data_to_write;
|
||||||
int data_except;
|
int data_except;
|
||||||
|
enum ssh_socket_states_e state;
|
||||||
ssh_buffer out_buffer;
|
ssh_buffer out_buffer;
|
||||||
ssh_buffer in_buffer;
|
ssh_buffer in_buffer;
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
@@ -105,7 +115,8 @@ struct socket *ssh_socket_new(ssh_session session) {
|
|||||||
s->data_to_read = 0;
|
s->data_to_read = 0;
|
||||||
s->data_to_write = 0;
|
s->data_to_write = 0;
|
||||||
s->data_except = 0;
|
s->data_except = 0;
|
||||||
|
s->poll=NULL;
|
||||||
|
s->state=SSH_SOCKET_NONE;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,17 +147,17 @@ int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
|||||||
if(r<0){
|
if(r<0){
|
||||||
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
||||||
if(s->callbacks){
|
if(s->callbacks){
|
||||||
s->callbacks->exception(s->callbacks->user,
|
s->callbacks->exception(
|
||||||
SSH_SOCKET_EXCEPTION_ERROR,
|
SSH_SOCKET_EXCEPTION_ERROR,
|
||||||
s->last_errno);
|
s->last_errno,s->callbacks->user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(r==0){
|
if(r==0){
|
||||||
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
||||||
if(s->callbacks){
|
if(s->callbacks){
|
||||||
s->callbacks->exception(s->callbacks->user,
|
s->callbacks->exception(
|
||||||
SSH_SOCKET_EXCEPTION_EOF,
|
SSH_SOCKET_EXCEPTION_EOF,
|
||||||
0);
|
0,s->callbacks->user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(r>0){
|
if(r>0){
|
||||||
@@ -161,6 +172,16 @@ int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(revents & POLLOUT){
|
if(revents & POLLOUT){
|
||||||
|
/* First, POLLOUT is a sign we may be connected */
|
||||||
|
if(s->state == SSH_SOCKET_CONNECTING){
|
||||||
|
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);
|
||||||
|
if(s->callbacks && s->callbacks->connected)
|
||||||
|
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->user);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* So, we can write data */
|
||||||
s->data_to_write=1;
|
s->data_to_write=1;
|
||||||
/* If buffered data is pending, write it */
|
/* If buffered data is pending, write it */
|
||||||
if(buffer_get_rest_len(s->out_buffer) > 0){
|
if(buffer_get_rest_len(s->out_buffer) > 0){
|
||||||
@@ -258,6 +279,8 @@ void ssh_socket_close(struct socket *s){
|
|||||||
*/
|
*/
|
||||||
void ssh_socket_set_fd(struct socket *s, socket_t fd) {
|
void ssh_socket_set_fd(struct socket *s, socket_t fd) {
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
|
if(s->poll)
|
||||||
|
ssh_poll_set_fd(s->poll,fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* \internal
|
/* \internal
|
||||||
@@ -724,6 +747,50 @@ int ssh_socket_get_status(struct socket *s) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief Launches a socket connection
|
||||||
|
* If a the socket connected callback has been defined and
|
||||||
|
* a poll object exists, this call will be non blocking
|
||||||
|
* @param
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ssh_socket_connect(struct socket *s, const char *host, int port, const char *bind_addr){
|
||||||
|
socket_t fd;
|
||||||
|
ssh_session session=s->session;
|
||||||
|
ssh_poll_ctx ctx;
|
||||||
|
enter_function();
|
||||||
|
if(s->state != SSH_SOCKET_NONE)
|
||||||
|
return SSH_ERROR;
|
||||||
|
fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
|
||||||
|
ssh_socket_set_fd(s,fd);
|
||||||
|
s->state=SSH_SOCKET_CONNECTING;
|
||||||
|
if(s->callbacks && s->callbacks->connected && s->poll){
|
||||||
|
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||||
|
ssh_poll_set_events(s->poll,POLLOUT);
|
||||||
|
leave_function();
|
||||||
|
return SSH_OK;
|
||||||
|
} else {
|
||||||
|
/* we have to do the connect ourselves */
|
||||||
|
ssh_poll_set_events(ssh_socket_get_poll_handle(s),POLLOUT);
|
||||||
|
ctx=ssh_poll_ctx_new(1);
|
||||||
|
ssh_poll_ctx_add(ctx,s->poll);
|
||||||
|
while(s->state == SSH_SOCKET_CONNECTING){
|
||||||
|
ssh_poll_ctx_dopoll(ctx,-1);
|
||||||
|
}
|
||||||
|
ssh_poll_ctx_free(ctx);
|
||||||
|
if(s->state == SSH_SOCKET_CONNECTED){
|
||||||
|
ssh_log(session,SSH_LOG_PACKET,"ssh_socket_connect blocking: connected");
|
||||||
|
leave_function();
|
||||||
|
return SSH_OK;
|
||||||
|
} else {
|
||||||
|
ssh_log(session,SSH_LOG_PACKET,"ssh_socket_connect blocking: not connected");
|
||||||
|
ssh_set_error(session,SSH_FATAL,"Error during blocking connect: %d",s->last_errno);
|
||||||
|
leave_function();
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/** @}
|
/** @}
|
||||||
*/
|
*/
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
/* vim: set ts=2 sw=2 et cindent: */
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
all: test_socket test_tunnel test_exec test_pcap
|
all: test_socket test_tunnel test_exec test_pcap
|
||||||
CFLAGS=-I../include/ -g -Wall
|
CFLAGS=-I../include/ -g -Wall -I../build/
|
||||||
LDFLAGS=-lssh -L../build/libssh/
|
LDFLAGS=-lssh -L../build/libssh/
|
||||||
|
|
||||||
test_tunnel: test_tunnel.o authentication.o connection.o
|
test_tunnel: test_tunnel.o authentication.o connection.o
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <libssh/callbacks.h>
|
#include <libssh/callbacks.h>
|
||||||
#include <libssh/socket.h>
|
#include <libssh/socket.h>
|
||||||
|
#include <libssh/poll.h>
|
||||||
|
|
||||||
static int data_rcv(const void *data, size_t len, void *user){
|
static int data_rcv(const void *data, size_t len, void *user){
|
||||||
printf("Received data: '");
|
printf("Received data: '");
|
||||||
@@ -36,15 +37,15 @@ static int data_rcv(const void *data, size_t len, void *user){
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void controlflow(void *user, int code){
|
static void controlflow(int code,void *user){
|
||||||
printf("Control flow: %x\n",code);
|
printf("Control flow: %x\n",code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exception(void *user, int code, int errno_code){
|
static void exception(int code, int errno_code,void *user){
|
||||||
printf("Exception: %d (%d)\n",code,errno_code);
|
printf("Exception: %d (%d)\n",code,errno_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void connected(void *user, int code, int errno_code){
|
static void connected(int code, int errno_code,void *user){
|
||||||
printf("Connected: %d (%d)\n",code, errno_code);
|
printf("Connected: %d (%d)\n",code, errno_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,10 +65,15 @@ int main(int argc, char **argv){
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
ssh_init();
|
||||||
s=ssh_socket_new(session);
|
s=ssh_socket_new(session);
|
||||||
ctx=ssh_poll_ctx_new(2);
|
ctx=ssh_poll_ctx_new(2);
|
||||||
ssh_socket_set_callbacks(s, &callbacks);
|
ssh_socket_set_callbacks(s, &callbacks);
|
||||||
ssh_poll_ctx_add_socket(ctx,s);
|
ssh_poll_ctx_add_socket(ctx,s);
|
||||||
|
if(ssh_socket_connect(s,argv[1],atoi(argv[2]),NULL)){
|
||||||
|
printf("ssh_socket_connect: %s\n",ssh_get_error(session));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
ssh_poll_ctx_dopoll(ctx,-1);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user