Asynchronous sockets work !
Still need a bit of tuning but it's stable enough for our current needs
Этот коммит содержится в:
родитель
7962029bdc
Коммит
4924ac8099
@ -119,14 +119,15 @@ struct ssh_socket_callbacks_struct {
|
||||
};
|
||||
typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
|
||||
|
||||
#define SSH_SOCKET_FLOW_WRITEWILLBLOCK (1<<0)
|
||||
#define SSH_SOCKET_FLOW_WRITEWONTBLOCK (1<<1)
|
||||
#define SSH_SOCKET_EXCEPTION_EOF (1<<0)
|
||||
#define SSH_SOCKET_EXCEPTION_ERROR (1<<1)
|
||||
#define SSH_SOCKET_FLOW_WRITEWILLBLOCK 1
|
||||
#define SSH_SOCKET_FLOW_WRITEWONTBLOCK 2
|
||||
|
||||
#define SSH_SOCKET_CONNECTED_OK (1<<0)
|
||||
#define SSH_SOCKET_CONNECTED_ERROR (1<<1)
|
||||
#define SSH_SOCKET_CONNECTED_TIMEOUT (1<<2)
|
||||
#define SSH_SOCKET_EXCEPTION_EOF 1
|
||||
#define SSH_SOCKET_EXCEPTION_ERROR 2
|
||||
|
||||
#define SSH_SOCKET_CONNECTED_OK 1
|
||||
#define SSH_SOCKET_CONNECTED_ERROR 2
|
||||
#define SSH_SOCKET_CONNECTED_TIMEOUT 3
|
||||
|
||||
/** Initializes an ssh_callbacks_struct
|
||||
* A call to this macro is mandatory when you have set a new
|
||||
|
@ -135,9 +135,24 @@ int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
||||
struct socket *s=(struct socket *)v_s;
|
||||
char buffer[4096];
|
||||
int r,w;
|
||||
(void)fd;
|
||||
int err=0;
|
||||
socklen_t errlen=sizeof(err);
|
||||
if(revents & POLLERR){
|
||||
s->data_except=1;
|
||||
/* 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;
|
||||
close(fd);
|
||||
s->fd=-1;
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err,
|
||||
s->callbacks->user);
|
||||
return 0;
|
||||
}
|
||||
/* Then we are in a more standard kind of error */
|
||||
/* force a read to get an explanation */
|
||||
revents |= POLLIN;
|
||||
}
|
||||
@ -145,6 +160,7 @@ int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
||||
s->data_to_read=1;
|
||||
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
|
||||
if(r<0){
|
||||
if(p != NULL)
|
||||
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
||||
if(s->callbacks){
|
||||
s->callbacks->exception(
|
||||
@ -187,6 +203,8 @@ int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
||||
if(buffer_get_rest_len(s->out_buffer) > 0){
|
||||
w=ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
|
||||
buffer_get_rest_len(s->out_buffer));
|
||||
if(w>0)
|
||||
buffer_pass_bytes(s->out_buffer,w);
|
||||
} else if(s->callbacks){
|
||||
/* Otherwise advertise the upper level that write can be done */
|
||||
s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK,s->callbacks->user);
|
||||
@ -643,6 +661,7 @@ int ssh_socket_nonblocking_flush(struct socket *s) {
|
||||
session->alive = 0;
|
||||
ssh_socket_close(s);
|
||||
/* FIXME use ssh_socket_get_errno() */
|
||||
/* FIXME use callback for errors */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Writing packet: error on socket (or connection closed): %s",
|
||||
strerror(s->last_errno));
|
||||
@ -752,7 +771,13 @@ int ssh_socket_get_status(struct socket *s) {
|
||||
* @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
|
||||
* @param host hostname or ip address to connect to
|
||||
* @param port port number to connect to
|
||||
* @param bind_addr address to bind to, or NULL for default
|
||||
* @returns SSH_OK socket is being connected
|
||||
* @returns SSH_ERROR error while connecting to remote host
|
||||
* @bug It only tries connecting to one of the available AI's
|
||||
* which is problematic for hosts having DNS fail-over
|
||||
*/
|
||||
|
||||
int ssh_socket_connect(struct socket *s, const char *host, int port, const char *bind_addr){
|
||||
@ -764,6 +789,8 @@ int ssh_socket_connect(struct socket *s, const char *host, int port, const char
|
||||
return SSH_ERROR;
|
||||
fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
|
||||
if(fd < 0)
|
||||
return SSH_ERROR;
|
||||
ssh_socket_set_fd(s,fd);
|
||||
s->state=SSH_SOCKET_CONNECTING;
|
||||
if(s->callbacks && s->callbacks->connected && s->poll){
|
||||
|
@ -30,10 +30,15 @@
|
||||
#include <libssh/socket.h>
|
||||
#include <libssh/poll.h>
|
||||
|
||||
int stop=0;
|
||||
struct socket *s;
|
||||
|
||||
static int data_rcv(const void *data, size_t len, void *user){
|
||||
printf("Received data: '");
|
||||
fwrite(data,1,len,stdout);
|
||||
printf("'\n");
|
||||
ssh_socket_write(s,"Hello you !\n",12);
|
||||
ssh_socket_nonblocking_flush(s);
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -43,10 +48,16 @@ static void controlflow(int code,void *user){
|
||||
|
||||
static void exception(int code, int errno_code,void *user){
|
||||
printf("Exception: %d (%d)\n",code,errno_code);
|
||||
stop=1;
|
||||
}
|
||||
|
||||
static void connected(int code, int errno_code,void *user){
|
||||
if(code == SSH_SOCKET_CONNECTED_OK)
|
||||
printf("Connected: %d (%d)\n",code, errno_code);
|
||||
else {
|
||||
printf("Error while connecting:(%d, %d:%s)\n",code,errno_code,strerror(errno_code));
|
||||
stop=1;
|
||||
}
|
||||
}
|
||||
|
||||
struct ssh_socket_callbacks_struct callbacks={
|
||||
@ -57,7 +68,6 @@ struct ssh_socket_callbacks_struct callbacks={
|
||||
NULL
|
||||
};
|
||||
int main(int argc, char **argv){
|
||||
struct socket *s;
|
||||
ssh_session session;
|
||||
ssh_poll_ctx ctx;
|
||||
int verbosity=SSH_LOG_FUNCTIONS;
|
||||
@ -72,10 +82,12 @@ int main(int argc, char **argv){
|
||||
ctx=ssh_poll_ctx_new(2);
|
||||
ssh_socket_set_callbacks(s, &callbacks);
|
||||
ssh_poll_ctx_add_socket(ctx,s);
|
||||
if(ssh_socket_connect(s,argv[1],atoi(argv[2]),NULL)){
|
||||
if(ssh_socket_connect(s,argv[1],atoi(argv[2]),NULL) != SSH_OK){
|
||||
printf("ssh_socket_connect: %s\n",ssh_get_error(session));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
while(!stop)
|
||||
ssh_poll_ctx_dopoll(ctx,-1);
|
||||
printf("finished\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user