📄 socket.c
字号:
/* socket.c
* Copyright (c) 1997 David Cole
*
* Handle the WINSOCK connection to server
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <winsock.h>
#include "platform.h"
#include "utils.h"
#include "dtelnet.h"
#include "emul.h"
#include "term.h"
#include "connect.h"
#include "raw.h"
#include "socket.h"
#include "status.h"
#include "log.h"
#include "proxy.h"
#define SOCKLIB_VERSION 0x0101
static char hostbuff[MAXGETHOSTSTRUCT]; /* data from host buffer */
static struct WSAData WSAData; /* SocketLib data buffer */
static HWND sockWnd; /* window for handling socket messages */
static SOCKET sock = INVALID_SOCKET; /* The socket associated with the class */
static struct sockaddr_in addr; /* Build address for socket to connect to */
static struct sockaddr_in proxyAddr; /* Build address for proxy server */
static struct sockaddr_in localAddr; /* Local address */
static BOOL remoteHasClosed; /* Remember if remote end has closed socket */
static BOOL readyForRead; /* Remember if we have a read pending */
static BOOL readyForWrite; /* Remember if we have a write pending */
static BOOL localFlowControl; /* Are we doing local flow control? */
static BOOL flowStopped; /* Has the user pressed ^S? */
static char socketHost[128]; /* where we connecting to */
static char socketService[64]; /* which service we are connecting to */
static char socketLocalIp[32]; /* Local IP address */
static char readBuffer[512]; /* limit amount we read every
* time to 512 so we can have
* some ability to interrupt
* output via ^S */
static int readIdx; /* current position in readBuffer */
/* Hold all data to be sent to the remote end in a queue.
*/
typedef struct Data Data;
struct Data {
Data* next; /* next data in queue */
unsigned char* text; /* text to be sent to remote end */
int len; /* length of text being sent */
};
static Data* dataQueue; /* head of data queue */
static Data* dataEnd; /* end of data queue */
static int writeIdx; /* write position in queue head */
/* Define the states that communication to the remote end can be in
*/
typedef enum {
sockOffline, /* idle and offline */
sockGetProxyHostName, /* offline - resolving proxy host */
sockGetHostName, /* offline - resolving host */
sockGetServName, /* offline - resolving service */
sockConnect, /* offline - connecting */
sockProxy, /* offline - proxy request */
sockOnline /* online */
} SocketState;
static SocketState socketState = sockOffline; /* current socket state */
static void socketSetState(SocketState state);
static char* socketWinClass = "DTelnetSocketWClass";
/* Report a socket error to the user
*
* Args:
* operation - the operation being performed when error was encountered
* error - the error that was encountered
*/
void socketError(const char* operation, int error)
{
char msg[512]; /* format error message */
char *dstHost; /* pointer to destination host */
char *dstService; /* pointer to destination service */
/* set destination host/service
*/
if (proxyEnabled()) {
dstHost = proxyGetHost();
dstService = proxyGetPort();
}
else {
dstHost = socketHost;
dstService = socketService;
}
switch (error) {
case WSAEINTR:
sprintf(msg, "%s was interrupted", operation);
break;
case WSAEBADF:
sprintf(msg, "%s used a bad file descriptor", operation);
break;
case WSAEACCES:
sprintf(msg, "Permission denied for %s", operation);
break;
case WSAEFAULT:
sprintf(msg, "%s used a bad address", operation);
break;
case WSAEINVAL:
sprintf(msg, "Invalid argument in %s", operation);
break;
case WSAEMFILE:
sprintf(msg, "Too many open files during %s", operation);
break;
case WSAEWOULDBLOCK:
sprintf(msg, "Operation %s would block", operation);
break;
case WSAEINPROGRESS:
sprintf(msg, "Called %s while blocking operation in progress",
operation);
break;
case WSAEALREADY:
sprintf(msg, "%s already in progress", operation);
break;
case WSAENOTSOCK:
sprintf(msg, "Called %s on a non-socket", operation);
break;
case WSAEDESTADDRREQ:
sprintf(msg, "Destination address missing during %s", operation);
break;
case WSAEMSGSIZE:
sprintf(msg, "Message too long during %s", operation);
break;
case WSAEPROTOTYPE:
sprintf(msg, "Protocol wrong type for socket during %s", operation);
break;
case WSAENOPROTOOPT:
sprintf(msg, "Protocol not available during %s", operation);
break;
case WSAEPROTONOSUPPORT:
sprintf(msg, "Protocol not supported during %s", operation);
break;
case WSAESOCKTNOSUPPORT:
sprintf(msg, "Socket type not supported during %s", operation);
break;
case WSAEOPNOTSUPP:
sprintf(msg, "Option not supported during %s", operation);
break;
case WSAEPFNOSUPPORT:
sprintf(msg, "Protocol family not supported during %s", operation);
break;
case WSAEAFNOSUPPORT:
sprintf(msg, "Address family not supported during %s", operation);
break;
case WSAEADDRINUSE:
sprintf(msg, "Address already in use during %s", operation);
break;
case WSAEADDRNOTAVAIL:
sprintf(msg, "Cannot assign requested address during %s", operation);
break;
case WSAENETDOWN:
sprintf(msg, "Network is down");
break;
case WSAENETUNREACH:
sprintf(msg, "Network is unreachable");
break;
case WSAENETRESET:
sprintf(msg, "Network dropped connection because of reset");
break;
case WSAECONNABORTED:
sprintf(msg, "Software caused connect abort during %s", operation);
break;
case WSAECONNRESET:
sprintf(msg, "Connect has been reset by server");
break;
case WSAENOBUFS:
sprintf(msg, "No buffer space available during %s", operation);
break;
case WSAEISCONN:
sprintf(msg, "Already connected during %s", operation);
break;
case WSAENOTCONN:
sprintf(msg, "Not connected during %s", operation);
break;
case WSAESHUTDOWN:
sprintf(msg, "Cannot send after shutdown during %s", operation);
break;
case WSAETOOMANYREFS:
sprintf(msg, "Too many references during %s", operation);
break;
case WSAETIMEDOUT:
sprintf(msg, "Connection to %s/%s timed out", dstHost, dstService);
break;
case WSAECONNREFUSED:
sprintf(msg, "Connection to %s/%s refused", dstHost, dstService);
break;
case WSAELOOP:
sprintf(msg, "Too many symbolic links during %s", operation);
break;
case WSAENAMETOOLONG:
sprintf(msg, "File name too long during %s", operation);
break;
case WSAEHOSTDOWN:
sprintf(msg, "Host %s is down", dstHost);
break;
case WSAEHOSTUNREACH:
sprintf(msg, "No route to host %s", dstHost);
break;
case WSAENOTEMPTY:
sprintf(msg, "Directory not empty during %s", operation);
break;
case WSAEUSERS:
sprintf(msg, "Too many users during %s", operation);
break;
case WSAEDQUOT:
sprintf(msg, "Quota exceeded during %s", operation);
break;
case WSAESTALE:
sprintf(msg, "Stale NFS handle during %s", operation);
break;
case WSAEREMOTE:
sprintf(msg, "Object is remote during %s", operation);
break;
case WSASYSNOTREADY:
sprintf(msg, "Network subsystem is not usable");
break;
case WSAVERNOTSUPPORTED:
sprintf(msg, "WINSOCK DLL cannot support this application");
break;
case WSANOTINITIALISED:
sprintf(msg, "WSAStartup has not been called during %s", operation);
break;
case WSAHOST_NOT_FOUND:
sprintf(msg, "Authoritative host not found");
break;
case WSATRY_AGAIN:
sprintf(msg, "Try again");
break;
case WSANO_RECOVERY:
sprintf(msg, "No recovery during %s", operation);
break;
case WSANO_DATA:
switch (socketState) {
case sockGetProxyHostName:
sprintf(msg, "No such host %s", proxyGetHost());
break;
case sockGetHostName:
sprintf(msg, "No such host %s", socketHost);
break;
case sockGetServName:
sprintf(msg, "No such service %s", socketService);
break;
default:
sprintf(msg, "No data during %s", operation);
break;
}
break;
}
MessageBox(termGetWnd(), msg, telnetAppName(),
MB_APPLMODAL | MB_ICONHAND | MB_OK);
}
/* Close our connection to the remote end and discard any data that
* was queued to be sent
*/
static void closeSocket(void)
{
remoteHasClosed = FALSE;
readIdx = writeIdx = 0;
if (sock != INVALID_SOCKET) {
if (WSAAsyncSelect(sock, sockWnd, 0, 0) == SOCKET_ERROR)
socketError("WSAAsyncSelect()", WSAGetLastError());
if (closesocket(sock) == SOCKET_ERROR)
socketError("closesocket()", WSAGetLastError());
sock = INVALID_SOCKET;
}
/* Reset the application window title
*/
telnetSetTitle();
socketSetState(sockOffline);
/* Discard all data that was queued to be sent to remote end
*/
while (dataQueue != NULL) {
Data* tmp = dataQueue->next;
ASSERT(dataQueue->text != NULL);
free(dataQueue->text);
free(dataQueue);
dataQueue = tmp;
}
dataEnd = NULL;
}
/* Return whether or not we have a connection to the remote end */
BOOL socketConnected()
{
return socketState == sockOnline;
}
/* Return whether or not we are offline and idle
*/
BOOL socketOffline(void)
{
return socketState == sockOffline;
}
/* Close the connection to the server
*/
void socketDisconnect(void)
{
closeSocket();
}
/* Read some data from the remote end and send it through the raw
* protocol processing code.
*/
static void socketReadReady(void)
{
int error; /* Error returned from socket read */
int numRead; /* Number of bytes read this time around */
int numUsed; /* Number of bytes used by processing */
if (sock == INVALID_SOCKET) return;
/* we give the control to proxy.c to handle the
* proxy protocol while socketState == sockProxy
*/
if (socketState == sockProxy)
{
int ret;
ret = proxyProtocolHandler();
if (ret == PROXY_ERROR) {
closeSocket();
}
else if (ret == PROXY_CONNECTED) {
socketSetState(sockOnline);
telnetSetTitle();
rawStartSession();
}
return;
}
/* Try to read as much as possible from the server.
*/
ASSERT(readIdx < sizeof(readBuffer));
numRead = recv(sock, ((char*)readBuffer) + readIdx,
sizeof(readBuffer) - readIdx, 0);
if (numRead == 0)
/* No more data ready
*/
return;
if (numRead == SOCKET_ERROR) {
error = WSAGetLastError();
if (error == WSAEWOULDBLOCK)
/* No more data ready
*/
return;
/* Error: close socket
*/
socketError("recv()", error);
closeSocket();
return;
}
/* Got some data from the remote end, send it through protocol
* processing
*/
ASSERT(numRead > 0);
readIdx += numRead;
numUsed = rawProcessData((unsigned char *)readBuffer, readIdx);
ASSERT(numUsed >= 0);
ASSERT(numUsed <= readIdx);
/* Skip over data that was consumed by protocol code
*/
if (numUsed == readIdx)
readIdx = 0;
else {
memmove(readBuffer, readBuffer + numUsed, readIdx - numUsed);
readIdx -= numUsed;
}
if (readIdx == sizeof(readBuffer)) {
/* Buffer is full.
*/
readIdx = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -