5773093 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n channels.c
  1 /* channels.c */
  2 /* It has support for ... ssh channels */
  3 /*
  4 Copyright 2003 Aris Adamantiadis
  5 
  6 This file is part of the SSH Library
  7 
  8 The SSH Library is free software; you can redistribute it and/or modify
  9 it under the terms of the GNU Lesser General Public License as published by
 10 the Free Software Foundation; either version 2.1 of the License, or (at your
 11 option) any later version.
 12 
 13 The SSH Library is distributed in the hope that it will be useful, but
 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 16 License for more details.
 17 
 18 You should have received a copy of the GNU Lesser General Public License
 19 along with the SSH Library; see the file COPYING.  If not, write to
 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 21 MA 02111-1307, USA. */
 22 
 23 #include "libssh/priv.h"
 24 #include <string.h>
 25 #include <stdlib.h>
 26 #ifdef HAVE_NETDB_H
 27 #include <netdb.h>
 28 #endif
 29 #include <unistd.h>
 30 #include <stdio.h>
 31 
 32 #include "libssh/ssh2.h"
 33 #define WINDOWLIMIT 1024
 34 #define WINDOWBASE 32000
 35 static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr);
 36 static CHANNEL *new_channel(SSH_SESSION *session){
 37     CHANNEL *channel=malloc(sizeof(CHANNEL));
 38     memset(channel,0,sizeof(CHANNEL));
 39     channel->session=session;
 40     if(!session->channels){
 41         session->channels=channel;
 42         channel->next=channel->prev=channel;
 43         return channel;
 44         }
 45     channel->next=session->channels;
 46     channel->prev=session->channels->prev;
 47     channel->next->prev=channel;
 48     channel->prev->next=channel;
 49     return channel;
 50 }
 51 
 52 static u32 channel_new_id(SSH_SESSION *session){
 53     u32 ret=session->maxchannel;
 54     session->maxchannel++;
 55     return ret;
 56 }
 57 
 58 static CHANNEL *channel_open(SSH_SESSION *session,char *type_c,int window,
 59 int maxpacket,BUFFER *payload){
 60     CHANNEL *channel=new_channel(session);
 61     STRING *type=string_from_char(type_c);
 62     u32 foo;
 63     int err;
 64     packet_clear_out(session);
 65     buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN);
 66     channel->local_channel=channel_new_id(session);
 67     channel->local_maxpacket=maxpacket;
 68     channel->local_window=window;
 69     ssh_say(2,"creating a channel %d with %d window and %d max packet\n",channel->local_channel,
 70         window,maxpacket);
 71     buffer_add_ssh_string(session->out_buffer,type);
 72     buffer_add_u32(session->out_buffer,htonl(channel->local_channel));
 73     buffer_add_u32(session->out_buffer,htonl(channel->local_window));
 74     buffer_add_u32(session->out_buffer,htonl(channel->local_maxpacket));
 75     free(type);
 76     if(payload)
 77         buffer_add_buffer(session->out_buffer,payload);
 78     packet_send(session);
 79     ssh_say(2,"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d\n",type_c,channel->local_channel);
 80     err=packet_wait(session,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,1);
 81     switch(session->in_packet.type){
 82         case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
 83             buffer_get_u32(session->in_buffer,&foo);
 84             if(channel->local_channel!=ntohl(foo)){
 85                 ssh_set_error(session,SSH_INVALID_DATA,"server answered with sender chan num %d instead of given %d",
 86                 ntohl(foo),channel->local_channel);
 87                 channel_free(channel);
 88                 return NULL;
 89                 }
 90             buffer_get_u32(session->in_buffer,&foo);
 91             channel->remote_channel=ntohl(foo);
 92             buffer_get_u32(session->in_buffer,&foo);
 93             channel->remote_window=ntohl(foo);
 94             buffer_get_u32(session->in_buffer,&foo);
 95             channel->remote_maxpacket=ntohl(foo);
 96             ssh_say(3,"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d\n",
 97                 channel->local_channel,channel->remote_channel);
 98             ssh_say(3,"Remote window : %ld, maxpacket : %ld\n",
 99         channel->remote_window, channel->remote_maxpacket);
100         channel->open=1;
101             return channel;
102         case SSH2_MSG_CHANNEL_OPEN_FAILURE:
103             {
104                 u32 code;
105                 STRING *error_s;
106                 char *error;
107                 buffer_get_u32(session->in_buffer,&foo);
108                 buffer_get_u32(session->in_buffer,&code);
109                 error_s=buffer_get_ssh_string(session->in_buffer);
110                 error=string_to_char(error_s);
111                 ssh_set_error(session,SSH_REQUEST_DENIED,"Channel opening failure : channel %d error (%d) %s",
112                     channel->local_channel,ntohl(code),error);
113                 free(error);
114                 free(error_s);
115                 channel_free(channel);
116                 return NULL;
117             }
118         default:
119             ssh_say(0,"Received unknown packet %d\n",session->in_packet.type);
120             channel_free(channel);
121             return NULL;
122         }
123     return NULL;
124 }
125 
126 static CHANNEL *find_local_channel(SSH_SESSION *session,u32 num){
127     // we assume we are always the local
128     CHANNEL *initchan,*channel;
129     initchan=session->channels;
130     if(!initchan)
131         return NULL;
132     for(channel=initchan;channel->local_channel!=num;channel=channel->next){
133         if(channel->next==initchan)
134             return NULL;
135     }
136     return channel;
137 }
138 
139 static void grow_window(SSH_SESSION *session, CHANNEL *channel){
140     u32 new_window=WINDOWBASE;
141     packet_clear_out(session);
142     buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST);
143     buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
144     buffer_add_u32(session->out_buffer,htonl(new_window));
145     packet_send(session);
146     ssh_say(3,"growing window (channel %d:%d) to %d bytes\n",
147         channel->local_channel,channel->remote_channel,
148         channel->local_window + new_window);
149     channel->local_window+=new_window;
150 }
151 
152 static CHANNEL *channel_from_msg(SSH_SESSION *session){
153     u32 chan;
154     CHANNEL *channel;
155     if (buffer_get_u32(session->in_buffer,&chan)!=sizeof(u32)){
156         ssh_set_error(session,SSH_FATAL,"Getting channel from message : short read");
157         return NULL;
158     }
159     channel=find_local_channel(session,ntohl(chan));
160     if(!channel)
161         ssh_set_error(session,SSH_FATAL,"Server specified invalid channel %d",ntohl(chan));
162     return channel;
163 }
164 
165 static void channel_rcv_change_window(SSH_SESSION *session){
166     u32 bytes;
167     CHANNEL *channel;
168     int err;
169     channel=channel_from_msg(session);
170     if(!channel)
171         ssh_say(0,"%s\n",ssh_get_error(session));
172     err = buffer_get_u32(session->in_buffer,&bytes);
173     if(!channel || err!= sizeof(u32)){
174         ssh_say(1,"Error getting a window adjust message : invalid packet\n");
175         return;
176     }
177     bytes=ntohl(bytes);
178     ssh_say(3,"Adding %d bytes to channel (%d:%d) (from %d bytes)\n",bytes,
179         channel->local_channel,channel->remote_channel,channel->remote_window);
180     channel->remote_window+=bytes;
181 }
182 
183 /* is_stderr is set to 1 if the data are extended, ie stderr */
184 static void channel_rcv_data(SSH_SESSION *session,int is_stderr){
185     STRING *str;
186     CHANNEL *channel;
187     channel=channel_from_msg(session);
188     if(!channel){
189         ssh_say(0,"%s",ssh_get_error(session));
190         return;
191     }
192     if(is_stderr){
193         u32 ignore;
194         /* uint32 data type code. we can ignore it */
195         buffer_get_u32(session->in_buffer,&ignore);
196     }
197     str=buffer_get_ssh_string(session->in_buffer);
198 
199     if(!str){
200         ssh_say(0,"Invalid data packet !\n");
201         return;
202     }
203     ssh_say(3,"adding %d bytes data in %d\n",string_len(str),is_stderr);
204     /* what shall we do in this case ? let's accept it anyway */
205     if(string_len(str)>channel->local_window)
206         ssh_say(0,"Data packet too big for our window(%d vs %d)",string_len(str),channel->local_window);
207     if(!is_stderr){
208         /* stdout */
209         if(channel->write_fct){
210             channel->write_fct(channel,str->string,string_len(str),channel->userarg);
211         } else {
212             channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
213         }
214     } else {
215         /* stderr */
216         if(channel->write_err_fct){
217             channel->write_err_fct(channel,str->string,string_len(str),channel->userarg);
218         } else {
219             channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
220         }
221     }
222     if(string_len(str)>=channel->local_window)
223         channel->local_window-=string_len(str);
224     else
225         channel->local_window=0; /* buggy remote */
226     if(channel->local_window < WINDOWLIMIT)
227         grow_window(session,channel); /* i wonder if this is the correct place to do that */
228     free(str);
229 }
230 
231 static void channel_rcv_eof(SSH_SESSION *session){
232     CHANNEL *channel;
233     channel=channel_from_msg(session);
234     if(!channel){
235         ssh_say(0,"%s\n",ssh_get_error(session));
236         return;
237     }
238     ssh_say(2,"Received eof on channel (%d:%d)\n",channel->local_channel,
239         channel->remote_channel);
240 //    channel->remote_window=0;
241     channel->remote_eof=1;
242 }
243 
244 static void channel_rcv_close(SSH_SESSION *session){
245     CHANNEL *channel;
246     channel=channel_from_msg(session);
247     if(!channel){
248         ssh_say(0,"%s\n",ssh_get_error(session));
249         return;
250     }
251     ssh_say(2,"Received close on channel (%d:%d)\n",channel->local_channel,
252         channel->remote_channel);
253     channel->open=0;
254     if(!channel->remote_eof)
255         ssh_say(2,"Remote host not polite enough to send an eof before close\n");
256     channel->remote_eof=1;
257 }
258 
259 static void channel_rcv_request(SSH_SESSION *session){
260     STRING *request_s;
261     char *request;
262     u32 status;
263     CHANNEL *channel=channel_from_msg(session);
264     if(!channel){
265         ssh_say(1,"%s\n",ssh_get_error(session));
266         return;
267     }
268     request_s=buffer_get_ssh_string(session->in_buffer);
269     if(!request_s){
270         ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
271         return;
272     }
273     buffer_get_u8(session->in_buffer,(u8 *)&status);
274     request=string_to_char(request_s);
275     if(!strcmp(request,"exit-status")){
276         buffer_get_u32(session->in_buffer,&status);
277         status=ntohl(status);
278 /* XXX do something with status, we might need it */
279         free(request_s);
280         free(request);
281         return ;
282     }
283     if(!strcmp(request,"exit-signal")){
284         STRING *signal_s;
285         char *signal;
286         char *core="(core dumped)";
287         u8 i;
288         signal_s=buffer_get_ssh_string(session->in_buffer);
289         if(!signal_s){
290             ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
291             free(request_s);
292             free(request);
293             return;
294         }
295         signal=string_to_char(signal_s);
296         buffer_get_u8(session->in_buffer,&i);
297         if(!i)
298             core="";
299         ssh_say(0,"Remote connection closed by signal SIG%s %s\n",signal,core);
300         free(signal_s);
301         free(signal);
302         free(request_s);
303         free(request);
304         return;
305     }
306     ssh_say(0,"Unknown request %s\n",request);
307     free(request_s);
308     free(request);
309 }
310 
311 /* channel_handle is called by wait_packet, ie, when there is channel informations to handle . */
312 void channel_handle(SSH_SESSION *session, int type){
313     ssh_say(3,"Channel_handle(%d)\n",type);
314     switch(type){
315         case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
316             channel_rcv_change_window(session);
317             break;
318         case SSH2_MSG_CHANNEL_DATA:
319             channel_rcv_data(session,0);
320             break;
321         case SSH2_MSG_CHANNEL_EXTENDED_DATA:
322             channel_rcv_data(session,1);
323             break;
324         case SSH2_MSG_CHANNEL_EOF:
325             channel_rcv_eof(session);
326             break;
327         case SSH2_MSG_CHANNEL_CLOSE:
328             channel_rcv_close(session);
329             break;
330         case SSH2_MSG_CHANNEL_REQUEST:
331             channel_rcv_request(session);
332             break;
333         default:
334             ssh_say(0,"Unexpected message %d\n",type);
335         }
336 }
337 
338 /* when data has been received from the ssh server, it can be applied to the known
339     user function, with help of the callback, or inserted here */
340 /* XXX is the window changed ? */
341 static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr){
342     ssh_say(3,"placing %d bytes into channel buffer (stderr=%d)\n",len,is_stderr);
343     if(!is_stderr){
344         /* stdout */
345         if(!channel->stdout_buffer)
346             channel->stdout_buffer=buffer_new();
347         buffer_add_data(channel->stdout_buffer,data,len);
348     } else {
349         /* stderr */
350         if(!channel->stderr_buffer)
351             channel->stderr_buffer=buffer_new();
352         buffer_add_data(channel->stderr_buffer,data,len);
353     }
354 }
355 
356 
357 /* --8<-- PUBLIC INTERFACE BEGINS HERE -8<-----8< --- */
358 
359 /* deprecated */
360 CHANNEL *open_session_channel(SSH_SESSION *session,int window,int maxpacket){
361     CHANNEL *chan=channel_open(session,"session",window,maxpacket,NULL);
362     return chan;
363 }
364 
365 CHANNEL *channel_open_session(SSH_SESSION *session){
366     return open_session_channel(session,64000,32000);
367 }
368 
369 /* tcpip forwarding */
370 CHANNEL *channel_open_forward(SSH_SESSION *session,char *remotehost, int remoteport, char *sourcehost, int localport){
371     CHANNEL *chan;
372     BUFFER *payload=buffer_new();
373     STRING *str=string_from_char(remotehost);
374     buffer_add_ssh_string(payload,str);
375     free(str);
376     str=string_from_char(sourcehost);
377     buffer_add_u32(payload,htonl(remoteport));
378     buffer_add_ssh_string(payload,str);
379     free(str);
380     buffer_add_u32(payload,htonl(localport));
381     chan=channel_open(session,"direct-tcpip",64000,32000,payload);
382     buffer_free(payload);
383     return chan;
384 }
385 
386 
387 void channel_free(CHANNEL *channel){
388     SSH_SESSION *session=channel->session;
389     if(session->alive && channel->open)
390         channel_close(channel);
391     /* handle the "my channel is first on session list" case */
392     if(session->channels==channel)
393         session->channels=channel->next;
394     /* handle the "my channel is the only on session list" case */
395     if(channel->next == channel){
396         session->channels=NULL;
397     } else {
398         channel->prev->next=channel->next;
399         channel->next->prev=channel->prev;
400     }
401     if(channel->stdout_buffer)
402         buffer_free(channel->stdout_buffer);
403     if(channel->stderr_buffer)
404         buffer_free(channel->stderr_buffer);
405     /* debug trick to catch use after frees */
406     memset(channel,'X',sizeof(CHANNEL));
407     free(channel);
408 }
409 
410 int channel_send_eof(CHANNEL *channel){
411     SSH_SESSION *session=channel->session;
412     int ret;
413     packet_clear_out(session);
414     buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF);
415     buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
416     ret=packet_send(session);
417     ssh_say(1,"Sent a EOF on client channel (%d:%d)\n",channel->local_channel,
418         channel->remote_channel);
419     channel->local_eof=1;
420     return ret;
421 }
422 
423 int channel_close(CHANNEL *channel){
424     SSH_SESSION *session=channel->session;
425     int ret=0;
426     if(!channel->local_eof)
427         ret=channel_send_eof(channel);
428     if(ret)
429         return ret;
430     packet_clear_out(session);
431     buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE);
432     buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
433     ret=packet_send(session);
434     ssh_say(1,"Sent a close on client channel (%d:%d)\n",channel->local_channel,
435         channel->remote_channel);
436     if(!ret)
437         channel->open =0;
438     return ret;
439 }
440 
441 /* Blocking write */
442 /* The exact len is written */
443 int channel_write(CHANNEL *channel ,void *data,int len){
444     SSH_SESSION *session=channel->session;
445     int effectivelen;
446     int origlen=len;
447     if(channel->local_eof){
448         ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d"
449             " after EOF was sent",channel->local_channel,channel->remote_channel);
450         return -1;
451     }
452     while(len >0){
453         if(channel->remote_window<len){
454         ssh_say(2,"Remote window is %d bytes. going to write %d bytes\n",
455         channel->remote_window,len);
456         ssh_say(2,"Waiting for a growing window message...\n");
457             // wonder what happens when the channel window is zero
458             while(channel->remote_window==0){
459                 // parse every incoming packet
460                 packet_wait(channel->session,0,0);
461             }
462             effectivelen=len>channel->remote_window?channel->remote_window:len;
463         } else
464             effectivelen=len;
465         packet_clear_out(session);
466         buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA);
467         buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
468         buffer_add_u32(session->out_buffer,htonl(effectivelen));
469         buffer_add_data(session->out_buffer,data,effectivelen);
470         packet_send(session);
471         ssh_say(2,"channel_write wrote %d bytes\n",effectivelen);
472         channel->remote_window-=effectivelen;
473         len -= effectivelen;
474         data+=effectivelen;
475     }
476     return origlen;
477 }
478 
479 int channel_is_open(CHANNEL *channel){
480     return (channel->open!=0);
481 }
482 
483 
484 static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int reply){
485     STRING *request_s=string_from_char(request);
486     SSH_SESSION *session=channel->session;
487     int err;
488     packet_clear_out(session);
489     buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST);
490     buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
491     buffer_add_ssh_string(session->out_buffer,request_s);
492     buffer_add_u8(session->out_buffer,reply?1:0);
493     if(buffer)
494         buffer_add_data(session->out_buffer,buffer_get(buffer),buffer_get_len(buffer));
495     packet_send(session);
496     ssh_say(3,"Sent a SSH_MSG_CHANNEL_REQUEST %s\n",request);
497     free(request_s);
498     if(!reply)
499         return 0;
500     err=packet_wait(session,SSH2_MSG_CHANNEL_SUCCESS,1);
501     if(err)
502         if(session->in_packet.type==SSH2_MSG_CHANNEL_FAILURE){
503             ssh_say(2,"%s channel request failed\n",request);
504             ssh_set_error(session,SSH_REQUEST_DENIED,"Channel request %s failed",request);
505         }
506         else
507             ssh_say(3,"Received an unexpected %d message\n",session->in_packet.type);
508     else
509         ssh_say(3,"Received a SUCCESS\n");
510     return err;
511 }
512 
513 int channel_request_pty_size(CHANNEL *channel, char *terminal, int col, int row){
514     STRING *term=string_from_char(terminal);
515     BUFFER *buffer=buffer_new();
516     int err;
517     buffer_add_ssh_string(buffer,term);
518     buffer_add_u32(buffer,htonl(col));
519     buffer_add_u32(buffer,htonl(row));
520     buffer_add_u32(buffer,0);
521     buffer_add_u32(buffer,0);
522 /* a 0byte string */
523     buffer_add_u32(buffer,htonl(1));
524     buffer_add_u8(buffer,0);
525     free(term);
526     err=channel_request(channel,"pty-req",buffer,1);
527     buffer_free(buffer);
528     return err;
529 }
530 
531 int channel_request_pty(CHANNEL *channel){
532     return channel_request_pty_size(channel,"xterm",80,24);
533 }
534 
535 int channel_change_pty_size(CHANNEL *channel,int cols,int rows){
536     BUFFER *buffer=buffer_new();
537     int err;
538     //buffer_add_u8(buffer,0);
539     buffer_add_u32(buffer,htonl(cols));
540     buffer_add_u32(buffer,htonl(rows));
541     buffer_add_u32(buffer,0);
542     buffer_add_u32(buffer,0);
543     err=channel_request(channel,"window-change",buffer,0);
544     buffer_free(buffer);
545     return err;
546 }    
547     
548 int channel_request_shell(CHANNEL *channel){
549     int err=channel_request(channel,"shell",NULL,1);
550     return err;
551 }
552 
553 int channel_request_subsystem(CHANNEL *channel, char *system){
554     BUFFER* buffer=buffer_new();
555     int ret;
556     STRING *subsystem=string_from_char(system);
557     buffer_add_ssh_string(buffer,subsystem);
558     free(subsystem);
559     ret=channel_request(channel,"subsystem",buffer,1);
560     buffer_free(buffer);
561     return ret;
562 }
563     
564 int channel_request_sftp( CHANNEL *channel){
565     return channel_request_subsystem(channel, "sftp");
566 }
567 
568 
569 int channel_request_env(CHANNEL *channel,char *name, char *value){
570     BUFFER *buffer=buffer_new();
571     int ret;
572     STRING *string=string_from_char(name);
573     buffer_add_ssh_string(buffer,string);
574     free(string);
575     string=string_from_char(value);
576     buffer_add_ssh_string(buffer,string);
577     free(string);
578     ret=channel_request(channel,"env",buffer,1);
579     buffer_free(buffer);
580     return ret;
581 }
582 
583 int channel_request_exec(CHANNEL *channel, char *cmd){
584     BUFFER *buffer=buffer_new();
585     int ret;
586     STRING *command=string_from_char(cmd);
587     buffer_add_ssh_string(buffer,command);
588     free(command);
589     ret=channel_request(channel,"exec",buffer,1);
590     buffer_free(buffer);
591     return ret;
592 }
593 
594 int channel_set_write_handler(CHANNEL *chan,
595         void (*write_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
596     chan->write_fct=write_fct;
597     chan->userarg=user;
598     return 0;
599 }
600 
601 int channel_set_stderr_write_handler(CHANNEL *chan,
602         void (*write_err_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
603     chan->write_err_fct=write_err_fct;
604     chan->userarg=user;
605     return 0;
606 }
607 
608 
609 /* reads into a channel and put result into buffer */
610 /* returns number of bytes read, 0 if eof or such and -1 in case of error */
611 /* if bytes != 0, the exact number of bytes are going to be read */
612 int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr){
613     BUFFER *stdbuf=NULL;
614     int len;
615     buffer_reinit(buffer);
616     /* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */
617     if(channel->write_fct){
618         ssh_set_error(channel->session,SSH_INVALID_REQUEST,"Specified channel hasn't got a default buffering system\n");
619         return -1;
620     }
621     if(is_stderr){
622         if(!channel->stderr_buffer)
623             channel->stderr_buffer=buffer_new();
624         stdbuf=channel->stderr_buffer;
625     } else {
626         if(!channel->stdout_buffer)
627             channel->stdout_buffer=buffer_new();
628         stdbuf=channel->stdout_buffer;
629     }
630     /* block reading if asked bytes=0 */
631     while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){
632         if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0)
633             return 0;
634         if(channel->remote_eof)
635             break; /* return the resting bytes in buffer */
636         if(packet_read(channel->session)||packet_translate(channel->session))
637             return -1;
638         packet_parse(channel->session);
639     }
640     
641     if(bytes==0){
642         /* write the ful buffer informations */
643         buffer_add_data(buffer,buffer_get_rest(stdbuf),buffer_get_rest_len(stdbuf));
644         buffer_reinit(stdbuf);
645     } else {
646         len=buffer_get_rest_len(stdbuf);
647         len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */
648         buffer_add_data(buffer,buffer_get_rest(stdbuf),len);
649         buffer_pass_bytes(stdbuf,len);
650     }
651     return buffer_get_len(buffer);
652 }
653 
654 /* returns the number of bytes available, 0 if nothing is currently available, -1 if error */
655 int channel_poll(CHANNEL *channel, int is_stderr){
656     BUFFER *buffer;
657 
658     if (!channel) {
659         return(-1);
660     }
661 
662     if(is_stderr){
663         buffer=channel->stderr_buffer;
664         if(!buffer)
665             buffer=channel->stderr_buffer=buffer_new();
666     } else {
667         buffer = channel->stdout_buffer;
668         if(!buffer)
669             buffer=channel->stdout_buffer=buffer_new();
670     }
671     while(buffer_get_len(buffer)==0){
672         if(ssh_fd_poll(channel->session)){
673             if(packet_read(channel->session)||packet_translate(channel->session))
674                 return -1;
675             packet_parse(channel->session);
676         } else
677             return 0; /* nothing is available has said fd_poll */
678     }
679     return buffer_get_len(buffer);
680 }
681 
682 /* nonblocking read on the specified channel. it will return <=len bytes of data read
683  atomicly. */
684 int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr){
685     int to_read=channel_poll(channel,is_stderr);
686     int lu;
687     BUFFER *buffer=buffer_new();
688     if(to_read<=0){
689         buffer_free(buffer);
690         return to_read; /* may be an error code */
691     }
692     if(to_read>len)
693         to_read=len;
694     lu=channel_read(channel,buffer,to_read,is_stderr);
695     memcpy(dest,buffer_get(buffer),lu>=0?lu:0);
696     buffer_free(buffer);
697     return lu;
698 }
5773094 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50