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