#include #include #include #include #include "putty.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif static SOCKET s = INVALID_SOCKET; #define iswritable(x) ( (x) != IAC && (x) != CR ) static void raw_size(void); static int sb_opt, sb_len; static char *sb_buf = NULL; static int sb_size = 0; #define SB_DELTA 1024 static void try_write (void) { while (outbuf_head != outbuf_reap) { int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE); int len = end - outbuf_reap; int ret; ret = send (s, outbuf+outbuf_reap, len, 0); if (ret > 0) outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK; if (ret < len) return; } } static void s_write (void *buf, int len) { unsigned char *p = buf; while (len--) { int new_head = (outbuf_head + 1) & OUTBUF_MASK; if (new_head != outbuf_reap) { outbuf[outbuf_head] = *p++; outbuf_head = new_head; } } try_write(); } static void c_write (char *buf, int len) { while (len--) { int new_head = (inbuf_head + 1) & INBUF_MASK; int c = (unsigned char) *buf; if (new_head != inbuf_reap) { inbuf[inbuf_head] = *buf++; inbuf_head = new_head; } else { term_out(); if( inbuf_head == inbuf_reap ) len++; else break; } } } /* * Called to set up the raw connection. Will arrange for * WM_NETEVENT messages to be passed to the specified window, whose * window procedure should then call raw_msg(). * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. */ static char *raw_init (HWND hwnd, char *host, int port, char **realhost) { SOCKADDR_IN addr; struct hostent *h; unsigned long a; /* * Try to find host. */ if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) { if ( (h = gethostbyname(host)) == NULL) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; case WSAHOST_NOT_FOUND: case WSANO_DATA: return "Host does not exist"; case WSATRY_AGAIN: return "Host not found"; default: return "gethostbyname: unknown error"; } memcpy (&a, h->h_addr, sizeof(a)); *realhost = h->h_name; } else *realhost = host; a = ntohl(a); if (port < 0) port = 23; /* default telnet port */ /* * Open socket. */ s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; case WSAEAFNOSUPPORT: return "TCP/IP support not present"; default: return "socket(): unknown error"; } /* * Bind to local address. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(0); if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; default: return "bind(): unknown error"; } /* * Connect to remote address. */ addr.sin_addr.s_addr = htonl(a); addr.sin_port = htons((short)port); if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; case WSAECONNREFUSED: return "Connection refused"; case WSAENETUNREACH: return "Network is unreachable"; case WSAEHOSTUNREACH: return "No route to host"; default: return "connect(): unknown error"; } if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; default: return "WSAAsyncSelect(): unknown error"; } return NULL; } /* * Process a WM_NETEVENT message. Will return 0 if the connection * has closed, or <0 for a socket error. */ static int raw_msg (WPARAM wParam, LPARAM lParam) { int ret; char buf[256]; /* * Because reading less than the whole of the available pending * data can generate an FD_READ event, we need to allow for the * possibility that FD_READ may arrive with FD_CLOSE already in * the queue; so it's possible that we can get here even with s * invalid. If so, we return 1 and don't worry about it. */ if (s == INVALID_SOCKET) return 1; if (WSAGETSELECTERROR(lParam) != 0) return -WSAGETSELECTERROR(lParam); switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: case FD_CLOSE: ret = recv(s, buf, sizeof(buf), 0); if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) return 1; if (ret < 0) /* any _other_ error */ return -10000-WSAGetLastError(); if (ret == 0) { s = INVALID_SOCKET; return 0; } c_write( buf, ret ); return 1; case FD_OOB: do { ret = recv(s, buf, sizeof(buf), 0); c_write( buf, ret ); } while (ret > 0); do { ret = recv(s, buf, 1, MSG_OOB); } while (ret > 0); if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) return -30000-WSAGetLastError(); return 1; case FD_WRITE: if (outbuf_head != outbuf_reap) try_write(); return 1; } return 1; /* shouldn't happen, but WTF */ } /* * Called to send data down the raw connection. */ static void raw_send (char *buf, int len) { if (s == INVALID_SOCKET) return; s_write( buf, len ); } /* * Called to set the size of the window */ static void raw_size(void) { /* Do nothing! */ return; } /* * Send raw special codes. */ static void raw_special (Telnet_Special code) { /* Do nothing! */ return; } Backend raw_backend = { raw_init, raw_msg, raw_send, raw_size, raw_special };