X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/32874aeac8dacbca26663777b39a79efc5d8dc4b..5f2e19fcf977f48387d918948aa3ed66748208b0:/winnet.c diff --git a/winnet.c b/winnet.c index 238730c4..bcb93481 100644 --- a/winnet.c +++ b/winnet.c @@ -65,6 +65,7 @@ struct Socket_tag { void *private_ptr; struct buffer *head, *tail; int writable; + int frozen; /* this tells the write stuff not to even bother trying to send at this point */ int sending_oob; int oobinline; }; @@ -87,11 +88,6 @@ struct SockAddr_tag { #ifdef IPV6 struct addrinfo *ai; /* Address IPv6 style. */ #endif - /* - * We need to have this lengthy enough to hold *any* hostname - * (including IPv6 reverse...) - */ - char realhost[8192]; }; struct buffer { @@ -213,11 +209,12 @@ SockAddr sk_namelookup(char *host, char **canonicalname) SockAddr ret = smalloc(sizeof(struct SockAddr_tag)); unsigned long a; struct hostent *h = NULL; + char realhost[8192]; /* Clear the structure and default to IPv4. */ memset(ret, 0, sizeof(struct SockAddr_tag)); ret->family = 0; /* We set this one when we have resolved the host. */ - *canonicalname = ret->realhost; /* This makes sure we always have a hostname to return. */ + *realhost = '\0'; if ((a = inet_addr(host)) == (unsigned long) INADDR_NONE) { #ifdef IPV6 @@ -255,7 +252,7 @@ SockAddr sk_namelookup(char *host, char **canonicalname) */ if (ret->family == 0) { /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */ - if (h = gethostbyname(host)) + if ( (h = gethostbyname(host)) ) ret->family = AF_INET; } } @@ -312,10 +309,9 @@ SockAddr sk_namelookup(char *host, char **canonicalname) ((struct sockaddr *) ret->ai->ai_addr, ret->family == AF_INET ? sizeof(SOCKADDR_IN) : - sizeof(SOCKADDR_IN6), ret->realhost, - sizeof(ret->realhost), NULL, 0, 0) != 0) { - strncpy(ret->realhost, host, - sizeof(ret->realhost)); + sizeof(SOCKADDR_IN6), realhost, + sizeof(realhost), NULL, 0, 0) != 0) { + strncpy(realhost, host, sizeof(realhost)); } } } @@ -325,7 +321,7 @@ SockAddr sk_namelookup(char *host, char **canonicalname) { memcpy(&a, h->h_addr, sizeof(a)); /* This way we are always sure the h->h_name is valid :) */ - strncpy(ret->realhost, h->h_name, sizeof(ret->realhost)); + strncpy(realhost, h->h_name, sizeof(realhost)); } } #ifdef IPV6 @@ -337,9 +333,12 @@ SockAddr sk_namelookup(char *host, char **canonicalname) * success return from inet_addr. */ ret->family = AF_INET; - *canonicalname = host; + strncpy(realhost, host, sizeof(realhost)); } ret->address = ntohl(a); + realhost[lenof(realhost)-1] = '\0'; + *canonicalname = smalloc(1+strlen(realhost)); + strcpy(*canonicalname, realhost); return ret; } @@ -365,10 +364,62 @@ static void sk_tcp_flush(Socket s) */ } -void sk_tcp_close(Socket s); -void sk_tcp_write(Socket s, char *data, int len); -void sk_tcp_write_oob(Socket s, char *data, int len); -char *sk_tcp_socket_error(Socket s); +static void sk_tcp_close(Socket s); +static void sk_tcp_write(Socket s, char *data, int len); +static void sk_tcp_write_oob(Socket s, char *data, int len); +static char *sk_tcp_socket_error(Socket s); + +extern char *do_select(SOCKET skt, int startup); + +Socket sk_register(void *sock, Plug plug) +{ + static struct socket_function_table fn_table = { + sk_tcp_plug, + sk_tcp_close, + sk_tcp_write, + sk_tcp_write_oob, + sk_tcp_flush, + sk_tcp_socket_error + }; + + DWORD err; + char *errstr; + Actual_Socket ret; + + /* + * Create Socket structure. + */ + ret = smalloc(sizeof(struct Socket_tag)); + ret->fn = &fn_table; + ret->error = NULL; + ret->plug = plug; + ret->head = ret->tail = NULL; + ret->writable = 1; /* to start with */ + ret->sending_oob = 0; + ret->frozen = 1; + + ret->s = (SOCKET)sock; + + if (ret->s == INVALID_SOCKET) { + err = WSAGetLastError(); + ret->error = winsock_error_string(err); + return (Socket) ret; + } + + ret->oobinline = 0; + + /* Set up a select mechanism. This could be an AsyncSelect on a + * window, or an EventSelect on an event object. */ + errstr = do_select(ret->s, 1); + if (errstr) { + ret->error = errstr; + return (Socket) ret; + } + + add234(sktree, ret); + + return (Socket) ret; +} Socket sk_new(SockAddr addr, int port, int privport, int oobinline, Plug plug) @@ -390,7 +441,6 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, DWORD err; char *errstr; Actual_Socket ret; - extern char *do_select(SOCKET skt, int startup); short localport; /* @@ -403,6 +453,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, ret->head = ret->tail = NULL; ret->writable = 1; /* to start with */ ret->sending_oob = 0; + ret->frozen = 0; /* * Open socket. @@ -521,6 +572,111 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, return (Socket) ret; } +Socket sk_newlistenner(int port, Plug plug) +{ + static struct socket_function_table fn_table = { + sk_tcp_plug, + sk_tcp_close, + sk_tcp_write, + sk_tcp_write_oob, + sk_tcp_flush, + sk_tcp_socket_error + }; + + SOCKET s; +#ifdef IPV6 + SOCKADDR_IN6 a6; +#endif + SOCKADDR_IN a; + DWORD err; + char *errstr; + Actual_Socket ret; + int retcode; + int on = 1; + + /* + * Create Socket structure. + */ + ret = smalloc(sizeof(struct Socket_tag)); + ret->fn = &fn_table; + ret->error = NULL; + ret->plug = plug; + ret->head = ret->tail = NULL; + ret->writable = 0; /* to start with */ + ret->sending_oob = 0; + ret->frozen = 0; + + /* + * Open socket. + */ + s = socket(AF_INET, SOCK_STREAM, 0); + ret->s = s; + + if (s == INVALID_SOCKET) { + err = WSAGetLastError(); + ret->error = winsock_error_string(err); + return (Socket) ret; + } + + ret->oobinline = 0; + + + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); + + +#ifdef IPV6 + if (addr->family == AF_INET6) { + memset(&a6, 0, sizeof(a6)); + a6.sin6_family = AF_INET6; +/*a6.sin6_addr = in6addr_any; *//* == 0 */ + a6.sin6_port = htons(port); + } else +#endif + { + a.sin_family = AF_INET; + a.sin_addr.s_addr = htonl(INADDR_ANY); + a.sin_port = htons((short)port); + } +#ifdef IPV6 + retcode = bind(s, (addr->family == AF_INET6 ? + (struct sockaddr *) &a6 : + (struct sockaddr *) &a), + (addr->family == + AF_INET6 ? sizeof(a6) : sizeof(a))); +#else + retcode = bind(s, (struct sockaddr *) &a, sizeof(a)); +#endif + if (retcode != SOCKET_ERROR) { + err = 0; + } else { + err = WSAGetLastError(); + } + + if (err) { + ret->error = winsock_error_string(err); + return (Socket) ret; + } + + + if (listen(s, SOMAXCONN) == SOCKET_ERROR) { + closesocket(s); + ret->error = winsock_error_string(err); + return (Socket) ret; + } + + /* Set up a select mechanism. This could be an AsyncSelect on a + * window, or an EventSelect on an event object. */ + errstr = do_select(s, 1); + if (errstr) { + ret->error = errstr; + return (Socket) ret; + } + + add234(sktree, ret); + + return (Socket) ret; +} + static void sk_tcp_close(Socket sock) { extern char *do_select(SOCKET skt, int startup); @@ -538,6 +694,7 @@ static void sk_tcp_close(Socket sock) */ void try_send(Actual_Socket s) { + if (s->frozen) return; while (s->head) { int nsent; DWORD err; @@ -696,6 +853,11 @@ int select_result(WPARAM wParam, LPARAM lParam) switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: + + /* In the case the socket is still frozen, we don't even bother */ + if (s->frozen) + break; + /* * We have received data on the socket. For an oobinline * socket, this might be data _before_ an urgent pointer, @@ -771,6 +933,26 @@ int select_result(WPARAM wParam, LPARAM lParam) } } while (ret > 0); return open; + case FD_ACCEPT: + { + struct sockaddr isa; + int addrlen = sizeof(struct sockaddr); + SOCKET t; /* socket of connection */ + + memset(&isa, 0, sizeof(struct sockaddr)); + err = 0; + t = accept(s->s,&isa,&addrlen); + if (t == INVALID_SOCKET) + { + err = WSAGetLastError(); + if (err == WSATRY_AGAIN) + break; + } + + if (plug_accepting(s->plug, &isa, (void*)t)) { + closesocket(t); // denied or error + } + } } return 1; @@ -807,6 +989,16 @@ static char *sk_tcp_socket_error(Socket sock) return s->error; } +void sk_set_frozen(Socket sock, int is_frozen) +{ + Actual_Socket s = (Actual_Socket) sock; + s->frozen = is_frozen; + if (!is_frozen) { + char c; + recv(s->s, &c, 1, MSG_PEEK); + } +} + /* * For Plink: enumerate all sockets currently active. */