aboutsummaryrefslogtreecommitdiff
path: root/libssh
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2008-06-16 23:02:49 +0000
committerAris Adamantiadis <aris@0xbadc0de.be>2008-06-16 23:02:49 +0000
commit77603dbc5a5c55ecfa8d583c133db844673fb690 (patch)
tree96c4ad653c74e1d53791f4a73c49d43cdcb58359 /libssh
parent5367581ce1d52518343bb8ede60738f4035e033a (diff)
downloadlibssh-77603dbc5a5c55ecfa8d583c133db844673fb690.tar.gz
libssh-77603dbc5a5c55ecfa8d583c133db844673fb690.tar.xz
libssh-77603dbc5a5c55ecfa8d583c133db844673fb690.zip
Big changes :
refactoring of the socket class. Now the buffering happens in the socket class. enhanced the logging system. Cleaned up some debugging messages. Verified the working with ssh-1. If this cleanup introduced bugs (it did but corrected the found ones) at least, they will be easier to find also added the (c) and fixed dates for updated files git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@169 7dcaeef0-15fb-0310-b436-a5af3365683c
Diffstat (limited to 'libssh')
-rw-r--r--libssh/auth.c8
-rw-r--r--libssh/auth1.c4
-rw-r--r--libssh/buffer.c6
-rw-r--r--libssh/channels.c10
-rw-r--r--libssh/channels1.c6
-rw-r--r--libssh/client.c9
-rw-r--r--libssh/connect.c44
-rw-r--r--libssh/kex.c19
-rw-r--r--libssh/messages.c8
-rw-r--r--libssh/packet.c275
-rw-r--r--libssh/server.c3
-rw-r--r--libssh/session.c11
-rw-r--r--libssh/socket.c295
13 files changed, 376 insertions, 322 deletions
diff --git a/libssh/auth.c b/libssh/auth.c
index a2fd722d..57d0bd61 100644
--- a/libssh/auth.c
+++ b/libssh/auth.c
@@ -1,6 +1,6 @@
/* auth.c deals with authentication methods */
/*
-Copyright 2003-2005 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -160,7 +160,6 @@ int ssh_userauth_none(SSH_SESSION *session,char *username){
user=string_from_char(username);
method=string_from_char("none");
service=string_from_char("ssh-connection");
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@@ -220,7 +219,6 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STR
method=string_from_char("publickey");
algo=string_from_char(ssh_type_to_char(type));
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@@ -284,7 +282,6 @@ int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey,
/* we said previously the public key was accepted */
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@@ -352,7 +349,6 @@ int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){
method=string_from_char("password");
password_s=string_from_char(password);
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user);
buffer_add_ssh_string(session->out_buffer,service);
@@ -567,7 +563,6 @@ static int kbdauth_init(SSH_SESSION *session,
STRING *method=string_from_char("keyboard-interactive");
int err;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
buffer_add_ssh_string(session->out_buffer,user_s);
buffer_add_ssh_string(session->out_buffer,service);
@@ -650,7 +645,6 @@ static int kbdauth_send(SSH_SESSION *session) {
int i;
int err;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE);
buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts));
for(i=0;i<session->kbdint->nprompts;++i){
diff --git a/libssh/auth1.c b/libssh/auth1.c
index 865f2257..7844d9ba 100644
--- a/libssh/auth1.c
+++ b/libssh/auth1.c
@@ -1,6 +1,6 @@
/* auth1.c deals with authentication with SSH-1 protocol */
/*
-Copyright 2005 Aris Adamantiadis
+Copyright (c) 2005-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -52,7 +52,6 @@ static int send_username(SSH_SESSION *session, char *username){
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
if(session->auth_service_asked)
return session->auth_service_asked;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_USER);
if(!username)
if(!(username=session->options->username)){
@@ -192,7 +191,6 @@ int ssh_userauth1_password(SSH_SESSION *session,char *username,char *password){
strcpy((char *)password_s->string,password);
}
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_AUTH_PASSWORD);
buffer_add_ssh_string(session->out_buffer,password_s);
string_burn(password_s);
diff --git a/libssh/buffer.c b/libssh/buffer.c
index 88cca409..3dea65d1 100644
--- a/libssh/buffer.c
+++ b/libssh/buffer.c
@@ -1,5 +1,5 @@
/*
-Copyright 2003-2008 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -75,7 +75,7 @@ static void realloc_buffer(BUFFER *buffer,int needed){
* \param data data pointer
* \param len length of data
*/
-void buffer_add_data(BUFFER *buffer,void *data,int len){
+void buffer_add_data(BUFFER *buffer,const void *data,int len){
if(buffer->allocated < buffer->used+len)
realloc_buffer(buffer,buffer->used+len);
memcpy(buffer->data+buffer->used,data,len);
@@ -105,7 +105,7 @@ void buffer_add_u8(BUFFER *buffer,u8 data){
* \param data data to add
* \param len length of data
*/
-void buffer_add_data_begin(BUFFER *buffer, void *data, int len){
+void buffer_add_data_begin(BUFFER *buffer, const void *data, int len){
if(buffer->allocated < buffer->used + len)
realloc_buffer(buffer,buffer->used+len);
memmove(buffer->data+len,buffer->data,buffer->used);
diff --git a/libssh/channels.c b/libssh/channels.c
index be87ca3e..10e9223b 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -1,5 +1,5 @@
/*
-Copyright 2003-2008 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -72,7 +72,6 @@ static int channel_open(CHANNEL *channel,char *type_c,int window,
u32 foo;
int err;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN);
channel->local_channel=ssh_channel_new_id(session);
channel->local_maxpacket=maxpacket;
@@ -152,7 +151,6 @@ CHANNEL *ssh_channel_from_local(SSH_SESSION *session,u32 num){
static void grow_window(SSH_SESSION *session, CHANNEL *channel){
u32 new_window=WINDOWBASE;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_u32(session->out_buffer,htonl(new_window));
@@ -473,7 +471,6 @@ int channel_send_eof(CHANNEL *channel){
SSH_SESSION *session=channel->session;
int ret;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
ret=packet_send(session);
@@ -503,7 +500,6 @@ int channel_close(CHANNEL *channel){
leave_function();
return ret;
}
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
ret=packet_send(session);
@@ -527,6 +523,7 @@ int channel_write(CHANNEL *channel ,void *data,int len){
SSH_SESSION *session=channel->session;
int effectivelen;
int origlen=len;
+ int err;
enter_function();
if(channel->local_eof){
ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d"
@@ -544,6 +541,7 @@ int channel_write(CHANNEL *channel ,void *data,int len){
err = channel_write1(channel,data,len);
leave_function();
return err;
+ }
#endif
while(len >0){
if(channel->remote_window<len){
@@ -558,7 +556,6 @@ int channel_write(CHANNEL *channel ,void *data,int len){
effectivelen=len>channel->remote_window?channel->remote_window:len;
} else
effectivelen=len;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_u32(session->out_buffer,htonl(effectivelen));
@@ -619,7 +616,6 @@ static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int re
SSH_SESSION *session=channel->session;
int err;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST);
buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
buffer_add_ssh_string(session->out_buffer,request_s);
diff --git a/libssh/channels1.c b/libssh/channels1.c
index c8ab3e24..d90d2398 100644
--- a/libssh/channels1.c
+++ b/libssh/channels1.c
@@ -67,7 +67,6 @@ int channel_request_pty_size1(CHANNEL *channel, char *terminal, int col,
STRING *str;
SSH_SESSION *session=channel->session;
str=string_from_char(terminal);
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_REQUEST_PTY);
buffer_add_ssh_string(session->out_buffer,str);
free(str);
@@ -105,7 +104,6 @@ int channel_request_pty_size1(CHANNEL *channel, char *terminal, int col,
int channel_change_pty_size1(CHANNEL *channel, int cols, int rows){
SSH_SESSION *session=channel->session;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_WINDOW_SIZE);
buffer_add_u32(session->out_buffer,ntohl(rows));
buffer_add_u32(session->out_buffer,ntohl(cols));
@@ -132,7 +130,6 @@ int channel_change_pty_size1(CHANNEL *channel, int cols, int rows){
int channel_request_shell1(CHANNEL *channel){
SSH_SESSION *session=channel->session;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL);
if(packet_send(session))
return -1;
@@ -143,7 +140,6 @@ int channel_request_shell1(CHANNEL *channel){
int channel_request_exec1(CHANNEL *channel, char *cmd){
SSH_SESSION *session=channel->session;
STRING *command=string_from_char(cmd);
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_CMD);
buffer_add_ssh_string(session->out_buffer,command);
free(command);
@@ -179,7 +175,6 @@ static void channel_rcv_close1(SSH_SESSION *session){
/* actually status is lost somewhere */
channel->open=0;
channel->remote_eof=1;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_EXIT_CONFIRMATION);
packet_send(session);
}
@@ -204,7 +199,6 @@ int channel_write1(CHANNEL *channel, void *data, int len){
int origlen=len;
int effectivelen;
while(len>0){
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH_CMSG_STDIN_DATA);
if(len > 32000)
effectivelen=32000;
diff --git a/libssh/client.c b/libssh/client.c
index f06a7363..c1dc6daf 100644
--- a/libssh/client.c
+++ b/libssh/client.c
@@ -1,6 +1,6 @@
/* client.c file */
/*
-Copyright 2003-2005 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -37,7 +37,7 @@ char *ssh_get_banner(SSH_SESSION *session){
char *ret;
enter_function();
while (i < 127) {
- if(!ssh_socket_is_open(session->socket) || ssh_socket_read(session->socket, &buffer[i], 1)<=0){
+ if(ssh_socket_read(session->socket, &buffer[i], 1)!= SSH_OK){
ssh_set_error(session,SSH_FATAL,"Remote host closed connection");
leave_function();
return NULL;
@@ -105,6 +105,7 @@ int ssh_send_banner(SSH_SESSION *session,int server){
session->clientbanner=strdup(banner);
snprintf(buffer,128,"%s\r\n",banner);
ssh_socket_write(session->socket,buffer,strlen(buffer));
+ ssh_socket_blocking_flush(session->socket);
leave_function();
return 0;
}
@@ -121,7 +122,6 @@ static int dh_handshake(SSH_SESSION *session){
enter_function();
switch(session->dh_handshake_state){
case DH_STATE_INIT:
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT);
dh_generate_x(session);
dh_generate_e(session);
@@ -170,7 +170,6 @@ static int dh_handshake(SSH_SESSION *session){
session->dh_server_signature=signature;
dh_build_k(session);
// send the MSG_NEWKEYS
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
packet_send(session);
session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND;
@@ -228,7 +227,6 @@ static int dh_handshake(SSH_SESSION *session){
int ssh_service_request(SSH_SESSION *session,char *service){
STRING *service_s;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST);
service_s=string_from_char(service);
buffer_add_ssh_string(session->out_buffer,service_s);
@@ -376,7 +374,6 @@ void ssh_disconnect(SSH_SESSION *session){
STRING *str;
enter_function();
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));
str=string_from_char("Bye Bye");
diff --git a/libssh/connect.c b/libssh/connect.c
index 8a42b0c1..a5156763 100644
--- a/libssh/connect.c
+++ b/libssh/connect.c
@@ -1,7 +1,7 @@
/* connect.c */
/* it handles connections to ssh servers */
/*
-Copyright 2003 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -220,47 +220,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host, const char
* \return 1 if it is possible to read, 0 otherwise, -1 on error
*/
int ssh_fd_poll(SSH_SESSION *session, int *write, int *except){
- struct timeval sometime;
- fd_set rdes; // read set
- fd_set wdes; // writing set
- fd_set edes; // exception set
- int fdmax=-1;
- enter_function();
- FD_ZERO(&rdes);
- FD_ZERO(&wdes);
- FD_ZERO(&edes);
-
- if(!session->alive || !ssh_socket_is_open(session->socket)){
- *except=1;
- *write=0;
- session->alive=0;
- leave_function();
- return 0;
- }
- if(!session->data_to_read)
- ssh_socket_fd_set(session->socket,&rdes,&fdmax);
- if(!session->data_to_write)
- 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(fdmax, &rdes,&wdes,&edes, &sometime) < 0) {
- ssh_set_error(session,SSH_FATAL, "select: %s", strerror(errno));
- leave_function();
- return -1;
- }
- if(!session->data_to_read)
- session->data_to_read=ssh_socket_fd_isset(session->socket,&rdes);
- if(!session->data_to_write)
- session->data_to_write=ssh_socket_fd_isset(session->socket,&wdes);
- *except=ssh_socket_fd_isset(session->socket,&edes);
- *write=session->data_to_write;
- leave_function();
- return session->data_to_read;
+ return ssh_socket_poll(session->socket,write,except);
}
diff --git a/libssh/kex.c b/libssh/kex.c
index 0856fdfe..f63dbf26 100644
--- a/libssh/kex.c
+++ b/libssh/kex.c
@@ -1,6 +1,6 @@
/* kex.c is used well, in key exchange :-) */
/*
-Copyright 2003 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -254,7 +254,6 @@ void ssh_send_kex(SSH_SESSION *session, int server_kex){
int i=0;
KEX *kex=(server_kex ? &session->server_kex : &session->client_kex);
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT);
buffer_add_data(session->out_buffer,kex->cookie,16);
hashbufout_add_cookie(session);
@@ -412,12 +411,12 @@ int ssh_get_kex1(SSH_SESSION *session){
int ko;
u16 bits;
enter_function();
- ssh_say(3,"Waiting for a SSH_SMSG_PUBLIC_KEY\n");
+ ssh_log(session,SSH_LOG_PROTOCOL,"Waiting for a SSH_SMSG_PUBLIC_KEY");
if(packet_wait(session,SSH_SMSG_PUBLIC_KEY,1)){
leave_function();
return -1;
}
- ssh_say(3,"Got a SSH_SMSG_PUBLIC_KEY\n");
+ ssh_log(session,SSH_LOG_PROTOCOL,"Got a SSH_SMSG_PUBLIC_KEY");
if(buffer_get_data(session->in_buffer,session->server_kex.cookie,8)!=8){
ssh_set_error(session,SSH_FATAL,"Can't get cookie in buffer");
leave_function();
@@ -433,7 +432,7 @@ int ssh_get_kex1(SSH_SESSION *session){
buffer_get_u32(session->in_buffer,&supported_ciphers_mask);
ko=buffer_get_u32(session->in_buffer,&supported_authentications_mask);
if((ko!=sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp){
- ssh_say(2,"Invalid SSH_SMSG_PUBLIC_KEY packet\n");
+ ssh_log(session,SSH_LOG_RARE,"Invalid SSH_SMSG_PUBLIC_KEY packet");
ssh_set_error(session,SSH_FATAL,"Invalid SSH_SMSG_PUBLIC_KEY packet");
if(host_mod)
free(host_mod);
@@ -451,8 +450,8 @@ int ssh_get_kex1(SSH_SESSION *session){
protocol_flags=ntohl(protocol_flags);
supported_ciphers_mask=ntohl(supported_ciphers_mask);
supported_authentications_mask=ntohl(supported_authentications_mask);
- ssh_say(1,"server bits: %d ; host bits: %d\nProtocol flags : %.8lx ; "
- "cipher mask : %.8lx ; auth mask: %.8lx\n",server_bits,
+ ssh_log(session,SSH_LOG_PROTOCOL,"server bits: %d ; host bits: %d Protocol flags : %.8lx ; "
+ "cipher mask : %.8lx ; auth mask: %.8lx",server_bits,
host_bits,protocol_flags,supported_ciphers_mask,
supported_authentications_mask);
serverkey=make_rsa1_string(server_exp,server_mod);
@@ -474,14 +473,14 @@ int ssh_get_kex1(SSH_SESSION *session){
leave_function();
return -1;
}
- packet_clear_out(session);
+ ssh_log(session,SSH_LOG_PROTOCOL,"sending SSH_CMSG_SESSION_KEY");
buffer_add_u8(session->out_buffer,SSH_CMSG_SESSION_KEY);
buffer_add_u8(session->out_buffer,SSH_CIPHER_3DES);
buffer_add_data(session->out_buffer,session->server_kex.cookie,8);
enc_session=encrypt_session_key(session,svr,host,server_bits, host_bits);
bits=string_len(enc_session)*8 - 7;
- ssh_say(2,"%d bits,%d bytes encrypted session\n",bits,string_len(enc_session));
+ ssh_log(session,SSH_LOG_PROTOCOL,"%d bits,%d bytes encrypted session",bits,string_len(enc_session));
bits=htons(bits);
/* the encrypted mpint */
buffer_add_data(session->out_buffer,&bits,sizeof(u16));
@@ -505,7 +504,7 @@ int ssh_get_kex1(SSH_SESSION *session){
leave_function();
return -1;
}
- ssh_say(1,"received SSH_SMSG_SUCCESS\n");
+ ssh_log(session,SSH_LOG_PROTOCOL,"received SSH_SMSG_SUCCESS\n");
leave_function();
return 0;
diff --git a/libssh/messages.c b/libssh/messages.c
index be785e4a..e609cbc6 100644
--- a/libssh/messages.c
+++ b/libssh/messages.c
@@ -58,7 +58,6 @@ static int handle_service_request(SSH_SESSION *session){
service_c=string_to_char(service);
ssh_say(2,"Sending a SERVICE_ACCEPT for service %s\n",service_c);
free(service_c);
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_ACCEPT);
buffer_add_ssh_string(session->out_buffer,service);
packet_send(session);
@@ -68,7 +67,6 @@ static int handle_service_request(SSH_SESSION *session){
}
static void handle_unimplemented(SSH_SESSION *session){
- packet_clear_out(session);
buffer_add_u32(session->out_buffer,htonl(session->recv_seq-1));
packet_send(session);
}
@@ -131,7 +129,6 @@ static int ssh_message_auth_reply_default(SSH_MESSAGE *msg,int partial){
SSH_SESSION *session=msg->session;
int ret;
enter_function();
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_FAILURE);
if(session->auth_methods==0){
session->auth_methods=SSH_AUTH_PUBLICKEY|SSH_AUTH_PASSWORD;
@@ -162,7 +159,6 @@ static int ssh_message_auth_reply_default(SSH_MESSAGE *msg,int partial){
int ssh_message_auth_reply_success(SSH_MESSAGE *msg,int partial){
if(partial)
return ssh_message_auth_reply_default(msg,partial);
- packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS);
return packet_send(msg->session);
}
@@ -205,7 +201,6 @@ CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg){
chan->remote_maxpacket=msg->channel_request_open.packet_size;
chan->remote_window=msg->channel_request_open.window;
chan->open=1;
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
buffer_add_u32(session->out_buffer,htonl(chan->remote_channel));
buffer_add_u32(session->out_buffer,htonl(chan->local_channel));
@@ -223,7 +218,6 @@ CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg){
static int ssh_message_channel_request_open_reply_default(SSH_MESSAGE *msg){
ssh_say(2,"Refusing a channel\n");
- packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_OPEN_FAILURE);
buffer_add_u32(msg->session->out_buffer,htonl(msg->channel_request_open.sender));
buffer_add_u32(msg->session->out_buffer,htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED));
@@ -309,7 +303,6 @@ int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg){
if(msg->channel_request.want_reply){
channel=msg->channel_request.channel->remote_channel;
ssh_say(2,"Sending a channel_request success to channel %d\n",channel);
- packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_SUCCESS);
buffer_add_u32(msg->session->out_buffer,htonl(channel));
return packet_send(msg->session);
@@ -324,7 +317,6 @@ static int ssh_message_channel_request_reply_default(SSH_MESSAGE *msg){
if(msg->channel_request.want_reply){
channel=msg->channel_request.channel->remote_channel;
ssh_say(2,"Sending a default channel_request denied to channel %d\n",channel);
- packet_clear_out(msg->session);
buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_FAILURE);
buffer_add_u32(msg->session->out_buffer,htonl(channel));
return packet_send(msg->session);
diff --git a/libssh/packet.c b/libssh/packet.c
index 295ef13c..c81ff289 100644
--- a/libssh/packet.c
+++ b/libssh/packet.c
@@ -1,7 +1,7 @@
/* packet.c */
/* packet building functions */
/*
-Copyright 2003 Aris Adamantiadis
+Copyright (c) 2003-2008 Aris Adamantiadis
This file is part of the SSH Library
@@ -37,66 +37,6 @@ static int macsize=SHA_DIGEST_LEN;
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
/* in blocking mode, it will read at least len bytes and will block until it's ok. */
-static int socket_read(SSH_SESSION *session,int len){
- enter_function();
- int except, can_write;
- int to_read;
- int r;
- char *buf;
- char buffer[4096];
- if(!session->in_socket_buffer)
- session->in_socket_buffer=buffer_new();
- to_read=len - buffer_get_rest_len(session->in_socket_buffer);
- if(to_read <= 0){
- leave_function();
- return SSH_OK;
- }
- if(session->blocking){
- buf=malloc(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");
- ssh_socket_close(session->socket);
- session->alive=0;
- session->data_except=1;
- leave_function();
- return SSH_ERROR;
- }
-
- buffer_add_data(session->in_socket_buffer,buf,to_read);
- free(buf);
- leave_function();
- return SSH_OK;
- }
- /* nonblocking read */
- do {
- ssh_fd_poll(session,&can_write,&except); /* internally sets data_to_read */
- if(!session->data_to_read){
- leave_function();
- return SSH_AGAIN;
- }
- session->data_to_read=0;
- /* read as much as we can */
- 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");
- ssh_socket_close(session->socket);
- session->data_except=1;
- session->alive=0;
- leave_function();
- return SSH_ERROR;
- }
- buffer_add_data(session->in_socket_buffer,buffer,r);
- } while(buffer_get_rest_len(session->in_socket_buffer)<len);
- leave_function();
- return SSH_OK;
-}
#define PACKET_STATE_INIT 0
#define PACKET_STATE_SIZEREAD 1
@@ -123,14 +63,14 @@ static int packet_read2(SSH_SESSION *session){
buffer_reinit(session->in_buffer);
else
session->in_buffer=buffer_new();
- ret=socket_read(session,blocksize);
+ ret=ssh_socket_wait_for_data(session->socket,session,blocksize);
if(ret != SSH_OK){
leave_function();
return ret; // can be SSH_ERROR or SSH_AGAIN
}
// be_read=completeread(session->fd,buffer,blocksize);
- memcpy(buffer,buffer_get_rest(session->in_socket_buffer),blocksize);
- buffer_pass_bytes(session->in_socket_buffer,blocksize); // mark them as read
+ // can't fail since we're sure there is enough data in socket buffer
+ ssh_socket_read(session->socket,buffer,blocksize);
len=packet_decrypt_len(session,buffer);
buffer_add_data(session->in_buffer,buffer,blocksize);
if(len> MAX_PACKET_LEN){
@@ -153,14 +93,13 @@ static int packet_read2(SSH_SESSION *session){
to_be_read=len-blocksize+sizeof(u32) + current_macsize;
/* if to_be_read is zero, the whole packet was blocksize bytes. */
if(to_be_read != 0){
- ret=socket_read(session,to_be_read);
+ ret=ssh_socket_wait_for_data(session->socket,session,to_be_read);
if(ret!=SSH_OK){
leave_function();
return ret;
}
packet=malloc(to_be_read);
- memcpy(packet,buffer_get_rest(session->in_socket_buffer),to_be_read-current_macsize);
- buffer_pass_bytes(session->in_socket_buffer,to_be_read-current_macsize);
+ ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);
buffer_add_data(session->in_buffer,packet,to_be_read-current_macsize);
free(packet);
@@ -169,8 +108,7 @@ static int packet_read2(SSH_SESSION *session){
/* decrypt the rest of the packet (blocksize bytes already have been decrypted */
packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,
buffer_get_len(session->in_buffer)-blocksize);
- memcpy(mac,buffer_get_rest(session->in_socket_buffer),macsize);
- buffer_pass_bytes(session->in_socket_buffer,macsize);
+ ssh_socket_read(session->socket,mac,macsize);
if(packet_hmac_verify(session,session->in_buffer,mac)){
ssh_set_error(session,SSH_FATAL,"HMAC error");
leave_function();
@@ -223,9 +161,11 @@ static int packet_read1(SSH_SESSION *session){
int to_be_read;
u32 padding;
u32 crc;
- ssh_say(3,"packet_read1()\n");
- if(!session->alive || session->data_except)
- return SSH_ERROR; // the error message was already set
+ enter_function();
+ if(!session->alive || session->data_except){
+ leave_function();
+ return SSH_ERROR; // the error message was already set
+ }
switch (session->packet_state){
case PACKET_STATE_INIT:
memset(&session->in_packet,0,sizeof(PACKET));
@@ -233,18 +173,19 @@ static int packet_read1(SSH_SESSION *session){
buffer_reinit(session->in_buffer);
else
session->in_buffer=buffer_new();
- ret=socket_read(session,sizeof(u32));
- if(ret!=SSH_OK)
- return ret; // could be SSH_AGAIN
- buffer_get_u32(session->in_socket_buffer,&len);
- /* be_read=completeread(session->fd,&len,sizeof(u32)); */
+ ret=ssh_socket_read(session->socket,&len,sizeof(u32));
+ if(ret!=SSH_OK){
+ leave_function();
+ return ret; // could be SSH_AGAIN
+ }
/* len is not encrypted */
len=ntohl(len);
if(len> MAX_PACKET_LEN){
ssh_set_error(session,SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len);
+ leave_function();
return SSH_ERROR;
}
- ssh_say(3,"%d bytes packet\n",len);
+ ssh_log(session,SSH_LOG_PACKET,"reading a %d bytes packet",len);
session->in_packet.len=len;
session->packet_state=PACKET_STATE_SIZEREAD;
case PACKET_STATE_SIZEREAD:
@@ -253,12 +194,13 @@ static int packet_read1(SSH_SESSION *session){
padding=8-(len % 8);
to_be_read=len+padding;
/* it is *not* possible that to_be_read be < 8. */
- ret=socket_read(session,to_be_read);
- if(ret != SSH_OK)
- return ret; // can be SSH_ERROR or SSH_AGAIN
packet=malloc(to_be_read);
- memcpy(packet,buffer_get_rest(session->in_socket_buffer),to_be_read);
- buffer_pass_bytes(session->in_socket_buffer,to_be_read);
+ ret=ssh_socket_read(session->socket,packet,to_be_read);
+ if(ret != SSH_OK){
+ free(packet);
+ leave_function();
+ return ret; // can be SSH_ERROR or SSH_AGAIN
+ }
buffer_add_data(session->in_buffer,packet,to_be_read);
free(packet);
@@ -276,10 +218,11 @@ static int packet_read1(SSH_SESSION *session){
ssh_print_hexa("read packet decrypted:",
buffer_get(session->in_buffer),buffer_get_len(session->in_buffer));
#endif
- ssh_say(3,"%d bytes padding\n",padding);
+ ssh_log(session,SSH_LOG_PACKET,"%d bytes padding",padding);
if((len+padding) != buffer_get_rest_len(session->in_buffer) || (len+padding) < sizeof(u32)){
- ssh_say(2,"no crc32 in packet\n");
+ ssh_log(session,SSH_LOG_RARE,"no crc32 in packet");
ssh_set_error(session,SSH_FATAL,"no crc32 in packet");
+ leave_function();
return SSH_ERROR;
}
memcpy(&crc,buffer_get_rest(session->in_buffer)+(len+padding)-sizeof(u32),
@@ -291,14 +234,15 @@ static int packet_read1(SSH_SESSION *session){
ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
len + padding - sizeof(u32));
#endif
- ssh_say(2,"invalid crc32\n");
+ ssh_log(session,SSH_LOG_RARE,"invalid crc32");
ssh_set_error(session,SSH_FATAL,"invalid crc32 : expected %.8lx, "
"got %.8lx",crc,
ssh_crc32(buffer_get_rest(session->in_buffer),len+padding-sizeof(u32)) );
+ leave_function();
return SSH_ERROR;
}
buffer_pass_bytes(session->in_buffer,padding); /*pass the padding*/
- ssh_say(3,"the packet is valid\n");
+ ssh_log(session,SSH_LOG_PACKET,"the packet is valid");
/* will do that later
#ifdef HAVE_LIBZ
if(session->current_crypto && session->current_crypto->do_compress_in){
@@ -308,9 +252,11 @@ static int packet_read1(SSH_SESSION *session){
*/
session->recv_seq++;
session->packet_state=PACKET_STATE_INIT;
+ leave_function();
return SSH_OK;
}
- ssh_set_error(session,SSH_FATAL,"Invalid state into packet_read2() : %d",session->packet_state);
+ ssh_set_error(session,SSH_FATAL,"Invalid state into packet_read1() : %d",session->packet_state);
+ leave_function();
return SSH_ERROR;
}
@@ -345,123 +291,23 @@ int packet_translate(SSH_SESSION *session){
return 0;
}
-// 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(!ssh_socket_is_open(s))
- return SSH_ERROR;
- while(len >0) {
- written=ssh_socket_write(s,buffer,len);
- if(written==0 || written==-1)
- return SSH_ERROR;
- len-=written;
- buffer+=written;
- }
- return SSH_OK;
-}
-
-/* when doing a nonblocking write, you should issue the packet_write only once, then
- * do packet_nonblocking_flush() until you get a SSH_OK or a SSH_ERROR */
-static int packet_nonblocking_flush(SSH_SESSION *session){
- int except, can_write;
- int w;
- enter_function();
- ssh_fd_poll(session,&can_write,&except); /* internally sets data_to_write */
- 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));
- leave_function();
- return SSH_ERROR;
- }
- while(session->data_to_write && buffer_get_rest_len(session->out_socket_buffer)>0){
- 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
- w=-1; /* write failed */
- if(w<0){
- session->data_to_write=0;
- session->data_except=1;
- session->alive=0;
- 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));
- leave_function();
- return SSH_ERROR;
- }
- buffer_pass_bytes(session->out_socket_buffer,w);
- /* refresh the socket status */
- ssh_fd_poll(session,&can_write,&except);
- }
- if(buffer_get_rest_len(session->out_socket_buffer)>0){
- leave_function();
- return SSH_AGAIN; /* there is data pending */
- }
- leave_function();
- return SSH_OK; // all data written
-}
-
-/* blocking packet flush */
-static int packet_blocking_flush(SSH_SESSION *session){
- enter_function();
- if(!ssh_socket_is_open(session->socket)) {
- session->alive=0;
- leave_function();
- return SSH_ERROR;
- }
- if(session->data_except){
- leave_function();
- return SSH_ERROR;
- }
- if(buffer_get_rest(session->out_socket_buffer)==0){
- leave_function();
- return SSH_OK;
- }
- 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;
- 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));
- leave_function();
- return SSH_ERROR;
- }
- session->data_to_write=0;
- buffer_reinit(session->out_socket_buffer);
- leave_function();
- return SSH_OK; // no data pending
-}
-
/* Write the the bufferized output. If the session is blocking, or enforce_blocking
* is set, the call may block. Otherwise, it won't block.
* return SSH°OK if everything has been sent, SSH_AGAIN if there are still things
* to send on buffer, SSH_ERROR if there is an error. */
int packet_flush(SSH_SESSION *session, int enforce_blocking){
if(enforce_blocking || session->blocking)
- return packet_blocking_flush(session);
- return packet_nonblocking_flush(session);
+ return ssh_socket_blocking_flush(session->socket);
+ return ssh_socket_nonblocking_flush(session->socket);
}
/* this function places the outgoing packet buffer into an outgoing socket buffer */
-static int socket_write(SSH_SESSION *session){
+static int packet_write(SSH_SESSION *session){
int ret;
enter_function();
- if(!session->out_socket_buffer){
- session->out_socket_buffer=buffer_new();
- }
- buffer_add_data(session->out_socket_buffer,
- buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
- if(!session->blocking)
- ret = packet_nonblocking_flush(session);
- else
- ret = packet_blocking_flush(session);
- leave_function();
+ ssh_socket_write(session->socket,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
+ ret=packet_flush(session,0);
+ leave_function();
return ret;
}
@@ -497,7 +343,7 @@ static int packet_send2(SSH_SESSION *session){
hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
if(hmac)
buffer_add_data(session->out_buffer,hmac,20);
- ret=socket_write(session);
+ ret=packet_write(session);
session->send_seq++;
buffer_reinit(session->out_buffer);
leave_function();
@@ -513,7 +359,8 @@ static int packet_send1(SSH_SESSION *session){
u32 currentlen=buffer_get_len(session->out_buffer)+sizeof(u32);
int ret=0;
unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8);
- ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
+ enter_function();
+ ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);
/*
#ifdef HAVE_LIBZ
if(session->current_crypto && session->current_crypto->do_compress_out){
@@ -528,7 +375,7 @@ static int packet_send1(SSH_SESSION *session){
else
memset(padstring,0,padding);
finallen=htonl(currentlen);
- ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen)));
+ ssh_log(session,SSH_LOG_PACKET,"%d bytes after comp + %d padding bytes = %d bytes packet",currentlen,padding,(ntohl(finallen)));
buffer_add_data_begin(session->out_buffer,&padstring,padding);
buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32));
crc=ssh_crc32(buffer_get(session->out_buffer)+sizeof(u32),buffer_get_len(session->out_buffer)-sizeof(u32));
@@ -542,9 +389,11 @@ static int packet_send1(SSH_SESSION *session){
ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer),
buffer_get_len(session->out_buffer));
#endif
- ret=socket_write(session);
+ ssh_socket_write(session->socket,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
+ ret=packet_flush(session,0);
session->send_seq++;
buffer_reinit(session->out_buffer);
+ leave_function();
return ret; /* SSH_OK, AGAIN or ERROR */
}
@@ -620,16 +469,18 @@ void packet_parse(SSH_SESSION *session){
#ifdef HAVE_SSH1
static int packet_wait1(SSH_SESSION *session,int type,int blocking){
- ssh_say(3,"packet_wait1 waiting for %d\n",type);
+ enter_function();
+ ssh_log(session,SSH_LOG_PROTOCOL,"packet_wait1 waiting for %d",type);
while(1){
- if(packet_read1(session))
- return -1;
- if(packet_translate(session))
+ if(packet_read1(session) || packet_translate(session)){
+ leave_function();
return -1;
- ssh_say(3,"packet_wait 1 received %d\n",session->in_packet.type);
+ }
+ ssh_log(session,SSH_LOG_PACKET,"packet_wait 1 received a type %d packet",session->in_packet.type);
switch(session->in_packet.type){
case SSH_MSG_DISCONNECT:
packet_parse(session);
+ leave_function();
return -1;
case SSH_SMSG_STDOUT_DATA:
case SSH_SMSG_STDERR_DATA:
@@ -645,13 +496,18 @@ static int packet_wait1(SSH_SESSION *session,int type,int blocking){
default:
if(type && (type != session->in_packet.type)){
ssh_set_error(session,SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type);
+ leave_function();
return -1;
}
+ leave_function();
return 0;
}
- if(blocking==0)
- return 0;
+ if(blocking==0){
+ leave_function();
+ return 0;
+ }
}
+ leave_function();
return 0;
}
#endif /* HAVE_SSH1 */
@@ -709,12 +565,3 @@ int packet_wait(SSH_SESSION *session, int type, int block){
#endif
return packet_wait2(session,type,block);
}
-
-
-void packet_clear_out(SSH_SESSION *session){
- if(session->out_buffer)
- buffer_reinit(session->out_buffer);
- else
- session->out_buffer=buffer_new();
-}
-
diff --git a/libssh/server.c b/libssh/server.c
index ee9f6d4a..58fbb615 100644
--- a/libssh/server.c
+++ b/libssh/server.c
@@ -163,7 +163,7 @@ SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind){
session=ssh_new();
session->server=1;
session->version=2;
- session->socket=ssh_socket_new();
+ session->socket=ssh_socket_new(session);
ssh_socket_set_fd(session->socket,fd);
session->options=ssh_options_copy(ssh_bind->options);
session->dsa_key=dsa;
@@ -260,7 +260,6 @@ static int dh_handshake_server(SSH_SESSION *session){
free(sign);
packet_send(session);
free(f);
- packet_clear_out(session);
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
packet_send(session);
ssh_say(2,"SSH_MSG_NEWKEYS sent\n");
diff --git a/libssh/session.c b/libssh/session.c
index f8344fa8..80b9e3a1 100644
--- a/libssh/session.c
+++ b/libssh/session.c
@@ -1,7 +1,7 @@
/* session.c */
/* contains the non-networking functions ssh_* */
/*
- * Copyright 2005-2008 Aris Adamantiadis
+ * Copyright (c) 2005-2008 Aris Adamantiadis
*
* This file is part of the SSH Library
*
@@ -41,10 +41,12 @@ SSH_SESSION *ssh_new() {
memset(session,0,sizeof(SSH_SESSION));
session->next_crypto=crypto_new();
session->maxchannel=FIRST_CHANNEL;
- session->socket=ssh_socket_new();
+ session->socket=ssh_socket_new(session);
session->alive=0;
session->blocking=1;
session->log_indent=0;
+ session->out_buffer=buffer_new();
+ session->in_buffer=buffer_new();
return session;
}
@@ -59,10 +61,6 @@ void ssh_cleanup(SSH_SESSION *session){
buffer_free(session->in_buffer);
if(session->out_buffer)
buffer_free(session->out_buffer);
- if(session->in_socket_buffer)
- buffer_free(session->in_socket_buffer);
- if(session->out_socket_buffer)
- buffer_free(session->out_socket_buffer);
if(session->banner)
free(session->banner);
if(session->options)
@@ -105,7 +103,6 @@ void ssh_cleanup(SSH_SESSION *session){
*/
void ssh_silent_disconnect(SSH_SESSION *session){
enter_function();
- ssh_log(session,SSH_LOG_ENTRY,"ssh_silent_disconnect()");
ssh_socket_close(session->socket);
session->alive=0;
ssh_disconnect(session);
diff --git a/libssh/socket.c b/libssh/socket.c
index 2d82ec66..0aefa017 100644
--- a/libssh/socket.c
+++ b/libssh/socket.c
@@ -1,7 +1,7 @@
/* socket.c */
/* the Socket class */
/*
- * Copyright 2008 Aris Adamantiadis
+ * Copyright (c) 2008 Aris Adamantiadis
*
* This file is part of the SSH Library
*
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <errno.h>
+#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#else
@@ -30,9 +31,17 @@
#endif
#include "libssh/priv.h"
+/** \defgroup ssh_socket Sockets
+ * \addtogroup ssh_socket
+ * @{
+ */
+
struct socket {
socket_t fd;
int last_errno;
+ BUFFER *out_buffer;
+ BUFFER *in_buffer;
+ SSH_SESSION *session;
};
/*
@@ -51,10 +60,13 @@ void ssh_socket_init(){
* \internal
* \brief creates a new Socket object
*/
-struct socket *ssh_socket_new(){
+struct socket *ssh_socket_new(SSH_SESSION *session){
struct socket *s=malloc(sizeof(struct socket));
s->fd=-1;
s->last_errno=-1;
+ s->session=session;
+ s->in_buffer=buffer_new();
+ s->out_buffer=buffer_new();
return s;
}
@@ -63,6 +75,8 @@ struct socket *ssh_socket_new(){
*/
void ssh_socket_free(struct socket *s){
ssh_socket_close(s);
+ buffer_free(s->in_buffer);
+ buffer_free(s->out_buffer);
free(s);
}
@@ -106,7 +120,7 @@ int ssh_socket_is_open(struct socket *s){
/* \internal
* \brief read len bytes from socket into buffer
*/
-int ssh_socket_read(struct socket *s, void *buffer, int len){
+int ssh_socket_unbuffered_read(struct socket *s, void *buffer, int len){
int r=recv(s->fd,buffer,len,0);
#ifndef _WIN32
s->last_errno=errno;
@@ -117,9 +131,9 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
}
/* \internal
- * \brief writes len bytes from byffer to socket
+ * \brief writes len bytes from buffer to socket
*/
-int ssh_socket_write(struct socket *s,const void *buffer, int len){
+int ssh_socket_unbuffered_write(struct socket *s,const void *buffer, int len){
int w=send(s->fd,buffer,len,0);
#ifndef _WIN32
s->last_errno=errno;
@@ -152,7 +166,7 @@ void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max){
}
}
-/* \internal
+/** \internal
* \brief reads blocking until len bytes have been read
*/
int ssh_socket_completeread(struct socket *s, void *buffer, int len){
@@ -161,7 +175,7 @@ int ssh_socket_completeread(struct socket *s, void *buffer, int len){
int toread=len;
if(!ssh_socket_is_open(s))
return SSH_ERROR;
- while((r=ssh_socket_read(s,buffer+total,toread))){
+ while((r=ssh_socket_unbuffered_read(s,buffer+total,toread))){
if(r==-1)
return SSH_ERROR;
total += r;
@@ -173,3 +187,270 @@ int ssh_socket_completeread(struct socket *s, void *buffer, int len){
}
return total ; /* connection closed */
}
+
+/** \internal
+ * \brief Blocking write of len bytes
+ */
+
+int ssh_socket_completewrite(struct socket *s, void *buffer, int len){
+ SSH_SESSION *session=s->session;
+ enter_function();
+ int written;
+ if(!ssh_socket_is_open(s)){
+ leave_function();
+ return SSH_ERROR;
+ }
+ while(len >0) {
+ written=ssh_socket_unbuffered_write(s,buffer,len);
+ if(written==0 || written==-1){
+ leave_function();
+ return SSH_ERROR;
+ }
+ len-=written;
+ buffer+=written;
+ }
+ leave_function();
+ return SSH_OK;
+}
+
+/** \internal
+ * \brief buffered read of data (complete)
+ * \returns SSH_OK or SSH_ERROR.
+ * \returns SSH_AGAIN in nonblocking mode
+ */
+int ssh_socket_read(struct socket *s, void *buffer, int len){
+ SSH_SESSION *session=s->session;
+ enter_function();
+ int ret=ssh_socket_wait_for_data(s,s->session,len);
+ if(ret != SSH_OK){
+ leave_function();
+ return ret;
+ }
+ memcpy(buffer,buffer_get_rest(s->in_buffer),len);
+ buffer_pass_bytes(s->in_buffer,len);
+ leave_function();
+ return SSH_OK;
+}
+
+#define WRITE_BUFFERING_THRESHOLD 65536
+/** \internal
+ * \brief buffered write of data
+ * \returns SSH_OK, or SSH_ERROR
+ * \warning has no effect on socket before a flush
+ */
+int ssh_socket_write(struct socket *s,const void *buffer, int len){
+ SSH_SESSION *session=s->session;
+ enter_function();
+ int ret;
+ buffer_add_data(s->out_buffer,buffer,len);
+ if(buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD)
+ ret=ssh_socket_nonblocking_flush(s);
+ else
+ ret=len;
+ leave_function();
+ return ret;
+}
+
+
+/** \internal
+ * \brief wait for data on socket
+ * \param s socket
+ * \param session the ssh session
+ * \param len number of bytes to be read
+ * \returns SSH_OK bytes are available on socket
+ * \returns SSH_AGAIN need to call later for data
+ * \returns SSH_ERROR error happened
+ */
+int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session,int len){
+ int except, can_write;
+ int to_read;
+ int r;
+ char *buf;
+ char buffer[4096];
+ enter_function();
+ to_read=len - buffer_get_rest_len(s->in_buffer);
+ if(to_read <= 0){
+ leave_function();
+ return SSH_OK;
+ }
+ if(session->blocking){
+ buf=malloc(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");
+ ssh_socket_close(session->socket);
+ session->alive=0;
+ session->data_except=1;
+ leave_function();
+ return SSH_ERROR;
+ }
+
+ buffer_add_data(s->in_buffer,buf,to_read);
+ free(buf);
+ leave_function();
+ return SSH_OK;
+ }
+ /* nonblocking read */
+ do {
+ ssh_socket_poll(s,&can_write,&except); /* internally sets data_to_read */
+ if(!session->data_to_read){
+ leave_function();
+ return SSH_AGAIN;
+ }
+ session->data_to_read=0;
+ /* read as much as we can */
+ if(ssh_socket_is_open(session->socket))
+ r=ssh_socket_unbuffered_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");
+ ssh_socket_close(session->socket);
+ session->data_except=1;
+ session->alive=0;
+ leave_function();
+ return SSH_ERROR;
+ }
+ buffer_add_data(s->in_buffer,buffer,r);
+ } while(buffer_get_rest_len(s->in_buffer)<len);
+ leave_function();
+ return SSH_OK;
+}
+
+/* \internal
+ * \brief polls the socket for data
+ * \param session ssh session
+ * \param write value pointed to set to 1 if it is possible to write
+ * \param except value pointed to set to 1 if there is an exception
+ * \return 1 if it is possible to read, 0 otherwise, -1 on error
+ */
+int ssh_socket_poll(struct socket *s, int *write, int *except){
+ SSH_SESSION *session=s->session;
+ struct timeval sometime;
+ 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(!ssh_socket_is_open(s)){
+ *except=1;
+ *write=0;
+ return 0;
+ }
+ if(!session->data_to_read)
+ ssh_socket_fd_set(s,&rdes,&fdmax);
+ if(!session->data_to_write)
+ ssh_socket_fd_set(s,&wdes,&fdmax);
+ ssh_socket_fd_set(s,&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(fdmax, &rdes,&wdes,&edes, &sometime) < 0) {
+ ssh_set_error(session,SSH_FATAL, "select: %s", strerror(errno));
+ leave_function();
+ return -1;
+ }
+ if(!session->data_to_read)
+ session->data_to_read=ssh_socket_fd_isset(session->socket,&rdes);
+ if(!session->data_to_write)
+ 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;
+}
+
+/** \internal
+ * \brief nonblocking flush of the output buffer
+ */
+int ssh_socket_nonblocking_flush(struct socket *s){
+ int except, can_write;
+ int w;
+ SSH_SESSION *session=s->session;
+ enter_function();
+ ssh_socket_poll(s,&can_write,&except); /* internally sets data_to_write */
+ 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));
+ leave_function();
+ return SSH_ERROR;
+ }
+ while(session->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));
+ session->data_to_write=0;
+ } else
+ w=-1; /* write failed */
+ if(w<0){
+ session->data_to_write=0;
+ session->data_except=1;
+ 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));
+ leave_function();
+ return SSH_ERROR;
+ }
+ buffer_pass_bytes(s->out_buffer,w);
+ /* refresh the socket status */
+ ssh_fd_poll(session,&can_write,&except);
+ }
+ if(buffer_get_rest_len(s->out_buffer)>0){
+ leave_function();
+ return SSH_AGAIN; /* there is data pending */
+ }
+ leave_function();
+ return SSH_OK; // all data written
+}
+
+
+/** \internal
+ * \brief locking flush of the output buffer
+ */
+int ssh_socket_blocking_flush(struct socket *s){
+ SSH_SESSION *session=s->session;
+ enter_function();
+ if(!ssh_socket_is_open(s)) {
+ session->alive=0;
+ leave_function();
+ return SSH_ERROR;
+ }
+ if(session->data_except){
+ leave_function();
+ return SSH_ERROR;
+ }
+ if(buffer_get_rest_len(s->out_buffer)==0){
+ leave_function();
+ return SSH_OK;
+ }
+ if(ssh_socket_completewrite(s,buffer_get_rest(s->out_buffer),
+ buffer_get_rest_len(s->out_buffer))){
+ session->data_to_write=0;
+ session->data_except=1;
+ session->alive=0;
+ ssh_socket_close(s);
+ // FIXME use the proper errno
+ ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
+ strerror(errno));
+ leave_function();
+ return SSH_ERROR;
+ }
+ session->data_to_write=0;
+ buffer_reinit(s->out_buffer);
+ leave_function();
+ return SSH_OK; // no data pending
+}
+
+/** @}
+ */