From 76d6838223718a5432baddb4fa5b3e82440c9ff2 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Mon, 30 Nov 2009 22:35:43 +0100 Subject: Some brain surgery to add event-based sockets chapter 1- SSH Socket Connections. I would like to be able to -Have a ssh_poll_ctx object -Add a ssh socket over it -launch the socket connection (using socket functions) -ssh_poll_ctx_dopoll() -Wait for the timeout or have the "connected" callback called --- include/libssh/poll.h | 2 ++ include/libssh/priv.h | 8 ++---- include/libssh/socket.h | 7 +++++ libssh/poll.c | 32 ++++++++++++++++++++++ libssh/socket.c | 14 ++++++++++ tests/Makefile | 6 +++- tests/test_socket.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 tests/test_socket.c diff --git a/include/libssh/poll.h b/include/libssh/poll.h index 4aa2f333..ca5ec181 100644 --- a/include/libssh/poll.h +++ b/include/libssh/poll.h @@ -90,10 +90,12 @@ void ssh_poll_set_events(ssh_poll_handle p, short events); void ssh_poll_add_events(ssh_poll_handle p, short events); void ssh_poll_remove_events(ssh_poll_handle p, short events); socket_t ssh_poll_get_fd(ssh_poll_handle p); +void ssh_poll_set_fd(ssh_poll_handle p, socket_t fd); void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata); ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size); void ssh_poll_ctx_free(ssh_poll_ctx ctx); int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p); +int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct socket *s); void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p); int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout); diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 90c700d5..f96e87c5 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -114,12 +114,6 @@ struct ssh_bind_struct { int toaccept; }; -struct socket; -struct ssh_poll; -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); -void ssh_socket_register_pollcallback(struct socket *s, struct ssh_poll_handle_struct *p); - SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback); SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); @@ -143,6 +137,8 @@ unsigned char *packet_encrypt(ssh_session session,void *packet,unsigned int len) /* it returns the hmac buffer if exists*/ int packet_hmac_verify(ssh_session session,ssh_buffer buffer,unsigned char *mac); +struct socket; + int ssh_packet_socket_callback(const void *data, size_t len, void *user); void ssh_packet_register_socket_callback(ssh_session session, struct socket *s); void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks); diff --git a/include/libssh/socket.h b/include/libssh/socket.h index bb54c7ea..858c5d82 100644 --- a/include/libssh/socket.h +++ b/include/libssh/socket.h @@ -22,6 +22,8 @@ #ifndef SOCKET_H_ #define SOCKET_H_ +#include "libssh/callbacks.h" +struct ssh_poll_handle_struct; /* socket.c */ struct socket; @@ -52,4 +54,9 @@ int ssh_socket_get_status(struct socket *s); int ssh_socket_data_available(struct socket *s); int ssh_socket_data_writable(struct socket *s); +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); +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); + #endif /* SOCKET_H_ */ diff --git a/libssh/poll.c b/libssh/poll.c index 4a84cbe3..7d9e3e5a 100644 --- a/libssh/poll.c +++ b/libssh/poll.c @@ -33,6 +33,7 @@ #include "libssh/priv.h" #include "libssh/libssh.h" #include "libssh/poll.h" +#include "libssh/socket.h" #ifndef SSH_POLL_CTX_CHUNK #define SSH_POLL_CTX_CHUNK 5 @@ -309,6 +310,21 @@ void ssh_poll_set_events(ssh_poll_handle p, short events) { } } +/** + * @brief Set the file descriptor of a poll object. The FD will also be propagated + * to an associated poll context. + * + * @param p Pointer to an already allocated poll object. + * @param fd New file descriptor. + */ +void ssh_poll_set_fd(ssh_poll_handle p, socket_t fd) { + if (p->ctx != NULL) { + p->ctx->pollfds[p->x.idx].fd = fd; + } else { + p->x.fd = fd; + } +} + /** * @brief Add extra events to a poll object. Duplicates are ignored. * The events will also be propagated to an associated poll context. @@ -474,6 +490,22 @@ int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) { return 0; } +/** + * @brief Add a socket object to a poll context. + * + * @param ctx Pointer to an already allocated poll context. + * @param s A SSH socket handle + * + * @return 0 on success, < 0 on error + */ +int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct socket *s) { + ssh_poll_handle p=ssh_socket_get_poll_handle(s); + if(p==NULL) + return -1; + return ssh_poll_ctx_add(ctx,p); +} + + /** * @brief Remove a poll object from a poll context. * diff --git a/libssh/socket.c b/libssh/socket.c index 8acc76ce..a250f2ea 100644 --- a/libssh/socket.c +++ b/libssh/socket.c @@ -181,6 +181,18 @@ void ssh_socket_register_pollcallback(struct socket *s, ssh_poll_handle p){ s->poll=p; } +/** @internal + * @brief returns the 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(struct socket *s){ + if(s->poll) + return s->poll; + s->poll=ssh_poll_new(s->fd,0,ssh_socket_pollcallback,s); + return s->poll; +} + /** \internal * \brief Deletes a socket object */ @@ -191,6 +203,8 @@ void ssh_socket_free(struct 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); } diff --git a/tests/Makefile b/tests/Makefile index 1ec30d6a..67353465 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -all: test_tunnel test_exec test_pcap +all: test_socket test_tunnel test_exec test_pcap CFLAGS=-I../include/ -g -Wall LDFLAGS=-lssh -L../build/libssh/ @@ -8,6 +8,10 @@ test_tunnel: test_tunnel.o authentication.o connection.o test_exec: test_exec.o authentication.o connection.o gcc -o $@ $^ $(LDFLAGS) +test_socket: test_socket.o + gcc -o $@ $^ $(LDFLAGS) + + test_pcap: test_pcap.o gcc -o $@ $^ $(LDFLAGS) diff --git a/tests/test_socket.c b/tests/test_socket.c new file mode 100644 index 00000000..b0ca03ed --- /dev/null +++ b/tests/test_socket.c @@ -0,0 +1,73 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2009 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/* Simple test for the socket callbacks */ + +#include +#include +#include +#include + +#include +#include + +static int data_rcv(const void *data, size_t len, void *user){ + printf("Received data: '"); + fwrite(data,1,len,stdout); + printf("'\n"); + return len; +} + +static void controlflow(void *user, int code){ + printf("Control flow: %x\n",code); +} + +static void exception(void *user, int code, int errno_code){ + printf("Exception: %d (%d)\n",code,errno_code); +} + +static void connected(void *user, int code, int errno_code){ + printf("Connected: %d (%d)\n",code, errno_code); +} + +struct ssh_socket_callbacks_struct callbacks={ + data_rcv, + controlflow, + exception, + connected, + NULL +}; +int main(int argc, char **argv){ + struct socket *s; + ssh_session session; + ssh_poll_ctx ctx; + if(argc < 3){ + printf("Usage : %s host port\n", argv[0]); + return EXIT_FAILURE; + } + session=ssh_new(); + s=ssh_socket_new(session); + ctx=ssh_poll_ctx_new(2); + ssh_socket_set_callbacks(s, &callbacks); + ssh_poll_ctx_add_socket(ctx,s); + + return EXIT_SUCCESS; +} -- cgit v1.2.3