📄 wal.c
字号:
EndPaint(hwnd, &ps);
} /* end do_stats */
/*----------------------------------------------------------------------
*
* Function: get_timers()
*
* Description: We get one timer for statistic updates, and *another*
* timer if the user elects to launch a timer-driven application.
*
* NOTE: We sometimes use *two* timers here. Considering timers are a
* limited resource, and especially since we could design it to use
* only one timer efficiently, this is not good. I'm being lazy
* here, plain and simple, but then again the timer-driven app is
* not recommended anyway (it's just for experimentation).
*/
void get_timers (HANDLE hInst, HANDLE hwnd)
{
hInst = hInst; /* avoid warning */
/* Set timer for statistics updates (every second) */
if (!SetTimer (hwnd, STATS_TIMER_ID, STATS_INTERVAL, NULL)) {
MessageBox (hwnd,
"Can't Get Windows Timer (for stats)",
"Error", MB_ICONEXCLAMATION | MB_OK);
} else {
KillTimer(hwnd, APP_TIMER_ID);
if (stWSAppData.nWinTimer) {
/* Get timer if user wants timer-driven application */
if (!SetTimer (hwnd, APP_TIMER_ID,
stWSAppData.nWinTimer, NULL)) {
MessageBox (hwnd,
"Can't Get Windows Timer (for app)", "Error",
MB_ICONEXCLAMATION | MB_OK);
}
}
}
do_stats (hwnd, hInst, TRUE); /* update stats display */
} /* end get_timers() */
/*----------------------------------------------------------------------
* Function: SetNewTimer()
*
* Description: Set a new timeout period for our timer.
*/
void SetNewTimer (HANDLE hwnd, int nOldTimer, int nNewTimer)
{
/* If we had a timer before, kill it (yea, this is unnecessary
* since SetTimer() automatically kills the old timer, but
* I *like* being paranoid). */
if (nOldTimer)
KillTimer (hwnd, APP_TIMER_ID);
/* If we have a timer now, set it */
if (nNewTimer) {
if (!SetTimer (hwnd, APP_TIMER_ID, nNewTimer, NULL)) {
MessageBox (hwnd, "Can't Get Windows Timer (for app)",
"Error", MB_ICONEXCLAMATION | MB_OK);
}
}
} /* end SetNewTimer() */
/*----------------------------------------------------------------------
*
* Function: LoopTimer()
*
* Description: Loop for a time-period, rather than waiting for reciept
* of a timer message (which is often unreliable on a busy system).
*/
void LoopTimer (BOOL IOStartFlag)
{
static u_long lLastTicks; /* Tick Count after last I/O */
u_long lTicksSince;
if (IOStartFlag) /*** if ENTERING I/O loop */
{
lTicksSince = (GetTickCount() - lLastTicks);
if (!lTicksSince) { /* if no time passed since last call */
stWSAppData.nLoopsDn++;
stWSAppData.nLoopsUp = 0;
if (stWSAppData.nLoopsDn >= stWSAppData.nLoopsDnMax) {
stWSAppData.nLoopsDn = 0;
/* Decrease the number of loops per IO call, if possible */
if (stWSAppData.nLoopLimit > 1)
stWSAppData.nLoopLimit -= 1;
}
} else {
stWSAppData.nLoopsUp++;
stWSAppData.nLoopsDn = 0;
if (stWSAppData.nLoopsUp >= stWSAppData.nLoopsUpMax) {
stWSAppData.nLoopsUp = 0;
/* Increment the number of loops per IO call, if it's
* still less than the maximum value user set */
if (stWSAppData.nLoopLimit < stWSAppData.nLoopMax)
stWSAppData.nLoopLimit += 1;
}
}
/* Increment the counter for the (calling) I/O function */
stWSAppData.lCallCount++;
}
else /*** if EXITING I/O loop ***/
{
/* Get Tick Count to see how soon we re-enter */
lLastTicks = GetTickCount();
}
return;
} /* end LoopTimer() */
/*----------------------------------------------------------------------
* Function: do_close()
*
* Description: Depending on the current socket state and the operation
* mode, we either initiate a close or complete a close.
*/
int do_close (HANDLE hInst, HANDLE hwnd, LPARAM bExitFlag)
{
int wRet;
int nOldState;
wRet = IDOK;
nOldState = stWSAppData.nSockState;
if (nOldState == STATE_CONNECTED) { /* connected? */
/* it's premature to reset socket state here,
* but we do it to expedite the socket close */
/*-----------------------------------------*/
stWSAppData.nSockState = STATE_CLOSE_PENDING;
/*-----------------------------------------*/
/*---------------------------------------------------------------------*/
/* NOTE: could add a dialog box here, to get closesocket timeout value */
/*---------------------------------------------------------------------*/
if (stWSAppData.nProtocol == PROT_DS) { /* if it's a datastream socket */
wRet = MessageBox ( /* ask if close gracefully */
hwnd, /* and set timeout = 0 if not */
"Close Connection Gracefully?",
"Close",
MB_ICONQUESTION | MB_YESNOCANCEL);
#if 0
/*------NOTE: This method of blocking close DOES NOT WORK-------*/
/* Check for and cancel pending blocking operation before we proceed! */
if ((wRet != IDCANCEL) &&
(WSAIsBlocking())) {
/* Cancel the blocking call */
WSACancelBlockingCall();
/* Now wait until the cancelled function returns (should
* fail with WSAEINTR error), before we close the socket */
do {
OurBlockingHook();
} while (WSAIsBlocking());
}
/*------------------ end of BAD example -----------------------*/
#endif
if (wRet == IDOK) {
/* Connection abort requested, need to set
* close timeout ("linger" value) to 0.
*/
struct linger stLinger;
int WSAerr;
stLinger.l_onoff = 1; /* Linger On */
stLinger.l_linger = 0; /* 0 Seconds */
if (setsockopt(stWSAppData.nSock,
SOL_SOCKET,
SO_LINGER,
(char FAR*) &stLinger,
sizeof(struct linger))) {
WSAerr = WSAGetLastError();
if (WSAerr == WSAEINPROGRESS) {
bl_close(hInst, hwnd);
} else {
WSAperror(WSAerr, "setsockopt()", hInst);
}
}
}
} else { /* if not Datastream, then it's Datagram */
wRet = MessageBox ( /* ask if they're sure they want to close */
hwnd,
"Are you sure you want to close the socket?",
"Close",
MB_ICONQUESTION | MB_OKCANCEL);
}
} /* end if STATE_CONNECTED */
/*
* If we have a socket and operation is not cancelled, then close the socket
*/
if (stWSAppData.nSockState > STATE_NONE) {
if (wRet != IDCANCEL) {
switch (stWSAppData.nOpMode) {
case OPMODE_BL:
wRet = bl_close (hInst, hwnd);
break;
case OPMODE_NB:
case OPMODE_AS:
wRet = nb_close (hInst, hwnd);
break;
}
} else {
/* cancel close requested */
stWSAppData.nSockState = nOldState; /* reset state */
if (nOldState == STATE_CONNECTED) /* if it was connected, jumpstart */
PostMessage(hwnd, WM_COMMAND, anIoCmd[stWSAppData.nIoMode], 0L);
return TRUE;
}
} else if (!bExitFlag) {
MessageBox (hwnd, "No Sockets Open", "Can't Close", MB_OK | MB_ICONINFORMATION);
}
return FALSE;
} /* end do_close() */
/*--------------------------------------------------------------------
* Function: WALWndProc()
*
* Description: Main window procedure
*/
LONG CALLBACK WALWndProc
(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
static HANDLE hInst;
FARPROC lpfnWSAppDlgProc, lpfnWSOptionProc;
int wRet, nFDError, nMsgQSize, i, j;
HMENU hWalMenu;
if (!stWSAppData.lBytesOut && !stWSAppData.lBytesIn)
stWSAppData.lStartTime = GetTickCount(); /* Start Time */
switch (msg) {
case IDM_ASYNC:
/*----------------------------------------------
* WSAAsyncSelect() event notification messages
*---------------------------------------------*/
nFDError = WSAGETSELECTERROR(lParam); /* check async error */
if (nFDError) {
int nFDEvent = WSAGETSELECTEVENT(lParam);
/* close the socket */
nb_close (hInst, hwnd);
/* if socket is active, notify user of error this asynch event message had */
if (!(stWSAppData.nSockState & (STATE_NONE | STATE_CLOSE_PENDING))) {
for (i=0, j=nFDEvent; j; i++, j>>=1); /* convert bit to index */
WSAperror(nFDError, aszWSAEvent[i], hInst);
}
}
switch (WSAGETSELECTEVENT(lParam)) { /* check async event */
case FD_OOB:
MessageBeep (MB_ICONASTERISK);
nb_oob_rcv (hInst, hwnd);
break;
case FD_READ:
/* we do multiple recv() calls per each FD_READ message we process,
* so we keep count of the number and ignore that many FD_READ
* messages. The threshold is at 2 since 1 recv() is legitimate,
* and the other may not have had data (if it failed with an
* WSAEWOULDBLOCK error */
if (recv_count > 2) {
recv_count--;
break;
}
/* rather than post the I/O message, we call the appropriate function to
* avoid the overhead involved with posting a message to proceed */
if (!(stWSAppData.nSockState & (STATE_CONNECTED | STATE_BOUND))) {
/* This message must have been left over
* in our message queue after a close */
break;
}
switch (stWSAppData.nIoMode) {
case IOMODE_R:
case IOMODE_WR:
/* do the read with more possible loops, to accomodate the
* asynchronous nature and "bunching" of incoming packets */
as_r (hInst, hwnd, (stWSAppData.nLoopLimit << 1));
break;
case IOMODE_RW:
as_r_w (hInst, hwnd);
break;
case IOMODE_W:
/* we shouldn't see the FD_READ event, so ask user what to do */
wRet = MessageBox(hwnd,
"Data received, but application is write-only. Read it?",
"Unexpected Condition",
MB_YESNO | MB_ICONQUESTION);
if (wRet == IDYES)
as_r (hInst, hwnd, DFLT_LOOP_MAX);
break;
}
break;
case FD_WRITE:
/* Either we've just connected, so we're starting I/O for the first
* time, or we've just got some outgoing buffers after a send()
* failed with WSAEWOULDBLOCK so we should be able to send again. */
if (!(stWSAppData.nSockState & (STATE_CONNECTED | STATE_BOUND))) {
/* This message must have been left over
* in our message queue after a close */
break;
}
switch (stWSAppData.nIoMode) {
case IOMODE_R:
/* nothing to do here since the application is read-only
* (its not sending any data). We really shouldn't have
* registered for the FD_WRITE event, since our application
* didn't need it.*/
break;
case IOMODE_WR:
/* write chargen data (printable ASCII character sequence
* we generate) */
as_w_r (hInst, hwnd);
break;
case IOMODE_RW:
/* we only have something to do for our "read then write"
* (server) application if we're recovering from a send()
* that failed with a WSAEWOULDBLOCK error. In that case
* we should have a count of bytes left to write (where
* we left off when our write failed). */
if (stWSAppData.nOutLen) {
as_r_w (hInst, hwnd);
}
break;
case IOMODE_W:
/* echo data that we received (the stWSAppData.nBytesToSend)*/
as_w (hInst, hwnd);
break;
}
break;
case FD_ACCEPT:
/* we have a connection request pending, accept it and start I/O */
as_accept(hInst, hwnd);
break;
case FD_CONNECT:
/* Set the socket state (if no error), and
* we'll start I/O with FD_WRITE */
if (!nFDError) {
/*-------------------------------------*/
stWSAppData.nSockState = STATE_CONNECTED;
/*-------------------------------------*/
} else {
/* close the socket, if there's an error */
do_close(hInst, hwnd, FALSE);
}
break;
case FD_CLOSE:
/* BQ NOTE: I just realized, I'd rather have my close functions call
* shutdown(), recv() (or ioctlsocket(FIONREAD) if blocking socket),
* then call closesocket().
*/
if (stWSAppData.nSockState == STATE_CONNECTED)
nb_close(hInst, hwnd);
}
break;
case WM_COMMAND:
switch (wParam) {
case IDM_WRITE_READ:
switch (stWSAppData.nOpMode) {
case OPMODE_BL:
bl_w_r (hInst, hwnd);
break;
case OPMODE_NB:
nb_w_r (hInst, hwnd);
break;
case OPMODE_AS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -