5e1a8e27 |
1 | #include <windows.h> |
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | #include <winsock.h> |
5 | |
6 | #include "putty.h" |
7 | |
8 | #ifndef FALSE |
9 | #define FALSE 0 |
10 | #endif |
11 | #ifndef TRUE |
12 | #define TRUE 1 |
13 | #endif |
14 | |
15 | static SOCKET s = INVALID_SOCKET; |
16 | |
17 | #define iswritable(x) ( (x) != IAC && (x) != CR ) |
18 | |
19 | static void raw_size(void); |
20 | |
21 | static int sb_opt, sb_len; |
22 | static char *sb_buf = NULL; |
23 | static int sb_size = 0; |
24 | #define SB_DELTA 1024 |
25 | |
26 | static void try_write (void) { |
27 | while (outbuf_head != outbuf_reap) { |
28 | int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE); |
29 | int len = end - outbuf_reap; |
30 | int ret; |
31 | |
32 | ret = send (s, outbuf+outbuf_reap, len, 0); |
33 | if (ret > 0) |
34 | outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK; |
35 | if (ret < len) |
36 | return; |
37 | } |
38 | } |
39 | |
40 | static void s_write (void *buf, int len) { |
41 | unsigned char *p = buf; |
42 | while (len--) { |
43 | int new_head = (outbuf_head + 1) & OUTBUF_MASK; |
44 | if (new_head != outbuf_reap) { |
45 | outbuf[outbuf_head] = *p++; |
46 | outbuf_head = new_head; |
47 | } |
48 | } |
49 | try_write(); |
50 | } |
51 | |
52 | static void c_write (char *buf, int len) { |
53 | while (len--) { |
54 | int new_head = (inbuf_head + 1) & INBUF_MASK; |
55 | int c = (unsigned char) *buf; |
56 | if (new_head != inbuf_reap) { |
57 | inbuf[inbuf_head] = *buf++; |
58 | inbuf_head = new_head; |
59 | } |
60 | } |
61 | } |
62 | |
63 | /* |
64 | * Called to set up the raw connection. Will arrange for |
65 | * WM_NETEVENT messages to be passed to the specified window, whose |
66 | * window procedure should then call raw_msg(). |
67 | * |
68 | * Returns an error message, or NULL on success. |
69 | * |
70 | * Also places the canonical host name into `realhost'. |
71 | */ |
72 | static char *raw_init (HWND hwnd, char *host, int port, char **realhost) { |
73 | SOCKADDR_IN addr; |
74 | struct hostent *h; |
75 | unsigned long a; |
76 | |
77 | /* |
78 | * Try to find host. |
79 | */ |
80 | if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) { |
81 | if ( (h = gethostbyname(host)) == NULL) |
82 | switch (WSAGetLastError()) { |
83 | case WSAENETDOWN: return "Network is down"; |
84 | case WSAHOST_NOT_FOUND: case WSANO_DATA: |
85 | return "Host does not exist"; |
86 | case WSATRY_AGAIN: return "Host not found"; |
87 | default: return "gethostbyname: unknown error"; |
88 | } |
89 | memcpy (&a, h->h_addr, sizeof(a)); |
90 | *realhost = h->h_name; |
91 | } else |
92 | *realhost = host; |
93 | a = ntohl(a); |
94 | |
95 | if (port < 0) |
96 | port = 23; /* default telnet port */ |
97 | |
98 | /* |
99 | * Open socket. |
100 | */ |
101 | s = socket(AF_INET, SOCK_STREAM, 0); |
102 | if (s == INVALID_SOCKET) |
103 | switch (WSAGetLastError()) { |
104 | case WSAENETDOWN: return "Network is down"; |
105 | case WSAEAFNOSUPPORT: return "TCP/IP support not present"; |
106 | default: return "socket(): unknown error"; |
107 | } |
108 | |
109 | /* |
110 | * Bind to local address. |
111 | */ |
112 | addr.sin_family = AF_INET; |
113 | addr.sin_addr.s_addr = htonl(INADDR_ANY); |
114 | addr.sin_port = htons(0); |
115 | if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) |
116 | switch (WSAGetLastError()) { |
117 | case WSAENETDOWN: return "Network is down"; |
118 | default: return "bind(): unknown error"; |
119 | } |
120 | |
121 | /* |
122 | * Connect to remote address. |
123 | */ |
124 | addr.sin_addr.s_addr = htonl(a); |
125 | addr.sin_port = htons((short)port); |
126 | if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) |
127 | switch (WSAGetLastError()) { |
128 | case WSAENETDOWN: return "Network is down"; |
129 | case WSAECONNREFUSED: return "Connection refused"; |
130 | case WSAENETUNREACH: return "Network is unreachable"; |
131 | case WSAEHOSTUNREACH: return "No route to host"; |
132 | default: return "connect(): unknown error"; |
133 | } |
134 | |
135 | if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | |
136 | FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR) |
137 | switch (WSAGetLastError()) { |
138 | case WSAENETDOWN: return "Network is down"; |
139 | default: return "WSAAsyncSelect(): unknown error"; |
140 | } |
141 | |
142 | return NULL; |
143 | } |
144 | |
145 | /* |
146 | * Process a WM_NETEVENT message. Will return 0 if the connection |
147 | * has closed, or <0 for a socket error. |
148 | */ |
149 | static int raw_msg (WPARAM wParam, LPARAM lParam) { |
150 | int ret; |
151 | char buf[256]; |
152 | |
153 | if (s == INVALID_SOCKET) /* how the hell did we get here?! */ |
154 | return -5000; |
155 | |
156 | if (WSAGETSELECTERROR(lParam) != 0) |
157 | return -WSAGETSELECTERROR(lParam); |
158 | |
159 | switch (WSAGETSELECTEVENT(lParam)) { |
160 | case FD_READ: |
161 | ret = recv(s, buf, sizeof(buf), 0); |
162 | if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) |
163 | return 1; |
164 | if (ret < 0) /* any _other_ error */ |
165 | return -10000-WSAGetLastError(); |
166 | if (ret == 0) { |
167 | s = INVALID_SOCKET; |
168 | return 0; /* can't happen, in theory */ |
169 | } |
170 | c_write( buf, ret ); |
171 | return 1; |
172 | case FD_OOB: |
173 | do { |
174 | ret = recv(s, buf, sizeof(buf), 0); |
175 | c_write( buf, ret ); |
176 | } while (ret > 0); |
177 | do { |
178 | ret = recv(s, buf, 1, MSG_OOB); |
179 | } while (ret > 0); |
180 | if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) |
181 | return -30000-WSAGetLastError(); |
182 | return 1; |
183 | case FD_WRITE: |
184 | if (outbuf_head != outbuf_reap) |
185 | try_write(); |
186 | return 1; |
187 | case FD_CLOSE: |
188 | s = INVALID_SOCKET; |
189 | return 0; |
190 | } |
191 | return 1; /* shouldn't happen, but WTF */ |
192 | } |
193 | |
194 | /* |
195 | * Called to send data down the raw connection. |
196 | */ |
197 | static void raw_send (char *buf, int len) { |
198 | |
199 | if (s == INVALID_SOCKET) |
200 | return; |
201 | |
202 | s_write( buf, len ); |
203 | } |
204 | |
205 | /* |
206 | * Called to set the size of the window |
207 | */ |
208 | static void raw_size(void) { |
209 | /* Do nothing! */ |
210 | return; |
211 | } |
212 | |
213 | /* |
214 | * Send raw special codes. |
215 | */ |
216 | static void raw_special (Telnet_Special code) { |
217 | /* Do nothing! */ |
218 | return; |
219 | } |
220 | |
221 | Backend raw_backend = { |
222 | raw_init, |
223 | raw_msg, |
224 | raw_send, |
225 | raw_size, |
226 | raw_special |
227 | }; |