winnet.c
来自「大名鼎鼎的远程登录软件putty的Symbian版源码」· C语言 代码 · 共 1,373 行 · 第 1/3 页
C
1,373 行
int got_addr = 0; a.sin_family = AF_INET; /* * Bind to source address. First try an explicitly * specified one... */ if (srcaddr) { a.sin_addr.s_addr = p_inet_addr(srcaddr); if (a.sin_addr.s_addr != INADDR_NONE) { /* Override localhost_only with specified listen addr. */ ret->localhost_only = ipv4_is_loopback(a.sin_addr); got_addr = 1; } } /* * ... and failing that, go with one of the standard ones. */ if (!got_addr) { if (local_host_only) a.sin_addr.s_addr = p_htonl(INADDR_LOOPBACK); else a.sin_addr.s_addr = p_htonl(INADDR_ANY); } a.sin_port = p_htons((short)port); }#ifdef IPV6 retcode = p_bind(s, (addr->family == AF_INET6 ? (struct sockaddr *) &a6 : (struct sockaddr *) &a), (addr->family == AF_INET6 ? sizeof(a6) : sizeof(a)));#else retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));#endif if (retcode != SOCKET_ERROR) { err = 0; } else { err = p_WSAGetLastError(); } if (err) { ret->error = winsock_error_string(err); return (Socket) ret; } if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) { p_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); Actual_Socket s = (Actual_Socket) sock; del234(sktree, s); do_select(s->s, 0); p_closesocket(s->s); sfree(s);}/* * The function which tries to send on a socket once it's deemed * writable. */void try_send(Actual_Socket s){ while (s->sending_oob || bufchain_size(&s->output_data) > 0) { int nsent; DWORD err; void *data; int len, urgentflag; if (s->sending_oob) { urgentflag = MSG_OOB; len = s->sending_oob; data = &s->oobdata; } else { urgentflag = 0; bufchain_prefix(&s->output_data, &data, &len); } nsent = p_send(s->s, data, len, urgentflag); noise_ultralight(nsent); if (nsent <= 0) { err = (nsent < 0 ? p_WSAGetLastError() : 0); if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) { /* * Perfectly normal: we've sent all we can for the moment. * * (Some WinSock send() implementations can return * <0 but leave no sensible error indication - * WSAGetLastError() is called but returns zero or * a small number - so we check that case and treat * it just like WSAEWOULDBLOCK.) */ s->writable = FALSE; return; } else if (nsent == 0 || err == WSAECONNABORTED || err == WSAECONNRESET) { /* * If send() returns CONNABORTED or CONNRESET, we * unfortunately can't just call plug_closing(), * because it's quite likely that we're currently * _in_ a call from the code we'd be calling back * to, so we'd have to make half the SSH code * reentrant. Instead we flag a pending error on * the socket, to be dealt with (by calling * plug_closing()) at some suitable future moment. */ s->pending_error = err; return; } else { /* We're inside the Windows frontend here, so we know * that the frontend handle is unnecessary. */ logevent(NULL, winsock_error_string(err)); fatalbox("%s", winsock_error_string(err)); } } else { if (s->sending_oob) { if (nsent < len) { memmove(s->oobdata, s->oobdata+nsent, len-nsent); s->sending_oob = len - nsent; } else { s->sending_oob = 0; } } else { bufchain_consume(&s->output_data, nsent); } } }}static int sk_tcp_write(Socket sock, const char *buf, int len){ Actual_Socket s = (Actual_Socket) sock; /* * Add the data to the buffer list on the socket. */ bufchain_add(&s->output_data, buf, len); /* * Now try sending from the start of the buffer list. */ if (s->writable) try_send(s); return bufchain_size(&s->output_data);}static int sk_tcp_write_oob(Socket sock, const char *buf, int len){ Actual_Socket s = (Actual_Socket) sock; /* * Replace the buffer list on the socket with the data. */ bufchain_clear(&s->output_data); assert(len <= sizeof(s->oobdata)); memcpy(s->oobdata, buf, len); s->sending_oob = len; /* * Now try sending from the start of the buffer list. */ if (s->writable) try_send(s); return s->sending_oob;}int select_result(WPARAM wParam, LPARAM lParam){ int ret, open; DWORD err; char buf[20480]; /* nice big buffer for plenty of speed */ Actual_Socket s; u_long atmark; /* wParam is the socket itself */ if (wParam == 0) return 1; /* boggle */ s = find234(sktree, (void *) wParam, cmpforsearch); if (!s) return 1; /* boggle */ if ((err = WSAGETSELECTERROR(lParam)) != 0) { /* * An error has occurred on this socket. Pass it to the * plug. */ return plug_closing(s->plug, winsock_error_string(err), err, 0); } noise_ultralight(lParam); switch (WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: s->connected = s->writable = 1; break; case FD_READ: /* In the case the socket is still frozen, we don't even bother */ if (s->frozen) { s->frozen_readable = 1; break; } /* * We have received data on the socket. For an oobinline * socket, this might be data _before_ an urgent pointer, * in which case we send it to the back end with type==1 * (data prior to urgent). */ if (s->oobinline) { atmark = 1; p_ioctlsocket(s->s, SIOCATMARK, &atmark); /* * Avoid checking the return value from ioctlsocket(), * on the grounds that some WinSock wrappers don't * support it. If it does nothing, we get atmark==1, * which is equivalent to `no OOB pending', so the * effect will be to non-OOB-ify any OOB data. */ } else atmark = 1; ret = p_recv(s->s, buf, sizeof(buf), 0); noise_ultralight(ret); if (ret < 0) { err = p_WSAGetLastError(); if (err == WSAEWOULDBLOCK) { break; } } if (ret < 0) { return plug_closing(s->plug, winsock_error_string(err), err, 0); } else if (0 == ret) { return plug_closing(s->plug, NULL, 0, 0); } else { return plug_receive(s->plug, atmark ? 0 : 1, buf, ret); } break; case FD_OOB: /* * This will only happen on a non-oobinline socket. It * indicates that we can immediately perform an OOB read * and get back OOB data, which we will send to the back * end with type==2 (urgent data). */ ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB); noise_ultralight(ret); if (ret <= 0) { char *str = (ret == 0 ? "Internal networking trouble" : winsock_error_string(p_WSAGetLastError())); /* We're inside the Windows frontend here, so we know * that the frontend handle is unnecessary. */ logevent(NULL, str); fatalbox("%s", str); } else { return plug_receive(s->plug, 2, buf, ret); } break; case FD_WRITE: { int bufsize_before, bufsize_after; s->writable = 1; bufsize_before = s->sending_oob + bufchain_size(&s->output_data); try_send(s); bufsize_after = s->sending_oob + bufchain_size(&s->output_data); if (bufsize_after < bufsize_before) plug_sent(s->plug, bufsize_after); } break; case FD_CLOSE: /* Signal a close on the socket. First read any outstanding data. */ open = 1; do { ret = p_recv(s->s, buf, sizeof(buf), 0); if (ret < 0) { err = p_WSAGetLastError(); if (err == WSAEWOULDBLOCK) break; return plug_closing(s->plug, winsock_error_string(err), err, 0); } else { if (ret) open &= plug_receive(s->plug, 0, buf, ret); else open &= plug_closing(s->plug, NULL, 0, 0); } } while (ret > 0); return open; case FD_ACCEPT: { struct sockaddr_in isa; int addrlen = sizeof(struct sockaddr_in); SOCKET t; /* socket of connection */ memset(&isa, 0, sizeof(struct sockaddr_in)); err = 0; t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen); if (t == INVALID_SOCKET) { err = p_WSAGetLastError(); if (err == WSATRY_AGAIN) break; } if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) { p_closesocket(t); /* dodgy WinSock let nonlocal through */ } else if (plug_accepting(s->plug, (void*)t)) { p_closesocket(t); /* denied or error */ } } } return 1;}/* * Deal with socket errors detected in try_send(). */void net_pending_errors(void){ int i; Actual_Socket s; /* * This might be a fiddly business, because it's just possible * that handling a pending error on one socket might cause * others to be closed. (I can't think of any reason this might * happen in current SSH implementation, but to maintain * generality of this network layer I'll assume the worst.) * * So what we'll do is search the socket list for _one_ socket * with a pending error, and then handle it, and then search * the list again _from the beginning_. Repeat until we make a * pass with no socket errors present. That way we are * protected against the socket list changing under our feet. */ do { for (i = 0; (s = index234(sktree, i)) != NULL; i++) { if (s->pending_error) { /* * An error has occurred on this socket. Pass it to the * plug. */ plug_closing(s->plug, winsock_error_string(s->pending_error), s->pending_error, 0); break; } } } while (s);}/* * Each socket abstraction contains a `void *' private field in * which the client can keep state. */static void sk_tcp_set_private_ptr(Socket sock, void *ptr){ Actual_Socket s = (Actual_Socket) sock; s->private_ptr = ptr;}static void *sk_tcp_get_private_ptr(Socket sock){ Actual_Socket s = (Actual_Socket) sock; return s->private_ptr;}/* * Special error values are returned from sk_namelookup and sk_new * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */const char *sk_addr_error(SockAddr addr){ return addr->error;}static const char *sk_tcp_socket_error(Socket sock){ Actual_Socket s = (Actual_Socket) sock; return s->error;}static void sk_tcp_set_frozen(Socket sock, int is_frozen){ Actual_Socket s = (Actual_Socket) sock; if (s->frozen == is_frozen) return; s->frozen = is_frozen; if (!is_frozen && s->frozen_readable) { char c; p_recv(s->s, &c, 1, MSG_PEEK); } s->frozen_readable = 0;}/* * For Plink: enumerate all sockets currently active. */SOCKET first_socket(int *state){ Actual_Socket s; *state = 0; s = index234(sktree, (*state)++); return s ? s->s : INVALID_SOCKET;}SOCKET next_socket(int *state){ Actual_Socket s = index234(sktree, (*state)++); return s ? s->s : INVALID_SOCKET;}int net_service_lookup(char *service){ struct servent *se; se = p_getservbyname(service, NULL); if (se != NULL) return p_ntohs(se->s_port); else return 0;}SockAddr platform_get_x11_unix_address(int displaynum, char **canonicalname){ SockAddr ret = snew(struct SockAddr_tag); memset(ret, 0, sizeof(struct SockAddr_tag)); ret->error = "unix sockets not supported on this platform"; return ret;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?