📄 socket.c
字号:
/* Write queued data to the remote end
*/
static void socketWriteReady(void)
{
while (dataQueue != NULL) {
int numWritten;
/* Get the data at the head of the queue and send as
* much as possible to the remote end.
*/
ASSERT(dataQueue->text != NULL);
ASSERT(dataQueue->len > writeIdx);
numWritten = send(sock, (char *)dataQueue->text + writeIdx,
dataQueue->len - writeIdx, 0);
if (numWritten != SOCKET_ERROR) {
/* Managed to send data
*/
writeIdx += numWritten;
if (writeIdx == dataQueue->len) {
Data* tmp = dataQueue;
/* Completed sending the data - remove it from the queue
* and delete it.
*/
dataQueue = dataQueue->next;
if (dataQueue == NULL)
dataEnd = NULL;
free(tmp->text);
free(tmp);
writeIdx = 0;
}
} else {
int error; /* query the error encountered */
/* Some sort of error sending to remote end.
*/
error = WSAGetLastError();
if (error == WSAEWOULDBLOCK)
/* No problems, remote end can not accept any more
* data just now
*/
return;
else {
/* Error: close socket
*/
socketError("send()", error);
closeSocket();
return;
}
}
}
}
/* Receive some out-of-band data from the other end of the socket
*/
static void socketOobReady(void)
{
int numRead; /* Number of bytes read this time around */
char oobBuffer[256]; /* Buffer for OOB data */
/* Try to read as much as possible from the remote end.
*/
numRead = recv(sock, oobBuffer, sizeof(oobBuffer), MSG_OOB);
if (numRead == 0)
/* No more data ready
*/
return;
if (numRead == SOCKET_ERROR) {
int error = WSAGetLastError();
if (error == WSAEWOULDBLOCK)
/* No more data ready
*/
return;
/* Error: close socket
*/
socketError("recv()", error);
closeSocket();
return;
}
/* Got some OOB data from remote end
*/
rawProcessOob((unsigned char*)oobBuffer, numRead);
/* Assume that the OOB data was in response to ^C, eventually we
* will get the prompt back - we must allow it to be shown be
* restoring character flow.
*/
if (rawGetProtocol() != protoNone && localFlowControl)
socketSetFlowStop(FALSE);
}
/* Perform a select on the socket. When an event occurs the WINSOCK
* library will sent a WM_SOCK_EVENT message to the socket window
* message proc.
*
* Return TRUE if the operation was successful.
*/
static BOOL socketSelect(void)
{
LONG events; /* socket events we are interested in */
if ((socketState == sockOnline) || (socketState == sockProxy))
/* We are online - listen for close, read, write, and out-of-band
*/
events = FD_CLOSE|FD_READ|FD_WRITE|FD_OOB;
else
/* We are not connected yet, just listen for connect
*/
events = FD_CONNECT;
if (WSAAsyncSelect(sock, sockWnd, WM_SOCK_EVENT, events) != SOCKET_ERROR)
return TRUE;
socketError("WSAAsyncSelect()", WSAGetLastError());
return FALSE;
}
/* Build a new socket and try to connect to the remote end
*
* Return TRUE if the operation was successful
*/
static BOOL socketMakeNew(void)
{
int error; /* detect errors encountered */
DWORD yes = 1; /* ioctl parameter */
struct sockaddr_in *dst; /* pointer to address for connect (direct/proxy) */
remoteHasClosed = FALSE;
/* Log that we are trying to connect
*/
logProtocol("Connecting to %d.%d.%d.%d/%d\n",
addr.sin_addr.s_net, addr.sin_addr.s_host,
addr.sin_addr.s_lh, addr.sin_addr.s_impno,
htons(addr.sin_port));
socketSetState(sockConnect);
/* Set up socket address family
*/
addr.sin_family = PF_INET;
proxyAddr.sin_family = PF_INET;
/* Create a socket
*/
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
socketError("socket()", WSAGetLastError());
return FALSE;
}
/* Set the socket non-blocking
*/
if (ioctlsocket(sock, FIONBIO, &yes) == SOCKET_ERROR) {
socketError("ioctlsocket()", WSAGetLastError());
return FALSE;
}
/* Set the events that we are interested in knowing about
*/
if (!socketSelect())
return FALSE;
if (rawGetProtocol() == protoTelnet)
/* If we are connecting to the Telnet port, disable local flow
* control.
*/
localFlowControl = FALSE;
else if (rawGetProtocol() == protoRlogin) {
SOCKADDR_IN localAddr; /* address of the local end */
u_short localPort = IPPORT_RESERVED; /* first port to try for
* local end of rlogin
* connection */
/* Rlogin servers will only accept connections from ports in
* the reserved range (below 1024). Start at 1023 and keep
* trying until we either get a valid local endpoint, or we
* run out of ports.
*/
localAddr.sin_family = PF_INET;
localAddr.sin_addr.s_addr = INADDR_ANY;
for (;;) {
localPort--;
if (localPort == IPPORT_RESERVED / 2) {
MessageBox(termGetWnd(), "All reserved ports in use",
telnetAppName(),
MB_APPLMODAL | MB_ICONHAND | MB_RETRYCANCEL);
return FALSE;
}
localAddr.sin_port = htons(localPort);
if (bind(sock, (LPSOCKADDR)&localAddr, sizeof(localAddr)) == 0)
break;
if ((error = WSAGetLastError()) != WSAEADDRINUSE) {
socketError("bind()", error);
return FALSE;
}
}
/* Enable local flow control
*/
localFlowControl = TRUE;
} else
/* Enable local flow control
*/
localFlowControl = TRUE;
/* We start connection with flow enabled. Flow can not be
* restarted with any character unless we negotiate that option.
*/
flowStopped = FALSE;
emulLocalFlowAny(FALSE);
/* set the destination address (direct/proxy)
*/
dst = (proxyEnabled() ? &proxyAddr : &addr);
/* Initiate the connection
*/
if (connect(sock, (struct sockaddr*)dst, sizeof(addr)) == SOCKET_ERROR) {
if ((error = WSAGetLastError()) != WSAEWOULDBLOCK) {
socketError("connect()", error);
return FALSE;
}
}
return TRUE;
}
/* Asynchronous get service by name has completed, save the results
* (service port)
*/
static void socketSaveService(void)
{
struct servent servent; /* Service to connect */
memcpy((void*)&servent, hostbuff, sizeof(servent));
addr.sin_port = servent.s_port;
}
/* Initiate an asynchronous get service by name
*
* Return TRUE if successful.
*/
static BOOL socketGetServByName(void)
{
socketSetState(sockGetServName);
if (strlen(socketService) > 0 && isdigit(socketService[0])) {
/* If service name starts with a digit, assume that the port
* was directly specified and proceed directly to establish a
* connection.
*/
addr.sin_port = htons((short)atoi(socketService));
return socketMakeNew();
}
/* Query service port from name
*/
if (WSAAsyncGetServByName(sockWnd, WM_SOCK_GETSERVBYNAME,
socketService, "tcp", hostbuff,
MAXGETHOSTSTRUCT))
return TRUE;
socketError("WSAAsyncGetServByName()", WSAGetLastError());
return FALSE;
}
/* Asynchronous get host by name has completed, save the results
* (host address)
*/
static void socketSaveHostname(void)
{
struct hostent hostent; /* Address of host to connect */
memcpy((void*)&hostent, hostbuff, sizeof(hostent));
memcpy((char*)&addr.sin_addr, (char*)&hostent.h_addr[0], hostent.h_length);
}
/* Initiate an asynchronous get host by name
*
* Return TRUE if successful.
*/
static BOOL socketGetHostByName(void)
{
unsigned long inaddr = inet_addr(socketHost); /* check if IP
* address specified
* directly */
socketSetState(sockGetHostName);
if (inaddr != INADDR_NONE) {
/* Looks like a numeric address was provided. Copy it into
* the address structure, and proceed to service lookup
*/
memcpy((char*)&addr.sin_addr, (char*)&inaddr, 4);
return socketGetServByName();
}
/* Query host address from name
*/
if (WSAAsyncGetHostByName(sockWnd, WM_SOCK_GETHOSTBYNAME,
socketHost, hostbuff, MAXGETHOSTSTRUCT))
return TRUE;
socketError("WSAAsyncGetGetHostByName()", WSAGetLastError());
return FALSE;
}
/* Asynchronous get host by name for Proxy server has completed, save the results
* (host address)
*/
static void socketSaveProxyHostname(void)
{
struct hostent hostent; /* Address of host to connect */
memcpy((void*)&hostent, hostbuff, sizeof(hostent));
memcpy((char*)&proxyAddr.sin_addr, (char*)&hostent.h_addr[0], hostent.h_length);
}
/* Initiate an asynchronous get host by name for Proxy server
*
* Return TRUE if successful.
*/
static BOOL socketGetProxyHostByName(void)
{
unsigned long inaddr;
proxyAddr.sin_port = htons((u_short) atoi(proxyGetPort()));
inaddr = inet_addr(proxyGetHost());
socketSetState(sockGetProxyHostName);
if (inaddr != INADDR_NONE) {
memcpy((char*)&proxyAddr.sin_addr, (char*)&inaddr, 4);
if (!proxySupportHostname()) {
return socketGetHostByName();
}
return socketGetServByName();
}
if (WSAAsyncGetHostByName(sockWnd, WM_SOCK_GETHOSTBYNAME,
proxyGetHost(), hostbuff, MAXGETHOSTSTRUCT))
return TRUE;
socketError("WSAAsyncGetGetHostByName()", WSAGetLastError());
return FALSE;
}
/* We delay our read / write on the socket until a convenient
* processing time. This prevents the situation where a telnet to
* CHARGEN totally locks up Windows. In our case, we wait until the
* message queue is empty.
*/
void socketProcessPending()
{
if (readyForRead) {
/* When we receive an FD_READ event on the socket, the code
* processing the event sets readyForRead TRUE. When we are
* performing local flow control, and we have blocked flow, we
* do not want to read from the socket. If we are not running
* telnet or rlogin, then there is no local flow control.
*/
if (rawGetProtocol() == protoNone
|| !(localFlowControl && flowStopped)) {
/* the following two statements are reversed in they */
/* execution order (Khader Al-Atrash) */
readyForRead = FALSE;
socketReadReady();
}
}
if (remoteHasClosed) {
/* if we have a proxy request in progress, proxyHasClosed() display a error */
if (socketState == sockProxy) {
proxyRemoteHasClosed();
}
closeSocket();
/* If the user has set exit-on-disconnect, exit the application
*/
if (connectGetExitOnDisconnect())
telnetExit();
} else if (readyForWrite) {
/* When we receive an FD_WRITE event on the socket, the
* processing code sets readyForWrite TRUE. We perform the
* write here, once the event queue is empty.
*/
/* the following two statements are reversed in they */
/* execution order (Khader Al-Atrash) */
readyForWrite = FALSE;
socketWriteReady();
}
}
/* Return whether or not we are performing local flow control
*/
BOOL socketLocalFlowControl(void)
{
return localFlowControl;
}
/* Set local flow control on or off
*
* Args:
* local - do we wish to switch to local flow control?
*/
void socketSetLocalFlowControl(BOOL local)
{
if (local == localFlowControl)
/* No change in value
*/
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -