123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- /*
- * fd-socket.c: implementation of Socket that just talks to two
- * existing input and output file descriptors.
- */
- #include <stdio.h>
- #include <assert.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "tree234.h"
- #include "putty.h"
- #include "network.h"
- typedef struct FdSocket {
- int outfd, infd, inerrfd; /* >= 0 if socket is open */
- DeferredSocketOpener *opener; /* non-NULL if not opened yet */
- bufchain pending_output_data;
- bufchain pending_input_data;
- ProxyStderrBuf psb;
- enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
- int pending_error;
- SockAddr *addr;
- int port;
- Plug *plug;
- Socket sock;
- } FdSocket;
- static void fdsocket_select_result_input(int fd, int event);
- static void fdsocket_select_result_output(int fd, int event);
- static void fdsocket_select_result_input_error(int fd, int event);
- /*
- * Trees to look up the fds in.
- */
- static tree234 *fdsocket_by_outfd;
- static tree234 *fdsocket_by_infd;
- static tree234 *fdsocket_by_inerrfd;
- static int fdsocket_infd_cmp(void *av, void *bv)
- {
- FdSocket *a = (FdSocket *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a->infd < b->infd)
- return -1;
- if (a->infd > b->infd)
- return +1;
- return 0;
- }
- static int fdsocket_infd_find(void *av, void *bv)
- {
- int a = *(int *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a < b->infd)
- return -1;
- if (a > b->infd)
- return +1;
- return 0;
- }
- static int fdsocket_inerrfd_cmp(void *av, void *bv)
- {
- FdSocket *a = (FdSocket *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a->inerrfd < b->inerrfd)
- return -1;
- if (a->inerrfd > b->inerrfd)
- return +1;
- return 0;
- }
- static int fdsocket_inerrfd_find(void *av, void *bv)
- {
- int a = *(int *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a < b->inerrfd)
- return -1;
- if (a > b->inerrfd)
- return +1;
- return 0;
- }
- static int fdsocket_outfd_cmp(void *av, void *bv)
- {
- FdSocket *a = (FdSocket *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a->outfd < b->outfd)
- return -1;
- if (a->outfd > b->outfd)
- return +1;
- return 0;
- }
- static int fdsocket_outfd_find(void *av, void *bv)
- {
- int a = *(int *)av;
- FdSocket *b = (FdSocket *)bv;
- if (a < b->outfd)
- return -1;
- if (a > b->outfd)
- return +1;
- return 0;
- }
- static Plug *fdsocket_plug(Socket *s, Plug *p)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- Plug *ret = fds->plug;
- if (p)
- fds->plug = p;
- return ret;
- }
- static void fdsocket_close(Socket *s)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- if (fds->opener)
- deferred_socket_opener_free(fds->opener);
- if (fds->outfd >= 0) {
- del234(fdsocket_by_outfd, fds);
- uxsel_del(fds->outfd);
- close(fds->outfd);
- }
- if (fds->infd >= 0) {
- del234(fdsocket_by_infd, fds);
- uxsel_del(fds->infd);
- close(fds->infd);
- }
- if (fds->inerrfd >= 0) {
- del234(fdsocket_by_inerrfd, fds);
- uxsel_del(fds->inerrfd);
- close(fds->inerrfd);
- }
- bufchain_clear(&fds->pending_input_data);
- bufchain_clear(&fds->pending_output_data);
- if (fds->addr)
- sk_addr_free(fds->addr);
- delete_callbacks_for_context(fds);
- sfree(fds);
- }
- static void fdsocket_error_callback(void *vs)
- {
- FdSocket *fds = (FdSocket *)vs;
- /*
- * Just in case other socket work has caused this socket to vanish
- * or become somehow non-erroneous before this callback arrived...
- */
- if (!fds->pending_error)
- return;
- /*
- * An error has occurred on this socket. Pass it to the plug.
- */
- plug_closing_errno(fds->plug, fds->pending_error);
- }
- static int fdsocket_try_send(FdSocket *fds)
- {
- int sent = 0;
- if (fds->opener)
- return sent;
- while (bufchain_size(&fds->pending_output_data) > 0) {
- ssize_t ret;
- ptrlen data = bufchain_prefix(&fds->pending_output_data);
- ret = write(fds->outfd, data.ptr, data.len);
- noise_ultralight(NOISE_SOURCE_IOID, ret);
- if (ret < 0 && errno != EWOULDBLOCK) {
- if (!fds->pending_error) {
- fds->pending_error = errno;
- queue_toplevel_callback(fdsocket_error_callback, fds);
- }
- return 0;
- } else if (ret <= 0) {
- break;
- } else {
- bufchain_consume(&fds->pending_output_data, ret);
- sent += ret;
- }
- }
- if (fds->outgoingeof == EOF_PENDING) {
- del234(fdsocket_by_outfd, fds);
- close(fds->outfd);
- uxsel_del(fds->outfd);
- fds->outfd = -1;
- fds->outgoingeof = EOF_SENT;
- }
- if (bufchain_size(&fds->pending_output_data) == 0)
- uxsel_del(fds->outfd);
- else
- uxsel_set(fds->outfd, SELECT_W, fdsocket_select_result_output);
- return sent;
- }
- static size_t fdsocket_write(Socket *s, const void *data, size_t len)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- assert(fds->outgoingeof == EOF_NO);
- bufchain_add(&fds->pending_output_data, data, len);
- fdsocket_try_send(fds);
- return bufchain_size(&fds->pending_output_data);
- }
- static size_t fdsocket_write_oob(Socket *s, const void *data, size_t len)
- {
- /*
- * oob data is treated as inband; nasty, but nothing really
- * better we can do
- */
- return fdsocket_write(s, data, len);
- }
- static void fdsocket_write_eof(Socket *s)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- assert(fds->outgoingeof == EOF_NO);
- fds->outgoingeof = EOF_PENDING;
- fdsocket_try_send(fds);
- }
- static void fdsocket_set_frozen(Socket *s, bool is_frozen)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- if (fds->infd < 0)
- return;
- if (is_frozen)
- uxsel_del(fds->infd);
- else
- uxsel_set(fds->infd, SELECT_R, fdsocket_select_result_input);
- }
- static const char *fdsocket_socket_error(Socket *s)
- {
- return NULL;
- }
- static void fdsocket_select_result_input(int fd, int event)
- {
- FdSocket *fds;
- char buf[20480];
- int retd;
- if (!(fds = find234(fdsocket_by_infd, &fd, fdsocket_infd_find)))
- return;
- retd = read(fds->infd, buf, sizeof(buf));
- if (retd > 0) {
- plug_receive(fds->plug, 0, buf, retd);
- } else {
- del234(fdsocket_by_infd, fds);
- uxsel_del(fds->infd);
- close(fds->infd);
- fds->infd = -1;
- if (retd < 0) {
- plug_closing_errno(fds->plug, errno);
- } else {
- plug_closing_normal(fds->plug);
- }
- }
- }
- static void fdsocket_select_result_output(int fd, int event)
- {
- FdSocket *fds;
- if (!(fds = find234(fdsocket_by_outfd, &fd, fdsocket_outfd_find)))
- return;
- if (fdsocket_try_send(fds))
- plug_sent(fds->plug, bufchain_size(&fds->pending_output_data));
- }
- static void fdsocket_select_result_input_error(int fd, int event)
- {
- FdSocket *fds;
- char buf[20480];
- int retd;
- if (!(fds = find234(fdsocket_by_inerrfd, &fd, fdsocket_inerrfd_find)))
- return;
- retd = read(fd, buf, sizeof(buf));
- if (retd > 0) {
- log_proxy_stderr(fds->plug, &fds->sock, &fds->psb, buf, retd);
- } else {
- del234(fdsocket_by_inerrfd, fds);
- uxsel_del(fds->inerrfd);
- close(fds->inerrfd);
- fds->inerrfd = -1;
- }
- }
- static const SocketVtable FdSocket_sockvt = {
- .plug = fdsocket_plug,
- .close = fdsocket_close,
- .write = fdsocket_write,
- .write_oob = fdsocket_write_oob,
- .write_eof = fdsocket_write_eof,
- .set_frozen = fdsocket_set_frozen,
- .socket_error = fdsocket_socket_error,
- .endpoint_info = nullsock_endpoint_info,
- };
- static void fdsocket_connect_success_callback(void *ctx)
- {
- FdSocket *fds = (FdSocket *)ctx;
- plug_log(fds->plug, &fds->sock, PLUGLOG_CONNECT_SUCCESS,
- fds->addr, fds->port, NULL, 0);
- }
- void setup_fd_socket(Socket *s, int infd, int outfd, int inerrfd)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- assert(fds->sock.vt == &FdSocket_sockvt);
- if (fds->opener) {
- deferred_socket_opener_free(fds->opener);
- fds->opener = NULL;
- }
- fds->infd = infd;
- fds->outfd = outfd;
- fds->inerrfd = inerrfd;
- if (fds->outfd >= 0) {
- if (!fdsocket_by_outfd)
- fdsocket_by_outfd = newtree234(fdsocket_outfd_cmp);
- add234(fdsocket_by_outfd, fds);
- }
- if (fds->infd >= 0) {
- if (!fdsocket_by_infd)
- fdsocket_by_infd = newtree234(fdsocket_infd_cmp);
- add234(fdsocket_by_infd, fds);
- uxsel_set(fds->infd, SELECT_R, fdsocket_select_result_input);
- }
- if (fds->inerrfd >= 0) {
- assert(fds->inerrfd != fds->infd);
- if (!fdsocket_by_inerrfd)
- fdsocket_by_inerrfd = newtree234(fdsocket_inerrfd_cmp);
- add234(fdsocket_by_inerrfd, fds);
- uxsel_set(fds->inerrfd, SELECT_R, fdsocket_select_result_input_error);
- }
- queue_toplevel_callback(fdsocket_connect_success_callback, fds);
- }
- void fd_socket_set_psb_prefix(Socket *s, const char *prefix)
- {
- FdSocket *fds = container_of(s, FdSocket, sock);
- assert(fds->sock.vt == &FdSocket_sockvt);
- psb_set_prefix(&fds->psb, prefix);
- }
- static FdSocket *make_fd_socket_internal(SockAddr *addr, int port, Plug *plug)
- {
- FdSocket *fds;
- fds = snew(FdSocket);
- fds->sock.vt = &FdSocket_sockvt;
- fds->addr = addr;
- fds->port = port;
- fds->plug = plug;
- fds->outgoingeof = EOF_NO;
- fds->pending_error = 0;
- fds->opener = NULL;
- fds->infd = fds->outfd = fds->inerrfd = -1;
- bufchain_init(&fds->pending_input_data);
- bufchain_init(&fds->pending_output_data);
- psb_init(&fds->psb);
- return fds;
- }
- Socket *make_fd_socket(int infd, int outfd, int inerrfd,
- SockAddr *addr, int port, Plug *plug)
- {
- FdSocket *fds = make_fd_socket_internal(addr, port, plug);
- setup_fd_socket(&fds->sock, infd, outfd, inerrfd);
- return &fds->sock;
- }
- Socket *make_deferred_fd_socket(DeferredSocketOpener *opener,
- SockAddr *addr, int port, Plug *plug)
- {
- FdSocket *fds = make_fd_socket_internal(addr, port, plug);
- fds->opener = opener;
- return &fds->sock;
- }
|