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
Этот коммит содержится в:
родитель
dda7808851
Коммит
152da07023
@ -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();
|
||||
|
4
sample.c
4
sample.c
@ -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);
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user