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
Этот коммит содержится в:
родитель
5367581ce1
Коммит
77603dbc5a
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
Copyright (c) 2003-2008 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
@ -122,15 +122,37 @@ char *ssh_get_error(void *error);
|
||||
int ssh_get_error_code(void *error);
|
||||
void ssh_say(int priority,char *format,...);
|
||||
void ssh_set_verbosity(int num);
|
||||
/** \addtogroup ssh_log
|
||||
* @{
|
||||
*/
|
||||
/** \brief Verbosity level for logging and help to debugging
|
||||
*/
|
||||
|
||||
/* There is a verbosity level */
|
||||
|
||||
#define SSH_LOG_NOLOG 0 // no log
|
||||
enum {
|
||||
/** No logging at all
|
||||
*/
|
||||
SSH_LOG_NOLOG=0,
|
||||
/** Only rare and noteworthy events
|
||||
*/
|
||||
SSH_LOG_RARE,
|
||||
/** High level protocol informations
|
||||
*/
|
||||
SSH_LOG_PROTOCOL,
|
||||
/** Lower level protocol infomations, packet level
|
||||
*/
|
||||
SSH_LOG_PACKET,
|
||||
/** Every function path
|
||||
*/
|
||||
SSH_LOG_FUNCTIONS
|
||||
};
|
||||
/** @}
|
||||
*/
|
||||
/*#define SSH_LOG_NOLOG 0 // no log
|
||||
#define SSH_LOG_RARE 1 // rare conditions
|
||||
#define SSH_LOG_ENTRY 2 // user-accessible entrypoints
|
||||
#define SSH_LOG_PACKET 3 // packet id and size
|
||||
#define SSH_LOG_FUNCTIONS 4 // every function in and return
|
||||
|
||||
*/
|
||||
/* log.c */
|
||||
void ssh_log(SSH_SESSION *session, int prioriry, char *format, ...);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
Copyright (c) 2003-2008 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
@ -322,10 +322,7 @@ struct ssh_session {
|
||||
BUFFER *in_buffer;
|
||||
PACKET in_packet;
|
||||
BUFFER *out_buffer;
|
||||
|
||||
BUFFER *out_socket_buffer;
|
||||
BUFFER *in_socket_buffer;
|
||||
|
||||
|
||||
/* the states are used by the nonblocking stuff to remember */
|
||||
/* where it was before being interrupted */
|
||||
int packet_state;
|
||||
@ -426,11 +423,11 @@ struct ssh_message {
|
||||
struct ssh_channel_request channel_request;
|
||||
};
|
||||
|
||||
/* socketc.c */
|
||||
/* socket.c */
|
||||
|
||||
struct socket;
|
||||
void ssh_socket_init();
|
||||
struct socket *ssh_socket_new();
|
||||
struct socket *ssh_socket_new(SSH_SESSION *session);
|
||||
void ssh_socket_free(struct socket *s);
|
||||
void ssh_socket_set_fd(struct socket *s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(struct socket *s);
|
||||
@ -441,6 +438,10 @@ 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);
|
||||
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session,int len);
|
||||
int ssh_socket_nonblocking_flush(struct socket *s);
|
||||
int ssh_socket_blocking_flush(struct socket *s);
|
||||
int ssh_socket_poll(struct socket *s, int *write, int *except);
|
||||
|
||||
/* session.c */
|
||||
|
||||
@ -486,7 +487,7 @@ unsigned char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len
|
||||
int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,unsigned char *mac);
|
||||
|
||||
/* in packet.c */
|
||||
void packet_clear_out(SSH_SESSION *session);
|
||||
|
||||
void packet_parse(SSH_SESSION *session);
|
||||
int packet_send(SSH_SESSION *session);
|
||||
|
||||
@ -546,8 +547,8 @@ void buffer_add_ssh_string(BUFFER *buffer,STRING *string);
|
||||
void buffer_add_u8(BUFFER *buffer, u8 data);
|
||||
void buffer_add_u32(BUFFER *buffer, u32 data);
|
||||
void buffer_add_u64(BUFFER *buffer,u64 data);
|
||||
void buffer_add_data(BUFFER *buffer, void *data, int len);
|
||||
void buffer_add_data_begin(BUFFER *buffer,void *data,int len);
|
||||
void buffer_add_data(BUFFER *buffer,const void *data, int len);
|
||||
void buffer_add_data_begin(BUFFER *buffer,const void *data,int len);
|
||||
void buffer_add_buffer(BUFFER *buffer, BUFFER *source);
|
||||
void buffer_reinit(BUFFER *buffer);
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
19
libssh/kex.c
19
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;
|
||||
|
||||
|
@ -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);
|
||||
|
275
libssh/packet.c
275
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))
|
||||
if(packet_read1(session) || packet_translate(session)){
|
||||
leave_function();
|
||||
return -1;
|
||||
if(packet_translate(session))
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
295
libssh/socket.c
295
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
|
||||
}
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user