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 } |