aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2008-03-04 00:44:02 +0000
committerAris Adamantiadis <aris@0xbadc0de.be>2008-03-04 00:44:02 +0000
commit077dd81fcc9453613de18c6d037ef61f3a8e161c (patch)
tree027bfb56ae17b1395100809a6ab791551ab8ca0e
parent9b5f8935132433d64757ac60ce0ee4e8c59a8af8 (diff)
downloadlibssh-077dd81fcc9453613de18c6d037ef61f3a8e161c.tar.gz
libssh-077dd81fcc9453613de18c6d037ef61f3a8e161c.tar.xz
libssh-077dd81fcc9453613de18c6d037ef61f3a8e161c.zip
added the socket class and created wrappers
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@137 7dcaeef0-15fb-0310-b436-a5af3365683c
-rw-r--r--include/libssh/priv.h19
-rw-r--r--libssh/Makefile.am3
-rw-r--r--libssh/channels.c27
-rw-r--r--libssh/client.c40
-rw-r--r--libssh/connect.c25
-rw-r--r--libssh/packet.c65
-rw-r--r--libssh/server.c3
-rw-r--r--libssh/session.c11
-rw-r--r--libssh/socket.c150
9 files changed, 244 insertions, 99 deletions
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index b871e1f7..08f9744d 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -285,7 +285,7 @@ struct error_struct {
struct ssh_session {
struct error_struct error;
- int fd;
+ struct socket *socket;
SSH_OPTIONS *options;
char *serverbanner;
char *clientbanner;
@@ -422,6 +422,21 @@ struct ssh_message {
struct ssh_channel_request channel_request;
};
+/* socketc.c */
+
+struct socket;
+struct socket *ssh_socket_new();
+void ssh_socket_free(struct socket *s);
+void ssh_socket_set_fd(struct socket *s, int fd);
+int ssh_socket_get_fd(struct socket *s);
+void ssh_socket_close(struct socket *s);
+int ssh_socket_read(struct socket *s, void *buffer, int len);
+int ssh_socket_write(struct socket *s,const void *buffer, int len);
+int ssh_socket_is_open(struct socket *s);
+int ssh_socket_fd_isset(struct socket *s, fd_set *set);
+void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max);
+int ssh_socket_completeread(struct socket *s, void *buffer, int len);
+
/* session.c */
void ssh_cleanup(SSH_SESSION *session);
@@ -603,7 +618,7 @@ char *my_gcry_bn2dec(bignum bn);
#endif /* !HAVE_LIBGCRYPT */
#ifdef __cplusplus
-} ;
+}
#endif
#endif /* _LIBSSH_PRIV_H */
diff --git a/libssh/Makefile.am b/libssh/Makefile.am
index 3804ac76..50367a4e 100644
--- a/libssh/Makefile.am
+++ b/libssh/Makefile.am
@@ -6,7 +6,8 @@ libssh_la_SOURCES = auth1.c auth.c base64.c buffer.c \
gzip.c init.c kex.c keyfiles.c \
keys.c messages.c misc.c options.c \
packet.c server.c session.c sftp.c \
- sftpserver.c string.c wrapper.c
+ sftpserver.c string.c wrapper.c \
+ socket.c
libssh_la_CPPFLAGS = -I$(top_srcdir)/include
diff --git a/libssh/channels.c b/libssh/channels.c
index b9f757df..65a2af3a 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -905,7 +905,7 @@ static int channel_protocol_select(CHANNEL **rchans, CHANNEL **wchans, CHANNEL *
j=0;
for(i=0;echans[i];++i){
chan=echans[i];
- if(chan->session->fd==-1 || !chan->open || chan->session->data_except){
+ if(!ssh_socket_is_open(chan->session->socket) || !chan->open || chan->session->data_except){
eout[j]=chan;
++j;
}
@@ -940,7 +940,7 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
CHANNEL *dummy=NULL;
CHANNEL **rchans, **wchans, **echans;
int fdmax=-1;
- int i,fd;
+ int i;
int r;
/* don't allow NULL pointers */
if(!readchans)
@@ -980,12 +980,25 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
FD_ZERO(&wset);
FD_ZERO(&eset);
for(i=0;readchans[i];++i){
- fd=readchans[i]->session->fd;
+ if(!ssh_socket_fd_isset(readchans[i]->session->socket,&rset))
+ ssh_socket_fd_set(readchans[i]->session->socket, &rset, &fdmax);
+ }
+ for(i=0;writechans[i];++i){
+ if(!ssh_socket_fd_isset(writechans[i]->session->socket,&wset))
+ ssh_socket_fd_set(writechans[i]->session->socket,&wset, &fdmax);
+ }
+ for(i=0;exceptchans[i];++i){
+ if(!ssh_socket_fd_isset(exceptchans[i]->session->socket,&eset))
+ ssh_socket_fd_set(exceptchans[i]->session->socket,&eset,&fdmax);
+ }
+
+/* fd=readchans[i]->session->fd;
if(!FD_ISSET(fd,&rset)){
FD_SET(fd,&rset);
if(fd>=fdmax)
fdmax=fd+1;
}
+
}
for(i=0;writechans[i];++i){
fd=writechans[i]->session->fd;
@@ -995,6 +1008,7 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
fdmax=fd+1;
}
}
+
for(i=0;exceptchans[i];++i){
fd=exceptchans[i]->session->fd;
if(!FD_ISSET(fd,&eset)){
@@ -1003,6 +1017,7 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
fdmax=fd+1;
}
}
+*/
/* here we go */
r=select(fdmax,&rset,&wset,&eset,timeout);
/* leave if select was interrupted */
@@ -1013,15 +1028,15 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
return SSH_EINTR;
}
for(i=0;readchans[i];++i){
- if(FD_ISSET(readchans[i]->session->fd,&rset))
+ if(ssh_socket_fd_isset(readchans[i]->session->socket,&rset))
readchans[i]->session->data_to_read=1;
}
for(i=0;writechans[i];++i){
- if(FD_ISSET(writechans[i]->session->fd,&wset))
+ if(ssh_socket_fd_isset(writechans[i]->session->socket,&wset))
writechans[i]->session->data_to_write=1;
}
for(i=0;exceptchans[i];++i){
- if(FD_ISSET(exceptchans[i]->session->fd,&eset))
+ if(ssh_socket_fd_isset(exceptchans[i]->session->socket,&eset))
exceptchans[i]->session->data_except=1;
}
} while(1); /* return to do loop */
diff --git a/libssh/client.c b/libssh/client.c
index 9af4e627..c498a9ad 100644
--- a/libssh/client.c
+++ b/libssh/client.c
@@ -36,7 +36,7 @@ char *ssh_get_banner(SSH_SESSION *session){
char buffer[128];
int i = 0;
while (i < 127) {
- if(session->fd <0 || read(session->fd, &buffer[i], 1)<=0){
+ if(!ssh_socket_is_open(session->socket) || ssh_socket_read(session->socket, &buffer[i], 1)<=0){
ssh_set_error(session,SSH_FATAL,"Remote host closed connection");
return NULL;
}
@@ -98,7 +98,7 @@ int ssh_send_banner(SSH_SESSION *session,int server){
else
session->clientbanner=strdup(banner);
snprintf(buffer,128,"%s\r\n",banner);
- write(session->fd,buffer,strlen(buffer));
+ ssh_socket_write(session->socket,buffer,strlen(buffer));
return 0;
}
@@ -247,12 +247,10 @@ int ssh_connect(SSH_SESSION *session){
if(fd<0)
return -1;
set_status(options,0.2);
- session->fd=fd;
+ ssh_socket_set_fd(session->socket,fd);
session->alive=1;
if(!(session->serverbanner=ssh_get_banner(session))){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
@@ -260,9 +258,7 @@ int ssh_connect(SSH_SESSION *session){
ssh_say(2,"banner : %s\n",session->serverbanner);
/* here we analyse the different protocols the server allows */
if(ssh_analyze_banner(session,&ssh1,&ssh2)){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
@@ -275,8 +271,7 @@ int ssh_connect(SSH_SESSION *session){
ssh_set_error(session,SSH_FATAL,
"no version of SSH protocol usable (banner: %s)",
session->serverbanner);
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
@@ -285,27 +280,21 @@ int ssh_connect(SSH_SESSION *session){
switch(session->version){
case 2:
if(ssh_get_kex(session,0)){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
set_status(options,0.6);
ssh_list_kex(&session->server_kex);
if(set_kex(session)){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
ssh_send_kex(session,0);
set_status(options,0.8);
if(dh_handshake(session)){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
@@ -314,9 +303,7 @@ int ssh_connect(SSH_SESSION *session){
break;
case 1:
if(ssh_get_kex1(session)){
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return -1;
}
@@ -344,7 +331,7 @@ char *ssh_get_issue_banner(SSH_SESSION *session){
*/
void ssh_disconnect(SSH_SESSION *session){
STRING *str;
- if(session->fd!= -1) {
+ if(ssh_socket_is_open(session->socket)) {
packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT);
buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION));
@@ -352,15 +339,14 @@ void ssh_disconnect(SSH_SESSION *session){
buffer_add_ssh_string(session->out_buffer,str);
free(str);
packet_send(session);
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
}
session->alive=0;
ssh_cleanup(session);
}
const char *ssh_copyright(){
- return LIBSSH_VERSION " (c) 2003-2006 Aris Adamantiadis (aris@0xbadc0de.be)"
+ return LIBSSH_VERSION " (c) 2003-2008 Aris Adamantiadis (aris@0xbadc0de.be)"
" Distributed under the LGPL, please refer to COPYING file for informations"
" about your rights" ;
}
diff --git a/libssh/connect.c b/libssh/connect.c
index c797dc28..59760900 100644
--- a/libssh/connect.c
+++ b/libssh/connect.c
@@ -189,37 +189,38 @@ int ssh_fd_poll(SSH_SESSION *session, int *write, int *except){
fd_set rdes; // read set
fd_set wdes; // writing set
fd_set edes; // exception set
+ int fdmax=-1;
FD_ZERO(&rdes);
FD_ZERO(&wdes);
FD_ZERO(&edes);
- if(!session->alive || session->fd<0){
+ if(!session->alive || !ssh_socket_is_open(session->socket)){
*except=1;
*write=0;
session->alive=0;
return 0;
}
if(!session->data_to_read)
- FD_SET(session->fd,&rdes);
+ ssh_socket_fd_set(session->socket,&rdes,&fdmax);
if(!session->data_to_write)
- FD_SET(session->fd,&wdes);
- FD_SET(session->fd,&edes);
+ ssh_socket_fd_set(session->socket,&wdes,&fdmax);
+ ssh_socket_fd_set(session->socket,&edes,&fdmax);
/* Set to return immediately (no blocking) */
sometime.tv_sec = 0;
sometime.tv_usec = 0;
/* Make the call, and listen for errors */
- if (select(session->fd + 1, &rdes,&wdes,&edes, &sometime) < 0) {
+ if (select(fdmax, &rdes,&wdes,&edes, &sometime) < 0) {
ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno));
return -1;
}
if(!session->data_to_read)
- session->data_to_read=FD_ISSET(session->fd,&rdes);
+ session->data_to_read=ssh_socket_fd_isset(session->socket,&rdes);
if(!session->data_to_write)
- session->data_to_write=FD_ISSET(session->fd,&wdes);
- *except=FD_ISSET(session->fd,&edes);
+ session->data_to_write=ssh_socket_fd_isset(session->socket,&wdes);
+ *except=ssh_socket_fd_isset(session->socket,&edes);
*write=session->data_to_write;
return session->data_to_read;
}
@@ -285,9 +286,7 @@ int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *read
memcpy(&localset,readfds,sizeof(fd_set));
for(i=0;channels[i];i++){
if(channels[i]->session->alive){
- FD_SET(channels[i]->session->fd,&localset);
- if(channels[i]->session->fd>maxfd-1)
- maxfd=channels[i]->session->fd+1;
+ ssh_socket_fd_set(channels[i]->session->socket,&localset,&maxfd);
}
}
rep=select(maxfd,&localset,NULL,NULL,timeout);
@@ -301,13 +300,13 @@ int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *read
}
/* set the data_to_read flag on each session */
for(i=0;channels[i];i++)
- if(channels[i]->session->alive && FD_ISSET(channels[i]->session->fd,&localset))
+ if(channels[i]->session->alive && ssh_socket_fd_isset(channels[i]->session->socket,&localset))
channels[i]->session->data_to_read=1;
/* now, test each channel */
j=0;
for(i=0;channels[i];i++){
- if(channels[i]->session->alive && FD_ISSET(channels[i]->session->fd,&localset))
+ if(channels[i]->session->alive && ssh_socket_fd_isset(channels[i]->session->socket,&localset))
if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){
outchannels[j]=channels[i];
j++;
diff --git a/libssh/packet.c b/libssh/packet.c
index 00f87f8e..a4d07267 100644
--- a/libssh/packet.c
+++ b/libssh/packet.c
@@ -34,25 +34,7 @@ MA 02111-1307, USA. */
/* XXX include selected mac size */
static int macsize=SHA_DIGEST_LEN;
-/* completeread will read blocking until len bytes have been read */
-static int completeread(int fd, void *buffer, int len){
- int r;
- int total=0;
- int toread=len;
- if(fd<0)
- return SSH_ERROR;
- while((r=read(fd,buffer+total,toread))){
- if(r==-1)
- return SSH_ERROR;
- total += r;
- toread-=r;
- if(total==len)
- return len;
- if(r==0)
- return 0;
- }
- return total ; /* connection closed */
-}
+
/* in nonblocking mode, socket_read will read as much as it can, and return */
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
@@ -71,13 +53,12 @@ static int socket_read(SSH_SESSION *session,int len){
return SSH_OK;
if(session->blocking){
buf=malloc(to_read);
- r=completeread(session->fd,buf,to_read);
+ r=ssh_socket_completeread(session->socket,buf,to_read);
session->data_to_read=0;
if(r==SSH_ERROR || r ==0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
session->data_except=1;
return SSH_ERROR;
@@ -94,16 +75,14 @@ static int socket_read(SSH_SESSION *session,int len){
return SSH_AGAIN;
session->data_to_read=0;
/* read as much as we can */
- if(session->fd>0)
- r=read(session->fd,buffer,sizeof(buffer));
+ if(ssh_socket_is_open(session->socket))
+ r=ssh_socket_read(session->socket,buffer,sizeof(buffer));
else
r=-1;
if(r<=0){
ssh_set_error(session,SSH_FATAL,
(r==0)?"Connection closed by remote host" : "Error reading socket");
- if(session->fd>=0)
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->data_except=1;
session->alive=0;
return SSH_ERROR;
@@ -341,12 +320,13 @@ int packet_translate(SSH_SESSION *session){
return 0;
}
-static int atomic_write(int fd, void *buffer, int len){
+// FIXME moves it in socket.c and rename it ssh_socket_completewrite()
+static int atomic_write(struct socket *s, void *buffer, int len){
int written;
- if(fd<0)
+ if(!ssh_socket_is_open(s))
return SSH_ERROR;
while(len >0) {
- written=write(fd,buffer,len);
+ written=ssh_socket_write(s,buffer,len);
if(written==0 || written==-1)
return SSH_ERROR;
len-=written;
@@ -361,14 +341,15 @@ static int packet_nonblocking_flush(SSH_SESSION *session){
int except, can_write;
int w;
ssh_fd_poll(session,&can_write,&except); /* internally sets data_to_write */
- if(session->fd<0){
+ if(!ssh_socket_is_open(session->socket)){
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));
return SSH_ERROR;
}
while(session->data_to_write && buffer_get_rest_len(session->out_socket_buffer)>0){
- if(session->fd>=0){
- w=write(session->fd,buffer_get_rest(session->out_socket_buffer),
+ if(ssh_socket_is_open(session->socket)){
+ w=ssh_socket_write(session->socket,buffer_get_rest(session->out_socket_buffer),
buffer_get_rest_len(session->out_socket_buffer));
session->data_to_write=0;
} else
@@ -377,8 +358,8 @@ static int packet_nonblocking_flush(SSH_SESSION *session){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
+ // FIXME use ssh_socket_get_errno()
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
return SSH_ERROR;
@@ -394,7 +375,7 @@ static int packet_nonblocking_flush(SSH_SESSION *session){
/* blocking packet flush */
static int packet_blocking_flush(SSH_SESSION *session){
- if(session->fd<0) {
+ if(!ssh_socket_is_open(session->socket)) {
session->alive=0;
return SSH_ERROR;
}
@@ -402,13 +383,13 @@ static int packet_blocking_flush(SSH_SESSION *session){
return SSH_ERROR;
if(buffer_get_rest(session->out_socket_buffer)==0)
return SSH_OK;
- if(atomic_write(session->fd,buffer_get_rest(session->out_socket_buffer),
+ if(atomic_write(session->socket,buffer_get_rest(session->out_socket_buffer),
buffer_get_rest_len(session->out_socket_buffer))){
session->data_to_write=0;
session->data_except=1;
session->alive=0;
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
+ // FIXME use the proper errno
ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
strerror(errno));
return SSH_ERROR;
@@ -545,8 +526,7 @@ void packet_parse(SSH_SESSION *session){
case SSH_MSG_DISCONNECT:
ssh_say(2,"Received SSH_MSG_DISCONNECT\n");
ssh_set_error(session,SSH_FATAL,"Received SSH_MSG_DISCONNECT");
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return;
case SSH_SMSG_STDOUT_DATA:
@@ -572,8 +552,7 @@ void packet_parse(SSH_SESSION *session){
free(error_s);
free(error);
}
- close(session->fd);
- session->fd=-1;
+ ssh_socket_close(session->socket);
session->alive=0;
return;
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
diff --git a/libssh/server.c b/libssh/server.c
index 4060c54c..06d5879f 100644
--- a/libssh/server.c
+++ b/libssh/server.c
@@ -148,7 +148,8 @@ SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind){
session=ssh_new();
session->server=1;
session->version=2;
- session->fd=fd;
+ session->socket=ssh_socket_new();
+ ssh_socket_set_fd(session->socket,fd);
session->options=ssh_options_copy(ssh_bind->options);
session->dsa_key=dsa;
session->rsa_key=rsa;
diff --git a/libssh/session.c b/libssh/session.c
index 1f19640d..06b31ab3 100644
--- a/libssh/session.c
+++ b/libssh/session.c
@@ -42,7 +42,7 @@ SSH_SESSION *ssh_new() {
memset(session,0,sizeof(SSH_SESSION));
session->next_crypto=crypto_new();
session->maxchannel=FIRST_CHANNEL;
- session->fd=-1;
+ session->socket=ssh_socket_new();
session->alive=0;
session->blocking=1;
return session;
@@ -70,7 +70,8 @@ void ssh_cleanup(SSH_SESSION *session){
crypto_free(session->current_crypto);
if(session->next_crypto)
crypto_free(session->next_crypto);
-
+ if(session->socket)
+ ssh_socket_free(session->socket);
// delete all channels
while(session->channels)
channel_free(session->channels);
@@ -101,10 +102,8 @@ void ssh_cleanup(SSH_SESSION *session){
* \param session current ssh session
*/
void ssh_silent_disconnect(SSH_SESSION *session){
- if(session->fd>=0)
- close(session->fd);
+ ssh_socket_close(session->socket);
session->alive=0;
- session->fd=-1;
ssh_disconnect(session);
}
@@ -135,7 +134,7 @@ void ssh_set_blocking(SSH_SESSION *session,int blocking){
* not connected
*/
int ssh_get_fd(SSH_SESSION *session){
- return session->fd;
+ return ssh_socket_get_fd(session->socket);
}
/** \brief say to the session it has data to read on the file descriptor without blocking
diff --git a/libssh/socket.c b/libssh/socket.c
new file mode 100644
index 00000000..c37fcaa9
--- /dev/null
+++ b/libssh/socket.c
@@ -0,0 +1,150 @@
+/* socket.c */
+/* the Socket class */
+/*
+ * Copyright 2008 Aris Adamantiadis
+ *
+ * This file is part of the SSH Library
+ *
+ * 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. */
+#include "libssh/priv.h"
+#include <unistd.h>
+#include <errno.h>
+#ifdef _WIN_32
+#include <winsock2.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct socket {
+ int fd;
+ int last_errno;
+};
+
+/*
+ * \internal
+ * \brief creates a new Socket object
+ */
+struct socket *ssh_socket_new(){
+ struct socket *s=malloc(sizeof(struct socket));
+ s->fd=-1;
+ s->last_errno=-1;
+ return s;
+}
+
+/* \internal
+ * \brief Deletes a socket object
+ */
+void ssh_socket_free(struct socket *s){
+ free(s);
+}
+
+/* \internal
+ * \brief closes a socket
+ */
+void ssh_socket_close(struct socket *s){
+ if(ssh_socket_is_open(s)){
+#ifdef _WIN_32
+ closesocket(s->fd);
+#else
+ close(s->fd);
+#endif
+ s->last_errno=errno;
+ s->fd=-1;
+ }
+}
+
+/* \internal
+ * \brief sets the file descriptor of the socket
+ */
+void ssh_socket_set_fd(struct socket *s, int fd){
+ s->fd=fd;
+}
+
+/* \internal
+ * \brief returns the file descriptor of the socket
+ */
+int ssh_socket_get_fd(struct socket *s){
+ return s->fd;
+}
+
+/* \internal
+ * \brief returns nonzero if the socket is open
+ */
+int ssh_socket_is_open(struct socket *s){
+ return s->fd != -1;
+}
+
+/* \internal
+ * \brief read len bytes from socket into buffer
+ */
+int ssh_socket_read(struct socket *s, void *buffer, int len){
+ int r=recv(s->fd,buffer,len,0);
+ s->last_errno=errno;
+ return r;
+}
+
+/* \internal
+ * \brief writes len bytes from byffer to socket
+ */
+int ssh_socket_write(struct socket *s,const void *buffer, int len){
+ int w=send(s->fd,buffer,len,0);
+ s->last_errno=errno;
+ return w;
+}
+
+/* \internal
+ * \brief returns nonzero if the current socket is in the fd_set
+ */
+int ssh_socket_fd_isset(struct socket *s, fd_set *set){
+ if(s->fd==-1)
+ return 0;
+ return FD_ISSET(s->fd,set);
+}
+
+/* \internal
+ * \brief sets the current fd in a fd_set and updates the fd_max
+ */
+
+void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max){
+ if(s->fd==-1)
+ return;
+ FD_SET(s->fd,set);
+ if(s->fd>= *fd_max){
+ *fd_max=s->fd+1;
+ }
+}
+
+/* \internal
+ * \brief reads blocking until len bytes have been read
+ */
+int ssh_socket_completeread(struct socket *s, void *buffer, int len){
+ int r;
+ int total=0;
+ int toread=len;
+ if(!ssh_socket_is_open(s))
+ return SSH_ERROR;
+ while((r=ssh_socket_read(s,buffer+total,toread))){
+ if(r==-1)
+ return SSH_ERROR;
+ total += r;
+ toread-=r;
+ if(total==len)
+ return len;
+ if(r==0)
+ return 0;
+ }
+ return total ; /* connection closed */
+}