socket.c | socket.c | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | |||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |||
* License for more details. | * License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Lesser General Public License | * 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 | * along with the SSH Library; see the file COPYING. If not, write to | |||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |||
* MA 02111-1307, USA. | * MA 02111-1307, USA. | |||
*/ | */ | |||
#include <unistd.h> | ||||
#include <errno.h> | #include <errno.h> | |||
#include <string.h> | #include <string.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#ifdef _WIN32 | #ifdef _WIN32 | |||
#include <winsock2.h> | #include <winsock2.h> | |||
#else | #else | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#include <sys/socket.h> | #include <sys/socket.h> | |||
#include <sys/un.h> | #include <sys/un.h> | |||
#endif | #endif | |||
#include "libssh/priv.h" | #include "libssh/priv.h" | |||
#include "libssh/socket.h" | ||||
#include "libssh/buffer.h" | ||||
#include "libssh/poll.h" | ||||
#include "libssh/session.h" | ||||
/** \defgroup ssh_socket SSH Sockets | /** \defgroup ssh_socket SSH Sockets | |||
* \addtogroup ssh_socket | * \addtogroup ssh_socket | |||
* @{ | * @{ | |||
*/ | */ | |||
struct socket { | struct socket { | |||
socket_t fd; | socket_t fd; | |||
int last_errno; | int last_errno; | |||
int data_to_read; /* reading now on socket will | int data_to_read; /* reading now on socket will | |||
not block */ | not block */ | |||
int data_to_write; | int data_to_write; | |||
int data_except; | int data_except; | |||
BUFFER *out_buffer; | ssh_buffer out_buffer; | |||
BUFFER *in_buffer; | ssh_buffer in_buffer; | |||
SSH_SESSION *session; | ssh_session session; | |||
}; | }; | |||
/* | /* | |||
* \internal | * \internal | |||
* \brief inits the socket system (windows specific) | * \brief inits the socket system (windows specific) | |||
*/ | */ | |||
int ssh_socket_init(void) { | int ssh_socket_init(void) { | |||
#ifdef _WIN32 | #ifdef _WIN32 | |||
struct WSAData wsaData; | struct WSAData wsaData; | |||
skipping to change at line 75 | skipping to change at line 78 | |||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { | if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { | |||
return -1; | return -1; | |||
} | } | |||
#endif | #endif | |||
return 0; | return 0; | |||
} | } | |||
/* | /* | |||
* \internal | * \internal | |||
* \brief creates a new Socket object | * \brief creates a new Socket object | |||
*/ | */ | |||
struct socket *ssh_socket_new(SSH_SESSION *session) { | struct socket *ssh_socket_new(ssh_session session) { | |||
struct socket *s; | struct socket *s; | |||
s = malloc(sizeof(struct socket)); | s = malloc(sizeof(struct socket)); | |||
if (s == NULL) { | if (s == NULL) { | |||
return NULL; | return NULL; | |||
} | } | |||
s->fd = -1; | s->fd = -1; | |||
s->last_errno = -1; | s->last_errno = -1; | |||
s->session = session; | s->session = session; | |||
s->in_buffer = buffer_new(); | s->in_buffer = buffer_new(); | |||
skipping to change at line 185 | skipping to change at line 188 | |||
/* \internal | /* \internal | |||
* \brief returns nonzero if the socket is open | * \brief returns nonzero if the socket is open | |||
*/ | */ | |||
int ssh_socket_is_open(struct socket *s) { | int ssh_socket_is_open(struct socket *s) { | |||
return s->fd != -1; | return s->fd != -1; | |||
} | } | |||
/* \internal | /* \internal | |||
* \brief read len bytes from socket into buffer | * \brief read len bytes from socket into buffer | |||
*/ | */ | |||
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, u32 l en) { | static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, uint3 2_t len) { | |||
int rc = -1; | int rc = -1; | |||
if (s->data_except) { | if (s->data_except) { | |||
return -1; | return -1; | |||
} | } | |||
rc = recv(s->fd,buffer, len, 0); | rc = recv(s->fd,buffer, len, 0); | |||
#ifdef _WIN32 | #ifdef _WIN32 | |||
s->last_errno = WSAGetLastError(); | s->last_errno = WSAGetLastError(); | |||
#else | #else | |||
skipping to change at line 211 | skipping to change at line 214 | |||
s->data_except = 1; | s->data_except = 1; | |||
} | } | |||
return rc; | return rc; | |||
} | } | |||
/* \internal | /* \internal | |||
* \brief writes len bytes from buffer to socket | * \brief writes len bytes from buffer to socket | |||
*/ | */ | |||
static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer , | static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer , | |||
u32 len) { | uint32_t len) { | |||
int w = -1; | int w = -1; | |||
if (s->data_except) { | if (s->data_except) { | |||
return -1; | return -1; | |||
} | } | |||
w = send(s->fd,buffer, len, 0); | w = send(s->fd,buffer, len, 0); | |||
#ifdef _WIN32 | #ifdef _WIN32 | |||
s->last_errno = WSAGetLastError(); | s->last_errno = WSAGetLastError(); | |||
#else | #else | |||
skipping to change at line 259 | skipping to change at line 262 | |||
return; | return; | |||
FD_SET(s->fd,set); | FD_SET(s->fd,set); | |||
if (s->fd >= *fd_max) { | if (s->fd >= *fd_max) { | |||
*fd_max = s->fd + 1; | *fd_max = s->fd + 1; | |||
} | } | |||
} | } | |||
/** \internal | /** \internal | |||
* \brief reads blocking until len bytes have been read | * \brief reads blocking until len bytes have been read | |||
*/ | */ | |||
int ssh_socket_completeread(struct socket *s, void *buffer, u32 len) { | int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len) { | |||
int r = -1; | int r = -1; | |||
u32 total = 0; | uint32_t total = 0; | |||
u32 toread = len; | uint32_t toread = len; | |||
if(! ssh_socket_is_open(s)) { | if(! ssh_socket_is_open(s)) { | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
while((r = ssh_socket_unbuffered_read(s, buffer + total, toread))) { | while((r = ssh_socket_unbuffered_read(s, ((uint8_t*)buffer + total), tore ad))) { | |||
if (r < 0) { | if (r < 0) { | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
total += r; | total += r; | |||
toread -= r; | toread -= r; | |||
if (total == len) { | if (total == len) { | |||
return len; | return len; | |||
} | } | |||
if (r == 0) { | if (r == 0) { | |||
return 0; | return 0; | |||
} | } | |||
} | } | |||
/* connection closed */ | /* connection closed */ | |||
return total; | return total; | |||
} | } | |||
/** \internal | /** \internal | |||
* \brief Blocking write of len bytes | * \brief Blocking write of len bytes | |||
*/ | */ | |||
int ssh_socket_completewrite(struct socket *s, const void *buffer, u32 len) | int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t | |||
{ | len) { | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
int written = -1; | int written = -1; | |||
enter_function(); | enter_function(); | |||
if(! ssh_socket_is_open(s)) { | if(! ssh_socket_is_open(s)) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
while (len >0) { | while (len >0) { | |||
written = ssh_socket_unbuffered_write(s, buffer, len); | written = ssh_socket_unbuffered_write(s, buffer, len); | |||
if (written == 0 || written == -1) { | if (written == 0 || written == -1) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
len -= written; | len -= written; | |||
buffer += written; | buffer = ((uint8_t*)buffer + written); | |||
} | } | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
/** \internal | /** \internal | |||
* \brief buffered read of data (complete) | * \brief buffered read of data (complete) | |||
* \returns SSH_OK or SSH_ERROR. | * \returns SSH_OK or SSH_ERROR. | |||
* \returns SSH_AGAIN in nonblocking mode | * \returns SSH_AGAIN in nonblocking mode | |||
*/ | */ | |||
int ssh_socket_read(struct socket *s, void *buffer, int len){ | int ssh_socket_read(struct socket *s, void *buffer, int len){ | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
enter_function(); | enter_function(); | |||
rc = ssh_socket_wait_for_data(s, s->session, len); | rc = ssh_socket_wait_for_data(s, s->session, len); | |||
if (rc != SSH_OK) { | if (rc != SSH_OK) { | |||
leave_function(); | leave_function(); | |||
return rc; | return rc; | |||
} | } | |||
skipping to change at line 344 | skipping to change at line 347 | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
#define WRITE_BUFFERING_THRESHOLD 65536 | #define WRITE_BUFFERING_THRESHOLD 65536 | |||
/** \internal | /** \internal | |||
* \brief buffered write of data | * \brief buffered write of data | |||
* \returns SSH_OK, or SSH_ERROR | * \returns SSH_OK, or SSH_ERROR | |||
* \warning has no effect on socket before a flush | * \warning has no effect on socket before a flush | |||
*/ | */ | |||
int ssh_socket_write(struct socket *s, const void *buffer, int len) { | int ssh_socket_write(struct socket *s, const void *buffer, int len) { | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
enter_function(); | enter_function(); | |||
if (buffer_add_data(s->out_buffer, buffer, len) < 0) { | if (buffer_add_data(s->out_buffer, buffer, len) < 0) { | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
if (buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD) { | if (buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD) { | |||
rc = ssh_socket_nonblocking_flush(s); | rc = ssh_socket_nonblocking_flush(s); | |||
skipping to change at line 372 | skipping to change at line 375 | |||
/** \internal | /** \internal | |||
* \brief wait for data on socket | * \brief wait for data on socket | |||
* \param s socket | * \param s socket | |||
* \param session the ssh session | * \param session the ssh session | |||
* \param len number of bytes to be read | * \param len number of bytes to be read | |||
* \returns SSH_OK bytes are available on socket | * \returns SSH_OK bytes are available on socket | |||
* \returns SSH_AGAIN need to call later for data | * \returns SSH_AGAIN need to call later for data | |||
* \returns SSH_ERROR error happened | * \returns SSH_ERROR error happened | |||
*/ | */ | |||
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 le n) { | int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_ t len) { | |||
char buffer[4096] = {0}; | char buffer[4096] = {0}; | |||
char *buf = NULL; | char *buf = NULL; | |||
int except; | int except; | |||
int can_write; | int can_write; | |||
int to_read; | int to_read; | |||
int r; | int r; | |||
enter_function(); | enter_function(); | |||
to_read = len - buffer_get_rest_len(s->in_buffer); | to_read = len - buffer_get_rest_len(s->in_buffer); | |||
skipping to change at line 448 | skipping to change at line 451 | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
(r == 0) ? "Connection closed by remote host" : | (r == 0) ? "Connection closed by remote host" : | |||
"Error reading socket"); | "Error reading socket"); | |||
ssh_socket_close(session->socket); | ssh_socket_close(session->socket); | |||
session->alive = 0; | session->alive = 0; | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
if (buffer_add_data(s->in_buffer,buffer, (u32) r) < 0) { | if (buffer_add_data(s->in_buffer,buffer, (uint32_t) r) < 0) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
} while(buffer_get_rest_len(s->in_buffer) < len); | } while(buffer_get_rest_len(s->in_buffer) < len); | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
/* ssh_socket_poll */ | /* ssh_socket_poll */ | |||
int ssh_socket_poll(struct socket *s, int *writeable, int *except) { | int ssh_socket_poll(struct socket *s, int *writeable, int *except) { | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
pollfd_t fd[1]; | ssh_pollfd_t fd[1]; | |||
int rc = -1; | int rc = -1; | |||
enter_function(); | enter_function(); | |||
if (!ssh_socket_is_open(s)) { | if (!ssh_socket_is_open(s)) { | |||
*except = 1; | *except = 1; | |||
*writeable = 0; | *writeable = 0; | |||
return 0; | return 0; | |||
} | } | |||
skipping to change at line 511 | skipping to change at line 514 | |||
*writeable = s->data_to_write; | *writeable = s->data_to_write; | |||
leave_function(); | leave_function(); | |||
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0)); | return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0)); | |||
} | } | |||
/** \internal | /** \internal | |||
* \brief nonblocking flush of the output buffer | * \brief nonblocking flush of the output buffer | |||
*/ | */ | |||
int ssh_socket_nonblocking_flush(struct socket *s) { | int ssh_socket_nonblocking_flush(struct socket *s) { | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
int except; | int except; | |||
int can_write; | int can_write; | |||
int w; | int w; | |||
enter_function(); | enter_function(); | |||
/* internally sets data_to_write */ | /* internally sets data_to_write */ | |||
if (ssh_socket_poll(s, &can_write, &except) < 0) { | if (ssh_socket_poll(s, &can_write, &except) < 0) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
skipping to change at line 579 | skipping to change at line 582 | |||
/* all data written */ | /* all data written */ | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
/** \internal | /** \internal | |||
* \brief locking flush of the output packet buffer | * \brief locking flush of the output packet buffer | |||
*/ | */ | |||
int ssh_socket_blocking_flush(struct socket *s) { | int ssh_socket_blocking_flush(struct socket *s) { | |||
SSH_SESSION *session = s->session; | ssh_session session = s->session; | |||
enter_function(); | enter_function(); | |||
if (!ssh_socket_is_open(s)) { | if (!ssh_socket_is_open(s)) { | |||
session->alive = 0; | session->alive = 0; | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
End of changes. 18 change blocks. | ||||
23 lines changed or deleted | 26 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |