static int handle_gotdata(struct handle *h, void *data, int len) { Handle_Socket ps = (Handle_Socket) handle_get_privdata(h); if (len < 0) { plug_closing(ps->plug, "Read error from handle", 0, 0); return 0; } else if (len == 0) { plug_closing(ps->plug, NULL, 0, 0); return 0; } else { assert(ps->frozen != FROZEN && ps->frozen != THAWING); if (ps->frozen == FREEZING) { /* * If we've received data while this socket is supposed to * be frozen (because the read winhandl.c started before * sk_set_frozen was called has now returned) then buffer * the data for when we unfreeze. */ bufchain_add(&ps->inputdata, data, len); ps->frozen = FROZEN; /* * And return a very large backlog, to prevent further * data arriving from winhandl until we unfreeze. */ return INT_MAX; } else { plug_receive(ps->plug, 0, data, len); return 0; } } }
int handle_write(struct handle *h, const void *data, int len) { assert(h->type == HT_OUTPUT); assert(h->u.o.outgoingeof == EOF_NO); bufchain_add(&h->u.o.queued_data, data, len); handle_try_output(&h->u.o); return bufchain_size(&h->u.o.queued_data); }
int from_backend(void *frontend_handle, int is_stderr, const char *data, int len) { int osize, esize; if (is_stderr) { bufchain_add(&stderr_data, data, len); try_output(1); } else { bufchain_add(&stdout_data, data, len); try_output(0); } osize = bufchain_size(&stdout_data); esize = bufchain_size(&stderr_data); return osize + esize; }
static int sk_proxy_write(Socket s, const char *data, int len) { Proxy_Socket ps = (Proxy_Socket) s; if (ps->state != PROXY_STATE_ACTIVE) { bufchain_add(&ps->pending_output_data, data, len); return bufchain_size(&ps->pending_output_data); } return sk_write(ps->sub_socket, data, len); }
static int sk_localproxy_write (Socket s, const char *data, int len) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; bufchain_add(&ps->pending_output_data, data, len); localproxy_try_send(ps); return bufchain_size(&ps->pending_output_data); }
static int sk_proxy_write (Socket s, const void *data, int len) { ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_add(&ps->pending_output_data, data, len); return bufchain_size(&ps->pending_output_data); } return sk_write(ps->sub_socket, data, len); }
static size_t sk_proxy_write (Socket *s, const void *data, size_t len) { ProxySocket *ps = container_of(s, ProxySocket, sock); if (ps->state != PROXY_STATE_ACTIVE) { bufchain_add(&ps->pending_output_data, data, len); return bufchain_size(&ps->pending_output_data); } return sk_write(ps->sub_socket, data, len); }
/* * Called to send data down the serial connection. */ static int serial_send(void *handle, const char *buf, int len) { Serial serial = (Serial) handle; if (serial->fd < 0) return 0; bufchain_add(&serial->output_data, buf, len); serial_try_write(serial); return bufchain_size(&serial->output_data); }
static int plug_proxy_receive(Plug p, int urgent, byte *data, int len) { Proxy_Plug pp = (Proxy_Plug) p; Proxy_Socket ps = pp->proxy_socket; if (ps->state != PROXY_STATE_ACTIVE) { /* we will lose the urgentness of this data, but since most, * if not all, of this data will be consumed by the negotiation * process, hopefully it won't affect the protocol above us */ bufchain_add(&ps->pending_input_data, data, len); ps->receive_urgent = urgent; ps->receive_data = data; ps->receive_len = len; return ps->negotiate(ps, PROXY_CHANGE_RECEIVE); } return plug_receive(ps->plug, urgent, data, len); }
/* * Internal wrapper function which must be called for _all_ output * to the log file. It takes care of opening the log file if it * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ static void logwrite(struct LogContext *ctx, void *data, int len) { /* * In state L_CLOSED, we call logfopen, which will set the state * to one of L_OPENING, L_OPEN or L_ERROR. Hence we process all of * those three _after_ processing L_CLOSED. */ if (ctx->state == L_CLOSED) logfopen(ctx); if (ctx->state == L_OPENING) { bufchain_add(&ctx->queue, data, len); } else if (ctx->state == L_OPEN) { assert(ctx->lgfp); fwrite(data, 1, len, ctx->lgfp); } /* else L_ERROR, so ignore the write */ }
static void plug_proxy_receive (Plug p, int urgent, char *data, int len) { ProxySocket *ps = FROMFIELD(p, ProxySocket, plugvt); if (ps->state != PROXY_STATE_ACTIVE) { /* we will lose the urgentness of this data, but since most, * if not all, of this data will be consumed by the negotiation * process, hopefully it won't affect the protocol above us */ bufchain_add(&ps->pending_input_data, data, len); ps->receive_urgent = urgent; ps->receive_data = data; ps->receive_len = len; ps->negotiate(ps, PROXY_CHANGE_RECEIVE); } else { plug_receive(ps->plug, urgent, data, len); } }
/* * Internal wrapper function which must be called for _all_ output * to the log file. It takes care of opening the log file if it * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ static void logwrite(struct LogContext *ctx, void *data, int len) { /* * In state L_CLOSED, we call logfopen, which will set the state * to one of L_OPENING, L_OPEN or L_ERROR. Hence we process all of * those three _after_ processing L_CLOSED. */ #ifdef PERSOPORT if( timestamp_newfile ) { if (ctx->state == L_OPEN) { logfclose(ctx); } timestamp_newfile = 0 ; } #endif if (ctx->state == L_CLOSED) logfopen(ctx); if (ctx->state == L_OPENING) { bufchain_add(&ctx->queue, data, len); } else if (ctx->state == L_OPEN) { assert(ctx->lgfp); #ifdef PERSOPORT if( !get_param("PUTTY") ) { if( timestamp_newline ) { log_writetimestamp( ctx ) ; timestamp_newline = 0 ; } char * c = (char*)(data+len-1) ; if( c[0]=='\n' ) timestamp_newline = 1 ; } #endif if (fwrite(data, 1, len, ctx->lgfp) < (size_t)len) { logfclose(ctx); ctx->state = L_ERROR; /* Log state is L_ERROR so this won't cause a loop */ logevent(ctx->frontend, "Disabled writing session log due to error while writing"); } } /* else L_ERROR, so ignore the write */ }
/* * Internal wrapper function which must be called for _all_ output * to the log file. It takes care of opening the log file if it * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ static void logwrite(struct LogContext *ctx, void *data, int len) { /* * In state L_CLOSED, we call logfopen, which will set the state * to one of L_OPENING, L_OPEN or L_ERROR. Hence we process all of * those three _after_ processing L_CLOSED. */ if (ctx->state == L_CLOSED) logfopen(ctx); if (ctx->state == L_OPENING) { bufchain_add(&ctx->queue, data, len); } else if (ctx->state == L_OPEN) { assert(ctx->lgfp); if (fwrite(data, 1, len, ctx->lgfp) < len) { logfclose(ctx); ctx->state = L_ERROR; /* Log state is L_ERROR so this won't cause a loop */ logevent(ctx->frontend, "Disabled writing session log due to error while writing"); } } /* else L_ERROR, so ignore the write */ }
int main(int argc, char **argv) { int masterr, masterw, slaver, slavew, pid; char ptyname[FILENAME_MAX]; bufchain tochild, tostdout; int tochild_active, tostdout_active, fromstdin_active, fromchild_active; int exitcode = -1; pid_t childpid = -1; --argc, ++argv; /* point at argument after "--" */ /* * Allocate the pipe for transmitting signals back to the * top-level select loop. */ if (pipe(signalpipe) < 0) { perror("pipe"); return 1; } /* * Now that pipe exists, we can set up the SIGCHLD handler to * write to one end of it. We needn't already know details like * which child pid we're waiting for, because we don't need that * until we respond to reading the far end of the pipe in the * main select loop. */ signal(SIGCHLD, sigchld); /* * Allocate the pty or pipes. */ masterr = pty_get(ptyname); masterw = dup(masterr); slaver = open(ptyname, O_RDWR); slavew = dup(slaver); if (slaver < 0) { perror("slave pty: open"); return 1; } bufchain_init(&tochild); bufchain_init(&tostdout); tochild_active = tostdout_active = TRUE; fromchild_active = fromstdin_active = TRUE; /* * Fork and execute the command. */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid == 0) { int i; /* * We are the child. */ close(masterr); close(masterw); fcntl(slaver, F_SETFD, 0); /* don't close on exec */ fcntl(slavew, F_SETFD, 0); /* don't close on exec */ close(0); dup2(slaver, 0); close(1); dup2(slavew, 1); int fd; close(2); dup2(slavew, 2); setsid(); setpgid(0, 0); tcsetpgrp(0, getpgrp()); if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY); close(fd); } ioctl(slavew, TIOCSCTTY); /* Close everything _else_, for tidiness. */ for (i = 3; i < 1024; i++) close(i); if (argc > 0) { execvp(argv[0], argv); /* assumes argv has trailing NULL */ } else { execl(getenv("SHELL"), getenv("SHELL"), NULL); } /* * If we're here, exec has gone badly foom. */ perror("exec"); exit(127); } /* * Now we're the parent. Close the slave fds and start copying * stuff back and forth. */ close(slaver); close(slavew); childpid = pid; tcgetattr(0, &oldattrs); newattrs = oldattrs; newattrs.c_iflag &= ~(IXON | IXOFF | ICRNL | INLCR); newattrs.c_oflag &= ~(ONLCR | OCRNL); newattrs.c_lflag &= ~(ISIG | ICANON | ECHO); atexit(attrsonexit); tcsetattr(0, TCSADRAIN, &newattrs); while (1) { fd_set rset, wset; char buf[65536]; int maxfd, ret; FD_ZERO(&rset); FD_ZERO(&wset); maxfd = 0; FD_SET(signalpipe[0], &rset); maxfd = max(signalpipe[0]+1, maxfd); if (tochild_active && bufchain_size(&tochild)) { FD_SET(masterw, &wset); maxfd = max(masterw+1, maxfd); } if (tostdout_active && bufchain_size(&tostdout)) { FD_SET(1, &wset); maxfd = max(1+1, maxfd); } if (fromstdin_active && bufchain_size(&tochild) < LOCALBUF_LIMIT) { FD_SET(0, &rset); maxfd = max(0+1, maxfd); } if (fromchild_active && bufchain_size(&tostdout) < LOCALBUF_LIMIT) { FD_SET(masterr, &rset); maxfd = max(masterr+1, maxfd); } do { ret = select(maxfd, &rset, &wset, NULL, NULL); } while (ret < 0 && (errno == EINTR || errno == EAGAIN)); if (ret < 0) { perror("select"); return 1; } if (FD_ISSET(masterr, &rset)) { if (FD_ISSET(masterr, &rset)) { ret = read(masterr, buf, sizeof(buf)); if (ret <= 0) { /* * EIO from a pty master just means end of * file, annoyingly. Why can't it report * ordinary EOF? */ if (errno == EIO) ret = 0; if (ret < 0) { perror("child process: read"); } close(masterr); fromchild_active = FALSE; ret = 0; } } else ret = 0; if (ret) { bufchain_add(&tostdout, buf, ret); } } if (FD_ISSET(0, &rset)) { if (FD_ISSET(0, &rset)) { ret = read(0, buf, sizeof(buf)); if (ret <= 0) { if (ret < 0) { perror("stdin: read"); } close(0); fromstdin_active = FALSE; ret = 0; } } else ret = 0; if (ret) { bufchain_add(&tochild, buf, ret); } } if (FD_ISSET(1, &wset)) { void *data; int len, ret; bufchain_prefix(&tostdout, &data, &len); if ((ret = write(1, data, len)) < 0) { perror("stdout: write"); close(1); close(masterr); tostdout_active = fromchild_active = FALSE; } else bufchain_consume(&tostdout, ret); } if (FD_ISSET(masterw, &wset)) { void *data; int len; bufchain_prefix(&tochild, &data, &len); if ((ret = write(masterw, data, len)) < 0) { perror("child process: write"); close(0); close(masterw); tochild_active = fromstdin_active = FALSE; } else bufchain_consume(&tochild, ret); } if (FD_ISSET(signalpipe[0], &rset)) { ret = read(signalpipe[0], buf, 1); if (ret == 1 && buf[0] == 'C') { int pid, code; pid = wait(&code); /* reap the exit code */ if (pid == childpid) exitcode = code; } } /* * If there can be no further data from a direction (the * input fd has been closed and the buffered data is used * up) but its output fd is still open, close it. */ if (!fromstdin_active && !bufchain_size(&tochild) && tochild_active) { tochild_active = FALSE; close(masterw); } if (!fromchild_active && !bufchain_size(&tostdout) && tostdout_active){ tostdout_active = FALSE; close(1); } /* * Termination condition with pipes is that there's still * data flowing in at least one direction. * * Termination condition for a pty-based run is that the * child process hasn't yet terminated and/or there is * still buffered data to send. */ if (exitcode < 0) /* process is still active */; else if (tochild_active && bufchain_size(&tochild)) /* data still to be sent to child's children */; else if (tostdout_active && bufchain_size(&tostdout)) /* data still to be sent to stdout */; else break; /* terminate */ } close(masterw); close(masterr); if (exitcode < 0) { int pid, code; pid = wait(&code); exitcode = code; } return (WIFEXITED(exitcode) ? WEXITSTATUS(exitcode) : 128 | WTERMSIG(exitcode)); }