Squashed commit of the following:

commit 43fad8dfd977637c31fade76ace2905f6528c3bc
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Fri Nov 27 18:39:06 2009 +0100

    adaptation to the new ssh_poll_handle object name

commit 1e5e6ac4605adf10d437d04f0fd4b7e66024853c
Merge: 3fd92a0... 810adad...
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Fri Nov 27 18:33:06 2009 +0100

    Merge branch 'master' into badcode/libssh_async

commit 3fd92a08eb74b1447a9ff4ca4e1d137475c62cc6
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Mon Nov 2 14:25:46 2009 +0100

    Compiles again

commit 8910d7b9692418c9ccea0234f6d49674d238dc16
Merge: e83f1b5... cce34a6...
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Mon Nov 2 12:47:34 2009 +0100

    Merge branch 'master' into libssh_async

    Very big merge !

    Conflicts:
    	include/libssh/callbacks.h
    	include/libssh/priv.h
    	libssh/channels.c
    	libssh/messages.c
    	libssh/packet.c
    	libssh/server.c
    	libssh/session.c
    	libssh/socket.c

commit e83f1b593219e183082b015315f09bfe95a29cfc
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Mon Nov 2 12:07:01 2009 +0100

    rename callback.h

commit dffa7b730e8f39e2198de18ab69a8e57bef95e58
Merge: 5a8b748... de8808c...
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Tue Sep 15 10:50:07 2009 +0200

    Merge branch 'master' of git://git.libssh.org/projects/libssh/libssh into libssh_async

commit 5a8b7484f36599d28f2c0c14a23b76bfc7257638
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Sun Sep 13 12:55:18 2009 +0200

    More updates to callback system

commit 18620c20d5e4e62107093f7fd330e553493253fa
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Sat Sep 12 22:26:52 2009 +0200

    Same thing with channel_rcv_data

commit fc4a56f6726e409a5866272923f1cbebfc821af3
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Sat Sep 12 22:17:45 2009 +0200

    added a few packet handlers for channels

commit 4b6bb4fd00b10cf1321a764126f277ab204bffe3
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Fri Sep 11 23:15:25 2009 +0300

    sample packet handlers + bugfixes

commit 2784d09d6dec0a8f868912d14f90d860233b3f82
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Fri Sep 11 20:30:50 2009 +0300

    Packet callbacks nearly finished

    Need tests and implementation of some packet callbacks

commit cd3ea43f20c9ae2f54576ca98a0ea75c5d4299d3
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Thu Sep 10 12:46:02 2009 +0300

    First step of async packet handling

    The socket to packet handler is nearly done (needs testing)
    I still need to define the interface for callbacks.

commit 487f4d2a900a5fe3b90ceda4460ab7d38d7ad722
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Tue Sep 8 23:24:09 2009 +0300

    Almost complete socket callback system

    Finished the callback function so it bufferizes data when
    callee does not use it.
    Flushes the buffer automaticaly after a ssh_socket_nonblocking_flush

commit 23571f22fac9e40c855dfa99569bba181a39648b
Author: Aris Adamantiadis <aris@0xbadc0de.be>
Date:   Tue Sep 8 22:22:32 2009 +0300

    First draft of a callback system
