1
1

Implement channel_read() as a POSIX like function.

Create channel_read_buffer() to have the old version still available.


git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@700 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Andreas Schneider 2009-05-04 10:06:49 +00:00
родитель dda7808851
Коммит 152da07023
6 изменённых файлов: 247 добавлений и 125 удалений

Просмотреть файл

@ -281,11 +281,14 @@ int channel_request_sftp(CHANNEL *channel);
int channel_write(CHANNEL *channel, const void *data, u32 len);
int channel_send_eof(CHANNEL *channel);
int channel_is_eof(CHANNEL *channel);
int channel_read(CHANNEL *channel, BUFFER *buffer, u32 bytes, int is_stderr);
int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr);
int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
int is_stderr);
int channel_poll(CHANNEL *channel, int is_stderr);
int channel_close(CHANNEL *channel);
void channel_set_blocking(CHANNEL *channel, int blocking);
int channel_read_nonblocking(CHANNEL *channel, char *dest, u32 len, int is_stderr);
int channel_read_nonblocking(CHANNEL *channel, void *dest, u32 count,
int is_stderr);
int channel_is_open(CHANNEL *channel);
int channel_is_closed(CHANNEL *channel);
int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptchans, struct

Просмотреть файл

@ -1335,90 +1335,248 @@ error:
/* TODO : fix the delayed close thing */
/* TODO : fix the blocking behaviours */
/* reads into a channel and put result into buffer */
/* returns number of bytes read, 0 if eof or such and -1 in case of error */
/* if bytes != 0, the exact number of bytes are going to be read */
/** \brief reads data from a channel
* \param channel channel
* \param buffer buffer which will get the data
* \param bytes number of bytes to be read. If it is bigger
* than 0, the exact size will be read, else (bytes=0) it will return
* once anything is available
* \param is_stderr boolean value to mark reading from the stderr flow.
* \return number of bytes read\n
* 0 on end of file\n
* SSH_ERROR on error
/**
* @brief Read data from a channel into a buffer.
*
* @param channel The channel to read from.
*
* @param buffer The buffer which will get the data.
*
* @param count The count of bytes to be read. If it is biggerthan 0,
* the exact size will be read, else (bytes=0) it will
* return once anything is available.
*
* @param is_stderr A boolean value to mark reading from the stderr stream.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
*/
int channel_read(CHANNEL *channel, BUFFER *buffer, u32 bytes, int is_stderr) {
BUFFER *stdbuf=NULL;
SSH_SESSION *session=channel->session;
u32 maxread=bytes;
u32 len;
int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
int is_stderr) {
SSH_SESSION *session=channel->session;
BUFFER *stdbuf = channel->stdout_buffer;
u32 maxread = count;
u32 len;
buffer_reinit(buffer);
enter_function();
if(bytes==0)
maxread=MAX_PACKET_LEN;
/* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */
if(is_stderr)
stdbuf=channel->stderr_buffer;
else
stdbuf=channel->stdout_buffer;
buffer_reinit(buffer);
/* We may have problem if the window is too small to accept as much data as asked */
ssh_log(session, SSH_LOG_PROTOCOL,
"Read (%d) buffered : %d bytes. Window: %d",
bytes,
buffer_get_rest_len(stdbuf),
channel->local_window);
if(bytes > buffer_get_rest_len(stdbuf) + channel->local_window) {
if (grow_window(session, channel, bytes - buffer_get_rest_len(stdbuf)) < 0) {
leave_function();
return -1;
}
enter_function();
if (count == 0) {
maxread = MAX_PACKET_LEN;
}
if (is_stderr) {
stdbuf = channel->stderr_buffer;
}
/*
* We may have problem if the window is too small to accept as much data
* as asked
*/
ssh_log(session, SSH_LOG_PROTOCOL,
"Read (%d) buffered: %d bytes. Window: %d",
count,
buffer_get_rest_len(stdbuf),
channel->local_window);
if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
if (grow_window(session, channel,
count - buffer_get_rest_len(stdbuf)) < 0) {
leave_function();
return -1;
}
/* block reading if asked bytes=0 */
while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){
if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0){
leave_function();
return 0;
}
if(channel->remote_eof)
break; /* return the resting bytes in buffer */
if(buffer_get_rest_len(stdbuf)>=maxread) // stop reading when buffer is full enough
break;
if ((packet_read(session)) != SSH_OK ||
(packet_translate(session) != SSH_OK)) {
leave_function();
return -1;
}
packet_parse(session);
}
/* block reading if asked bytes=0 */
while (buffer_get_rest_len(stdbuf) == 0 ||
buffer_get_rest_len(stdbuf) < count) {
if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
leave_function();
return 0;
}
if(channel->local_window < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
leave_function();
return -1;
}
if (channel->remote_eof) {
/* Return the resting bytes in buffer */
break;
}
if(bytes==0){
/* write the ful buffer informations */
if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
buffer_get_rest_len(stdbuf)) < 0) {
leave_function();
return -1;
}
buffer_reinit(stdbuf);
} else {
len=buffer_get_rest_len(stdbuf);
len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */
if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
leave_function();
return -1;
}
buffer_pass_bytes(stdbuf,len);
if (buffer_get_rest_len(stdbuf) >= maxread) {
/* Stop reading when buffer is full enough */
break;
}
if ((packet_read(session)) != SSH_OK ||
(packet_translate(session) != SSH_OK)) {
leave_function();
return -1;
}
packet_parse(session);
}
if(channel->local_window < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
leave_function();
return -1;
}
}
if (count == 0) {
/* write the ful buffer informations */
if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
buffer_get_rest_len(stdbuf)) < 0) {
leave_function();
return -1;
}
buffer_reinit(stdbuf);
} else {
/* Read bytes bytes if len is greater, everything otherwise */
len = buffer_get_rest_len(stdbuf);
len = (len > count ? count : len);
if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
leave_function();
return -1;
}
buffer_pass_bytes(stdbuf,len);
}
leave_function();
return buffer_get_len(buffer);
}
/* TODO FIXME Fix the delayed close thing */
/* TODO FIXME Fix the blocking behaviours */
/**
* @brief Reads data from a channel.
*
* @param channel The channel to read from.
*
* @param dest The destination buffer which will get the data.
*
* @param count The count of bytes to be read.
*
* @param is_stderr A boolean value to mark reading from the stderr flow.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
*/
int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr) {
SSH_SESSION *session = channel->session;
BUFFER *stdbuf = channel->stdout_buffer;
u32 len;
enter_function();
if (count == 0) {
leave_function();
return buffer_get_len(buffer);
return 0;
}
if (is_stderr) {
stdbuf=channel->stderr_buffer;
}
/*
* We may have problem if the window is too small to accept as much data
* as asked
*/
ssh_log(session, SSH_LOG_PROTOCOL,
"Read (%d) buffered : %d bytes. Window: %d",
count,
buffer_get_rest_len(stdbuf),
channel->local_window);
if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
if (grow_window(session, channel,
count - buffer_get_rest_len(stdbuf)) < 0) {
leave_function();
return -1;
}
}
/* block reading if asked bytes=0 */
while (buffer_get_rest_len(stdbuf) == 0 ||
buffer_get_rest_len(stdbuf) < count) {
if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
leave_function();
return 0;
}
if (channel->remote_eof) {
/* Return the resting bytes in buffer */
break;
}
if (buffer_get_rest_len(stdbuf) >= count) {
/* Stop reading when buffer is full enough */
break;
}
if ((packet_read(session)) != SSH_OK ||
(packet_translate(session) != SSH_OK)) {
leave_function();
return -1;
}
packet_parse(session);
}
if (channel->local_window < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
leave_function();
return -1;
}
}
len = buffer_get_rest_len(stdbuf);
/* Read count bytes if len is greater, everything otherwise */
len = (len > count ? count : len);
memcpy(dest, buffer_get_rest(stdbuf), len);
buffer_pass_bytes(stdbuf,len);
leave_function();
return len;
}
/**
* @brief Do a nonblocking read on the channel.
*
* A nonblocking read on the specified channel. it will return <= count bytes of
* data read atomicly.
*
* @param channel The channel to read from.
*
* @param dest A pointer to a destination buffer.
*
* @param count The count of bytes of data to be read.
*
* @param is_stderr A boolean to select the stderr stream.
*
* @return The number of bytes read, 0 if nothing is available or
* SSH_ERROR on error.
*
* @warning Don't forget to check for EOF as it would return 0 here.
*
* @see channel_is_eof()
*/
int channel_read_nonblocking(CHANNEL *channel, void *dest, u32 count,
int is_stderr) {
SSH_SESSION *session = channel->session;
u32 to_read;
int rc;
enter_function();
to_read = channel_poll(channel, is_stderr);
if (to_read <= 0) {
leave_function();
return to_read; /* may be an error code */
}
if (to_read > count) {
to_read = count;
}
rc = channel_read(channel, dest, to_read, is_stderr);
leave_function();
return rc;
}
/** \brief polls the channel for data to read
@ -1453,45 +1611,6 @@ int channel_poll(CHANNEL *channel, int is_stderr){
return buffer_get_rest_len(buffer);
}
/* nonblocking read on the specified channel. it will return <=len bytes of data read
atomicly. */
/** This read will make a nonblocking read (unlike channel_read()) and won't force you
* to deal with BUFFER's
* \brief nonblocking read
* \param channel channel
* \param dest pointer to destination for data
* \param len maximum length of data to be read
* \param is_stderr boolean to select the stderr stream
* \return number of bytes read\n
* 0 if nothing is available\n
* SSH_ERROR on error
* \warning don't forget to check for EOF as it would
* return 0 here
* \see channel_is_eof()
*/
int channel_read_nonblocking(CHANNEL *channel, char *dest, u32 len, int is_stderr){
SSH_SESSION *session = channel->session;
BUFFER *buffer;
int lu;
u32 to_read;
enter_function();
to_read=channel_poll(channel,is_stderr);
buffer=buffer_new();
if(to_read<=0){
buffer_free(buffer);
leave_function();
return to_read; /* may be an error code */
}
if(to_read>len)
to_read=len;
lu=channel_read(channel,buffer,to_read,is_stderr);
memcpy(dest,buffer_get(buffer),lu>=0?lu:0);
buffer_free(buffer);
leave_function();
return lu;
}
/** \brief recover the session in which belong a channel
* \param channel channel
* \return the session pointer

Просмотреть файл

@ -18,8 +18,8 @@ SSH_0.3 {
channel_request_pty; channel_request_pty_size; channel_change_pty_size;
channel_request_shell; channel_request_subsystem; channel_request_env;
channel_request_exec; channel_request_sftp; channel_write;
channel_send_eof; channel_read; channel_poll; channel_close;
channel_read_nonblocking; channel_is_open;
channel_send_eof; channel_read_buffer; channel_read; channel_read_nonblocking;
channel_poll; channel_close; channel_is_open;
channel_is_closed; channel_is_eof; channel_select;
ssh_options_new; ssh_options_copy; ssh_options_free; ssh_options_set_wanted_algos;
ssh_options_set_username; ssh_options_set_port; ssh_options_getopt;

Просмотреть файл

@ -237,7 +237,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
return NULL;
}
if (channel_read(sftp->channel, packet->payload, 4, 0) <= 0) {
if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();
@ -252,7 +252,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
}
size = ntohl(size);
if (channel_read(sftp->channel, packet->payload, 1, 0) <= 0) {
if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();
@ -261,7 +261,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
buffer_get_u8(packet->payload, &packet->type);
if (size > 1) {
if (channel_read(sftp->channel, packet->payload, size - 1, 0) <= 0) {
if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();

Просмотреть файл

@ -188,7 +188,7 @@ static void select_loop(SSH_SESSION *session,CHANNEL *channel){
}
if(channels[0]){
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
lus=channel_read(channel,readbuf,0,0);
lus=channel_read_buffer(channel,readbuf,0,0);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
@ -204,7 +204,7 @@ static void select_loop(SSH_SESSION *session,CHANNEL *channel){
write(1,buffer_get(readbuf),lus);
}
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
lus=channel_read(channel,readbuf,0,1);
lus=channel_read_buffer(channel,readbuf,0,1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));

Просмотреть файл

@ -145,7 +145,7 @@ int main(int argc, char **argv){
printf("it works !\n");
buf=buffer_new();
do{
i=channel_read(chan,buf,0,0);
i=channel_read_buffer(chan,buf,0,0);
if(i>0)
write(1,buffer_get(buf),buffer_get_len(buf));
} while (i>0);