home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-06-26 | 10.9 KB | 375 lines | [TEXT/CWIE] |
- /*
- File: LiveFastStartServerTest.c
- -- based on OTSimpleServerHTTPTest.c and HackTV.c
-
- Contains: A test program for the simple HTTP server code.
-
- Written by: Quinn "The Eskimo!"
-
- Copyright: © 1997 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- You may incorporate this sample code into your applications without
- restriction, though the sample code has been provided "AS IS" and the
- responsibility for its operation is 100% yours. However, what you are
- not permitted to do is to redistribute the source as "DSC Sample Code"
- after having made changes. If you're going to re-distribute the source,
- we require that you make it clear in the source that the code was
- descended from Apple Sample Code, but that you've made changes.
-
- =====================================================================
-
- Let me make this clear: this source was descended (sic) from Apple Sample Code,
- but I've made changes. Horrible changes.
-
- Sam Bushell
- MacHack, June 1999
- */
-
- /////////////////////////////////////////////////////////////////////
- // The OT debugging macros in <OTDebug.h> require this variable to
- // be set.
-
- #ifndef qDebug
- #define qDebug 1
- #endif
-
- /////////////////////////////////////////////////////////////////////
- // Pick up all the standard OT stuff.
-
- #include <OpenTransport.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up all the OT TCP/IP stuff.
-
- #include <OpenTptInternet.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up the OTDebugBreak and OTAssert macros.
-
- //#include <OTDebug.h>
- #define OTAssert(x,y) if(!(y)) printf(x);
-
- /////////////////////////////////////////////////////////////////////
- // Some common Mac OS prototypes.
-
- #include <Threads.h>
- #include <Files.h>
- #include <Events.h>
- #include <MacWindows.h>
- #include <Resources.h>
- #include <NumberFormatting.h>
- #include <Strings.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up SIOUXHandleOneEvent.
-
- #include <SIOUX.h>
-
- /////////////////////////////////////////////////////////////////////
- // Standard C prototypes.
-
- #include <stdio.h>
- #include <stdlib.h>
-
- /////////////////////////////////////////////////////////////////////
- // Prototypes for the actual core HTTP server code.
-
- #include "LiveFastStartServer.h"
-
- /////////////////////////////////////////////////////////////////////
- // OTDebugStr is not defined in any OT header files, but it is
- // exported by the libraries, so we define the prototype here.
-
- extern pascal void OTDebugStr(const char* str);
-
- /////////////////////////////////////////////////////////////////////
- // The only way to tell whether OT supports IP single link
- // multihoming is to check the version number. The feature was
- // added in OT 1.3. The initialisation code sets
- // gHaveIPSingleLinkMultihoming depending on the version number
- // to avoid the rest of the code having to call Gestalt repeatedly.
-
- enum
- {
- kOTIPSingleLinkMultihomingVersion = 0x01300000
- };
-
- static Boolean gHaveIPSingleLinkMultihoming = false;
-
- /////////////////////////////////////////////////////////////////////
-
- // gLastCallWNE is used to throttle calls to wait next event so that
- // we don't call it too often, which can be bad for system performance.
-
- static UInt32 gLastCallWNE = 0;
-
- // gRunningThreads contains the number of running HTTP listeners.
- // We spool an HTTP listener for each IP address on the computer.
- // Normally you would only spool one listener for the entire machine
- // (listening on kOTAnyInetAddress), but we want to actively distinguish
- // between each IP address so that we can server different information
- // for each IP address.
-
- static UInt32 gRunningThreads = 0;
-
- /////////////////////////////////////////////////////////////////////
-
- static OSErr FSpGetCatInfo(FSSpecPtr fss, short ioFDirIndex, CInfoPBPtr cpb)
- // A simple wrapper for GetCatInfo.
- {
- cpb->hFileInfo.ioVRefNum = fss->vRefNum;
- cpb->hFileInfo.ioDirID = fss->parID;
- cpb->hFileInfo.ioNamePtr = fss->name;
- cpb->hFileInfo.ioFDirIndex = ioFDirIndex;
- return ( PBGetCatInfoSync(cpb) );
- }
-
- /////////////////////////////////////////////////////////////////////
-
- static pascal OSStatus HTTPServerProc(InetHost ipAddr)
- // This routine is the main line of the thread that runs
- // an HTTP server. ipAddr is the address on which the
- // server is listening. Specify kOTAnyInetAddress to listen
- // on all active IP addresses simultaneously.
- //
- // The routine uses a directory whose name is the
- // dotted decimal string representation of ipAddr as the
- // root directory of the HTTP server.
- {
- OSStatus err;
- Str255 ipAddrString = "\pwebpages"; // hack hack hack
- long rootVRefNum;
- long rootDirID;
- FSSpec dirSpec;
- CInfoPBRec cpb;
-
- // Get ipAddr as a dotted decimal Pascal string.
- //OTInetHostToString(ipAddr, (char *) ipAddrString);
- //C2PStr( (char *) ipAddrString);
-
- // Find the associated dirID, creatintg the directory
- // if necessary.
-
- (void) FSMakeFSSpec(0, 0, ipAddrString, &dirSpec);
- rootVRefNum = dirSpec.vRefNum;
- err = FSpGetCatInfo(&dirSpec, 0, &cpb);
- if (err == noErr && ( (cpb.hFileInfo.ioFlAttrib & (1 << 4)) != 0) ) {
- rootDirID = cpb.hFileInfo.ioDirID;
- } else {
- err = FSpDirCreate(&dirSpec, 0, &rootDirID);
- }
-
- // Start running an HTTP server on the IP address. This
- // routine won't return under someone sets gQuitNow, which
- // is why we're calling it from a thread.
-
- if (err == noErr) {
- err = RunHTTPServer(ipAddr, rootVRefNum, rootDirID);
- }
-
- gRunningThreads -= 1;
-
- return (err);
- }
-
- /////////////////////////////////////////////////////////////////////
-
- static OSStatus RunOneServer(InetHost ipAddr)
- // Runs a single HTTP server thread, serving the
- // given ipAddr.
- {
- OSStatus err;
- ThreadID junkServerThread;
-
- err = NewThread(kCooperativeThread,
- (ThreadEntryProcPtr) HTTPServerProc, (void *) ipAddr,
- 0, kCreateIfNeeded,
- nil,
- &junkServerThread);
- if (err == noErr) {
- gRunningThreads += 1;
- }
-
- return (err);
- }
-
- /////////////////////////////////////////////////////////////////////
-
- static OSStatus RunServersForInterface(InetInterfaceInfo* interfaceInfo, SInt32 interfaceIndex)
- // Run HTTP servers for all of the IP addresses associated
- // with the interface denoted by interfaceInfo and interfaceIndex.
- // This routine first starts a server for the primary address
- // of the interface, then iterates through the secondary addresses on
- // the interface, starting a server thread for each one.
- {
- OSStatus err;
- InetHost *secondaryAddressBuffer;
- UInt32 numberOfSecondaryAddresses;
- UInt32 addressIndex;
-
- secondaryAddressBuffer = nil;
-
- // First run the server for the interfaces primary address.
-
- err = RunOneServer(interfaceInfo->fAddress);
-
- // Now start a server for each of the interface's secondary
- // addresses. This stuff can only be done on systems that
- // support IP single link multihoming.
-
- numberOfSecondaryAddresses = interfaceInfo->fIPSecondaryCount;
-
- if ( err == noErr && gHaveIPSingleLinkMultihoming && numberOfSecondaryAddresses > 0 ) {
-
- // Allocate a buffer for the secondary address info.
-
- secondaryAddressBuffer = (InetHost *) OTAllocMem( numberOfSecondaryAddresses * sizeof(InetHost) );
- if (secondaryAddressBuffer == nil) {
- err = kENOMEMErr;
- }
-
- // Ask OT for the list of secondary addresses on this interface.
-
- if (err == noErr) {
- err = OTInetGetSecondaryAddresses(secondaryAddressBuffer, &numberOfSecondaryAddresses, interfaceIndex);
- }
-
- // Start a server for each secondary address.
-
- addressIndex = 0;
- while (err == noErr && addressIndex < numberOfSecondaryAddresses) {
- err = RunOneServer(secondaryAddressBuffer[addressIndex]);
- if (err == noErr) {
- addressIndex += 1;
- }
- }
- }
-
- // Clean up.
-
- if (secondaryAddressBuffer != nil) {
- OTFreeMem(secondaryAddressBuffer);
- }
-
- return (err);
- }
-
- /////////////////////////////////////////////////////////////////////
-
- static OSStatus RunAllHTTPServers(void)
- // Run HTTP servers for all of the IP addresses on the machine.
- // This routine iterates through the active Internet interfaces,
- // starting server threads for each active IP address on each
- // interface.
- {
- OSStatus err;
- OSStatus junk;
- EndpointRef dummyEP;
- InetInterfaceInfo info;
- SInt32 interfaceIndex;
- Boolean done;
- TEndpointInfo epInfo;
-
- // Force TCP to load by creating a dummy endpoint. Otherwise,
- // if we're the first TCP application to run, OTInetGetInterfaceInfo
- // will not return any active interfaces )-:
-
- dummyEP = OTOpenEndpoint(OTCreateConfiguration("tcp"), 0, &epInfo, &err);
- if (err == noErr) {
-
- // Iterate through the interfaces, starting HTTP servers on each.
-
- done = false;
- interfaceIndex = 0;
- do {
- done = ( OTInetGetInterfaceInfo(&info, interfaceIndex) != noErr );
- if ( ! done ) {
- err = RunServersForInterface(&info, interfaceIndex);
- interfaceIndex += 1;
- }
- } while (err == noErr && !done);
- }
-
- if (dummyEP != nil) {
- junk = OTCloseProvider(dummyEP);
- OTAssert("RunAllHTTPServers: Failed closing dummy endpoint", junk == noErr);
- }
-
- return (err);
- }
-
-
- /////////////////////////////////////////////////////////////////////
-
- void main(void)
- // The main line of the application. This routine performs
- // two functions. At startup, it initialises the network and
- // starts HTTP servers on all the active IP addresses on the machine.
- // After that it goes into a loop calling WaitNextEvent and
- // waiting for all the listener threads to terminate. Events
- // are handled by sending them to SIOUX, except when the user
- // presses 'q' the routine sets the gQuitNow boolean to force
- // all the server threads to terminate.
- {
- OSStatus err;
- OSStatus junk;
- EventRecord event;
- // NumVersionVariant otVersion;
-
- printf("Welcome to LiveFastStartServer!\n");
- printf("-- based on OTSimpleServerHTTP, \"the world's dumbest HTTP server\".\n");
- printf("-- Press 'q' to stop the server. NOT command-Q, just 'q'.\n");
- printf("\n");
-
- gQuitNow = false;
-
- err = InitLiveMovie();
- if (err == noErr)
- err = InitGrabber();
- if (err == noErr)
- err = InitOpenTransport();
- if (err == noErr) {
-
- //gHaveIPSingleLinkMultihoming = ( Gestalt(gestaltOpenTptVersions, (long *) &otVersion) == noErr
- // && (otVersion.whole >= kOTIPSingleLinkMultihomingVersion ) );
- gRunningThreads = 0;
-
- err = RunAllHTTPServers();
-
- while ( gRunningThreads != 0 ) {
- if ( TickCount() > (gLastCallWNE + 3) ) {
- (void) WaitNextEvent(everyEvent, &event, 0, nil);
- if (event.what == keyDown) {
- if ( (event.message & charCodeMask) == 'q' ) {
- gQuitNow = true;
- printf("Setting gQuitNow.\n");
- fflush(stdout);
- }
- }
- else if( ! IsGrabberEvent( &event ) ) {
- (void) SIOUXHandleOneEvent(&event);
- }
- gLastCallWNE = TickCount();
- }
- junk = YieldToAnyThread();
- OTAssert("main: YieldToAnyThread failed", junk == noErr);
-
- IdleGrabber();
- }
-
- CloseOpenTransport();
- }
-
- if (err == noErr) {
- printf("Success.\n");
- } else {
- printf("Failed with error %d.\n", err);
- }
- KillGrabber();
- printf("Done. Press command-Q to Quit.\n");
- }
-
-
-