- /* remote => local */
- if ( FD_ISSET(remote, ifds) && (rbuf_len < sizeof(rbuf)) ) {
- len = recv( remote, rbuf + rbuf_len, sizeof(rbuf)-rbuf_len, 0);
- if ( len == 0 ) {
- debug("connection closed by peer\n");
- f_remote = 0; /* no more read from socket */
- f_local = 0;
- } else if ( len == -1 ) {
- if (socket_errno() != ECONNRESET) {
- /* error */
- fatal("recv() faield, %d\n", socket_errno());
- } else {
- debug("ECONNRESET detected\n");
- }
- } else {
- debug("recv %d bytes\n", len);
- if ( 1 < f_debug ) /* more verbose */
- report_bytes( "<<<", rbuf, rbuf_len);
- rbuf_len += len;
- }
- }
-
- /* local => remote */
- if ( FD_ISSET(local_in, ifds) && (lbuf_len < sizeof(lbuf)) ) {
- if (local_type == LOCAL_SOCKET)
- len = recv(local_in, lbuf + lbuf_len,
- sizeof(lbuf)-lbuf_len, 0);
- else
- len = read(local_in, lbuf + lbuf_len, sizeof(lbuf)-lbuf_len);
- if ( len == 0 ) {
- /* stdin is EOF */
- debug("local input is EOF\n");
- shutdown(remote, 1); /* no-more writing */
- f_local = 0;
- } else if ( len == -1 ) {
- /* error on reading from stdin */
- fatal("recv() failed, errno = %d\n", errno);
- } else {
- /* repeat */
- lbuf_len += len;
- }
- }
-
- /* flush data in buffer to socket */
- if ( 0 < lbuf_len ) {
- len = send(remote, lbuf, lbuf_len, 0);
- if ( 1 < f_debug ) /* more verbose */
- report_bytes( ">>>", lbuf, lbuf_len);
- if ( len == -1 ) {
- fatal("send() failed, %d\n", socket_errno());
- } else if ( 0 < len ) {
- /* move data on to top of buffer */
- debug("send %d bytes\n", len);
- lbuf_len -= len;
- if ( 0 < lbuf_len )
- memcpy( lbuf, lbuf+len, lbuf_len );
- assert( 0 <= lbuf_len );
- }
- }
-
- /* flush data in buffer to local output */
- if ( 0 < rbuf_len ) {
- if (local_type == LOCAL_SOCKET)
- len = send( local_out, rbuf, rbuf_len, 0);
- else
- len = write( local_out, rbuf, rbuf_len);
- if ( len == -1 ) {
- fatal("output (local) failed, errno=%d\n", errno);
- }
- rbuf_len -= len;
- if ( len < rbuf_len )
- memcpy( rbuf, rbuf+len, rbuf_len );
- assert( 0 <= rbuf_len );
- }
-
- }
-
- return 0;
+ /* remote => local */
+ if ( FD_ISSET(remote, &ifds) && (rbuf_len < (int)sizeof(rbuf)) ) {
+ len = recv( remote, rbuf + rbuf_len, sizeof(rbuf)-rbuf_len, 0);
+ if ( len == 0 ) {
+ debug("connection closed by peer\n");
+ close_reason = REASON_CLOSED_BY_REMOTE;
+ f_remote = 0; /* no more read from socket */
+ f_local = 0;
+ } else if ( len == -1 ) {
+ if (socket_errno() != ECONNRESET) {
+ /* error */
+ fatal("recv() faield, %d\n", socket_errno());
+ } else {
+ debug("ECONNRESET detected\n");
+ }
+ } else {
+ debug("recv %d bytes\n", len);
+ if ( 1 < f_debug ) /* more verbose */
+ report_bytes( "<<<", rbuf, rbuf_len);
+ rbuf_len += len;
+ }
+ }
+
+ /* local => remote */
+ if ( FD_ISSET(local_in, &ifds) && (lbuf_len < (int)sizeof(lbuf)) ) {
+ if (local_type == LOCAL_SOCKET)
+ len = recv(local_in, lbuf + lbuf_len,
+ sizeof(lbuf)-lbuf_len, 0);
+ else
+ len = read(local_in, lbuf + lbuf_len, sizeof(lbuf)-lbuf_len);
+ if ( len == 0 ) {
+ /* stdin is EOF */
+ debug("local input is EOF\n");
+ if (!f_hold_session)
+ shutdown(remote, 1); /* no-more writing */
+ f_local = 0;
+ close_reason = REASON_CLOSED_BY_LOCAL;
+ } else if ( len == -1 ) {
+ /* error on reading from stdin */
+ if (f_hold_session) {
+ debug ("failed to read from local\n");
+ f_local = 0;
+ close_reason = REASON_CLOSED_BY_LOCAL;
+ } else
+ fatal("recv() failed, errno = %d\n", errno);
+ } else {
+ /* repeat */
+ lbuf_len += len;
+ }
+ }
+
+ /* flush data in buffer to socket */
+ if ( 0 < lbuf_len ) {
+ len = send(remote, lbuf, lbuf_len, 0);
+ if ( 1 < f_debug ) /* more verbose */
+ report_bytes( ">>>", lbuf, lbuf_len);
+ if ( len == -1 ) {
+ fatal("send() failed, %d\n", socket_errno());
+ } else if ( 0 < len ) {
+ /* move data on to top of buffer */
+ debug("send %d bytes\n", len);
+ lbuf_len -= len;
+ if ( 0 < lbuf_len )
+ memcpy( lbuf, lbuf+len, lbuf_len );
+ assert( 0 <= lbuf_len );
+ }
+ }
+
+ /* flush data in buffer to local output */
+ if ( 0 < rbuf_len ) {
+ if (local_type == LOCAL_SOCKET)
+ len = send( local_out, rbuf, rbuf_len, 0);
+ else
+ len = write( local_out, rbuf, rbuf_len);
+ if ( len == -1 ) {
+ fatal("output (local) failed, errno=%d\n", errno);
+ }
+ rbuf_len -= len;
+ if ( len < rbuf_len )
+ memcpy( rbuf, rbuf+len, rbuf_len );
+ assert( 0 <= rbuf_len );
+ }
+ if (f_local == 0 && f_hold_session) {
+ debug ("closing local port without disconnecting from remote\n");
+ f_remote = 0;
+ shutdown (local_out, 2);
+ close (local_out);
+ break;
+ }
+ }
+
+ return close_reason;