Re: TCP connection timeout
Re: TCP connection timeout
- Subject: Re: TCP connection timeout
- From: Quinn <email@hidden>
- Date: Tue, 27 Jan 2004 11:22:34 +0000
At 14:48 +0300 19/1/04, Igor garnov wrote:
So how can I set an endpoint's options so that this timeout would
be, say, 5 seconds? Is there some sample code?
This is a bit of a FAQ (mea culpa, I should've written a Q&A about
it). Here's my stock answer from the archives.
At 12:41 -0800 22/12/00, Quinn wrote:
I know of three different ways to implement connection timeouts with
the synchronous form of OTConnect.
o OTCancelSynchronousCalls -- In current versions of
OTCancelSynchronous calls does not work for synchronous OTConnect
due bug [2220123]. AFAIK this is fixed in OT 2.7.4, which will be
released as part of Mac OS 9.1.
o TCP_CONN_ABORT_THRESHOLD option -- As I mentioned earlier, I'm
reticent to wholeheartedly recommend this approach because it may
not work in the OT compatibility library on Mac OS X.
o OTSndDisconnect -- AFAIK this approach works for all versions of
OT and works on Mac OS X.
The following snippet of code demonstrates all 3 approaches (I also
include a "no timeout" option so that you can see the difference).
Also, the code in OTMP correctly handles cancelling an OTMPConnect
and is perfectly usable for non-MP code as well as MP code.
S+E
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Technical Support * Networking, Communications, Hardware
/*
File: OTConnectTimeout.c
Contains: Snippet that shows how to force OTConnect to stop
after a specific time.
Written by: DTS
Copyright: Copyright ) 2000 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you
by Apple Computer, Inc.
("Apple") in consideration of your agreement to the
following terms, and your
use, installation, modification or redistribution of
this Apple software
constitutes acceptance of these terms. If you do
not agree with these terms,
please do not use, install, modify or redistribute
this Apple software.
In consideration of your agreement to abide by the
following terms, and subject
to these terms, Apple grants you a personal,
non-exclusive license, under Apple's
copyrights in this original Apple software (the
"Apple Software"), to use,
reproduce, modify and redistribute the Apple
Software, with or without
modifications, in source and/or binary forms;
provided that if you redistribute
the Apple Software in its entirety and without
modifications, you must retain
this notice and the following text and disclaimers
in all such redistributions of
the Apple Software. Neither the name, trademarks,
service marks or logos of
Apple Computer, Inc. may be used to endorse or
promote products derived from the
Apple Software without specific prior written
permission from Apple. Except as
expressly stated in this notice, no other rights or
licenses, express or implied,
are granted by Apple herein, including but not
limited to any patent rights that
may be infringed by your derivative works or by
other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS
IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT
LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND
FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL,
INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR
OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
*/
#include <OpenTransport.h>
#include <OpenTransportProviders.h>
#include <Events.h>
#include <stdio.h>
/////////////////////////////////////////////////////////////////
static void MoreAssertQ(Boolean mustBeTrue)
{
if ( ! mustBeTrue ) {
DebugStr("\pMoreAssertQ: Assertion failure.");
}
}
typedef UInt32 TimeoutType;
enum {
kTimeoutNone = 0,
kTimeoutCancelSyncCalls,
kTimeoutOption,
kTimeoutSndDisconnect
};
static UInt32 gLastPrinted = 0;
static UInt32 gConnectTimeout = 0;
static TimeoutType gWhichTimeout;
static pascal void YieldingNotifier(void* contextPtr, OTEventCode code,
OTResult result, void* cookie)
{
OSStatus junk;
EndpointRef ep;
#pragma unused(contextPtr)
#pragma unused(result)
#pragma unused(cookie)
ep = (EndpointRef) contextPtr;
switch (code) {
case kOTSyncIdleEvent:
if ( TickCount() > gLastPrinted + 6 ) {
printf(".");
fflush(stdout);
gLastPrinted = TickCount();
}
if ( TickCount() > gConnectTimeout ) {
switch (gWhichTimeout) {
case kTimeoutNone:
// do nothing
break;
case kTimeoutCancelSyncCalls:
junk = OTCancelSynchronousCalls(ep, kOTCanceledErr);
MoreAssertQ(junk == noErr);
break;
case kTimeoutOption:
// do nothing, timeout is done by TCP itself
break;
case kTimeoutSndDisconnect:
// do nothing
junk = OTSndDisconnect(ep, nil);
MoreAssertQ(junk == noErr);
break;
default:
MoreAssertQ(false);
break;
}
}
break;
default:
// do nothing
break;
}
}
static EndpointRef OpenYieldingTCPEndpoint(OSStatus *err)
{
OSStatus junk;
EndpointRef ep;
ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, nil, err);
if (*err == noErr) {
junk = OTSetSynchronous(ep);
OTAssert("OpenYieldingTCPEndpoint: OTSetSynchronous failed",
junk == noErr);
junk = OTSetBlocking(ep);
OTAssert("OpenYieldingTCPEndpoint: OTSetBlocking failed",
junk == noErr);
junk = OTInstallNotifier(ep, YieldingNotifier, ep);
OTAssert("OpenYieldingTCPEndpoint: OTInstallNotifier
failed", junk == noErr);
junk = OTUseSyncIdleEvents(ep, true);
OTAssert("OpenYieldingTCPEndpoint: OTUseSyncIdleEvents
failed", junk == noErr);
}
return ep;
}
static OTResult SetFourByteOption(EndpointRef ep,
OTXTILevel level,
OTXTIName name,
UInt32 value)
// level and name must denote a four byte option that is
// appropriate for the endpoint ep. This routine sets the
// option to value. ep is assumed to be in synchronous
// mode.
//
// If all goes well, the result is noErr. If an error
// occurs, the result is negative. If the option could not
// be negotiated, a positive result being one of (T_FAILURE,
// T_PARTSUCCESS, T_READONLY, T_NOTSUPPORT) is returned
{
OTResult err;
TOption option;
TOptMgmt request;
TOptMgmt result;
// Set up the option buffer to reflect the specific option
// and value we want to set. We use a TOption structure
// to represent the option buffer. TOption is specifically
// defined to allow easy construction of 4 byte options.
// If you want to negotiate different size options, or
// multiple options in a single call, then constructing
// the option buffer is a little trickier
option.len = kOTFourByteOptionSize;
option.level = level;
option.name = name;
option.status = 0;
option.value[0] = value;
// Set up the request for OTOptionManagement to point
// to the option buffer we just filled out, and tell
// it that we want to negotiate (ie set) the option.
request.opt.buf = (UInt8 *) &option;
request.opt.len = sizeof(option);
request.flags = T_NEGOTIATE;
// Set up the reply for OTOptionManagement. This is where
// OTOptionManagement puts the result of the negotiation.
result.opt.buf = (UInt8 *) &option;
result.opt.maxlen = sizeof(option);
// Call OTOptionManagement and then check that the value
// was negotiated successfully. Any value other than
// T_SUCCESS is reported via the error result.
err = OTOptionManagement(ep, &request, &result);
if (err == noErr) {
if (option.status != T_SUCCESS) {
err = option.status;
}
}
return (err);
}
enum {
kTimeoutInSeconds = 5
};
static void OTConnectWithTimeout(TimeoutType whichTimeout)
{
OSStatus err;
OSStatus junk;
EndpointRef ep;
ep = OpenYieldingTCPEndpoint(&err);
if (err == noErr) {
// It's important that we set up gConnectTimeout before calling
// OTBind because the YieldingNotifier is already installed at
// this time. This means that the bind time is also included
// in the timeout, but that time is trivial.
gConnectTimeout = TickCount() + (kTimeoutInSeconds * 60);
gWhichTimeout = whichTimeout;
err = OTBind(ep, nil, nil);
}
if (err == noErr && whichTimeout == kTimeoutOption) {
err = SetFourByteOption(ep, INET_TCP,
TCP_CONN_ABORT_THRESHOLD, kTimeoutInSeconds * 1000);
if (err == noErr) {
err = SetFourByteOption(ep, INET_TCP,
TCP_CONN_NOTIFY_THRESHOLD, kTimeoutInSeconds * 1000 / 2);
}
}
if (err == noErr) {
TCall sndCall;
InetAddress sndAddr;
OTInitInetAddress(&sndAddr, 80, 0x01020304); // 1.2.3.4:80
OTMemzero(&sndCall, sizeof(sndCall));
sndCall.addr.buf = (UInt8 *) &sndAddr;
sndCall.addr.len = sizeof(sndAddr);
err = OTConnect(ep, &sndCall, nil);
}
if (ep != kOTInvalidEndpointRef) {
junk = OTCloseProvider(ep);
MoreAssertQ(junk == noErr);
}
if (err == noErr) {
printf("Success.\n");
} else {
printf("Failed with error %ld.\n", err);
}
}
void main(void)
{
OSStatus err;
Boolean quitNow;
char commandStr[256];
printf("Hello Cruel World!\n");
err = InitOpenTransport();
if (err == noErr) {
printf("c) Connect without special timeout\n");
printf("C) Connect with OTCancelSynchronousCalls timeout\n");
printf("k) Connect with TCP_CONN_ABORT_THRESHOLD timeout\n");
printf("K) Connect with OTSndDisconnect timeout\n");
printf("q) Quit\n");
printf("\n");
quitNow = false;
do {
printf("Enter a command:\n");
gets(commandStr);
switch (commandStr[0]) {
case 'c':
OTConnectWithTimeout(kTimeoutNone);
break;
case 'C':
OTConnectWithTimeout(kTimeoutCancelSyncCalls);
break;
case 'k':
OTConnectWithTimeout(kTimeoutOption);
break;
case 'K':
OTConnectWithTimeout(kTimeoutSndDisconnect);
break;
case 'q':
quitNow = true;
break;
default:
printf("Huh?");
break;
}
} while (!quitNow);
CloseOpenTransport();
}
if (err == noErr) {
printf("Success.\n");
} else {
printf("Failed with error %ld.\n", err);
}
printf("Done. Press command-Q to Quit.\n");
}
--
Quinn "The Eskimo!" <
http://www.apple.com/developer/>
Apple Developer Technical Support * Networking, Communications, Hardware
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.