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