This commit is contained in:
Aris Adamantiadis
2009-11-27 20:42:43 +01:00
parent 810adadf2e
commit 91bb1b2de6
10 changed files with 664 additions and 212 deletions

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2008 by Aris Adamantiadis
* Copyright (c) 2008,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
@@ -34,11 +34,11 @@
#include <sys/un.h>
#endif
#include "libssh/priv.h"
#include "libssh/callbacks.h"
#include "libssh/socket.h"
#include "libssh/buffer.h"
#include "libssh/poll.h"
#include "libssh/session.h"
/** \defgroup ssh_socket SSH Sockets
* \addtogroup ssh_socket
* @{
@@ -54,8 +54,14 @@ struct socket {
ssh_buffer out_buffer;
ssh_buffer in_buffer;
ssh_session session;
ssh_socket_callbacks callbacks;
ssh_poll_handle poll;
};
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, uint32_t len);
static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
uint32_t len);
/*
* \internal
* \brief inits the socket system (windows specific)
@@ -103,7 +109,78 @@ struct socket *ssh_socket_new(ssh_session session) {
return s;
}
/* \internal
/**
* @internal
* @brief the socket callbacks, i.e. callbacks to be called
* upon a socket event
* @param callbacks a ssh_socket_callback object reference
*/
void ssh_socket_set_callbacks(struct socket *s, ssh_socket_callbacks callbacks){
s->callbacks=callbacks;
}
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;
if(revents & POLLERR){
s->data_except=1;
/* force a read to get an explanation */
revents |= POLLIN;
}
if(revents & POLLIN){
s->data_to_read=1;
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
if(r<0){
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
if(s->callbacks){
s->callbacks->exception(s->callbacks->user,
SSH_SOCKET_EXCEPTION_ERROR,
s->last_errno);
}
}
if(r==0){
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
if(s->callbacks){
s->callbacks->exception(s->callbacks->user,
SSH_SOCKET_EXCEPTION_EOF,
0);
}
}
if(r>0){
/* Bufferize the data and then call the callback */
buffer_add_data(s->in_buffer,buffer,r);
if(s->callbacks){
r= s->callbacks->data(s->callbacks->user,
buffer_get_rest(s->in_buffer), buffer_get_rest_len(s->in_buffer));
buffer_pass_bytes(s->in_buffer,r);
}
}
}
if(revents & POLLOUT){
s->data_to_write=1;
/* If buffered data is pending, write it */
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));
} else if(s->callbacks){
/* Otherwise advertise the upper level that write can be done */
s->callbacks->controlflow(s->callbacks->user,SSH_SOCKET_FLOW_WRITEWONTBLOCK);
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLOUT);
/* TODO: Find a way to put back POLLOUT when buffering occurs */
}
}
return 0;
}
void ssh_socket_register_pollcallback(struct socket *s, ssh_poll_handle p){
ssh_poll_set_callback(p,ssh_socket_pollcallback,s);
s->poll=p;
}
/** \internal
* \brief Deletes a socket object
*/
void ssh_socket_free(struct socket *s){
@@ -225,7 +302,10 @@ static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
s->last_errno = errno;
#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 (w < 0) {
s->data_except = 1;
}
@@ -337,7 +417,6 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
return SSH_OK;
}
#define WRITE_BUFFERING_THRESHOLD 65536
/** \internal
* \brief buffered write of data
* \returns SSH_OK, or SSH_ERROR
@@ -345,22 +424,12 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
*/
int ssh_socket_write(struct socket *s, const void *buffer, int len) {
ssh_session session = s->session;
int rc = SSH_ERROR;
enter_function();
if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
return SSH_ERROR;
}
if (buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD) {
rc = ssh_socket_nonblocking_flush(s);
} else {
rc = len;
}
leave_function();
return rc;
return len;
}
@@ -509,64 +578,46 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
}
/** \internal
* \brief nonblocking flush of the output buffer
* \brief starts a nonblocking flush of the output buffer
*
*/
int ssh_socket_nonblocking_flush(struct socket *s) {
ssh_session session = s->session;
int except;
int can_write;
int w;
enter_function();
/* internally sets data_to_write */
if (ssh_socket_poll(s, &can_write, &except) < 0) {
leave_function();
return SSH_ERROR;
}
if (!ssh_socket_is_open(s)) {
session->alive = 0;
/* FIXME use ssh_socket_get_errno */
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(errno));
strerror(s->last_errno));
leave_function();
return SSH_ERROR;
}
while(s->data_to_write && buffer_get_rest_len(s->out_buffer) > 0) {
if (ssh_socket_is_open(s)) {
w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
buffer_get_rest_len(s->out_buffer));
} else {
/* write failed */
w =- 1;
}
if (s->data_to_write && 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) {
session->alive = 0;
ssh_socket_close(s);
/* FIXME use ssh_socket_get_errno() */
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(errno));
strerror(s->last_errno));
leave_function();
return SSH_ERROR;
}
buffer_pass_bytes(s->out_buffer, w);
/* refresh the socket status */
if (ssh_socket_poll(session->socket, &can_write, &except) < 0) {
leave_function();
return SSH_ERROR;
}
}
/* Is there some data pending? */
if (buffer_get_rest_len(s->out_buffer) > 0) {
if (buffer_get_rest_len(s->out_buffer) > 0 && s->poll) {
/* force the poll system to catch pollout events */
ssh_poll_set_events(s->poll, ssh_poll_get_events(s->poll) |POLLOUT);
leave_function();
return SSH_AGAIN;
}