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

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59