home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1990, 1991 Stanford University
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that (i) the above copyright notices and this permission notice appear in
- * all copies of the software and related documentation, and (ii) the name
- * Stanford may not be used in any advertising or publicity relating to
- * the software without the specific, prior written permission of
- * Stanford.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
- * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
- * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
- /* $Header: /Source/Media/drapeau/NetworkProtocol/RCS/Receiver.c,v 1.39 92/09/13 22:43:20 drapeau Exp $ */
- /* $Log: Receiver.c,v $
- * Revision 1.39 92/09/13 22:43:20 drapeau
- * Fixed minor error in the reporting of an error creating a socket on a
- * particular port. The error message mistakenly reported that the requested
- * port number was the defined constant "PortMgrPortNumber", instead of the
- * variable "tempPortNumber" as requested.
- *
- * Revision 1.38 92/05/29 12:40:36 drapeau
- * Changed the name of the "Selection" structure to "MAESelection",
- * to avoid name conflicts with other software packages and toolkits
- * that might also define a "Selection" structure.
- *
- * Revision 1.37 91/11/25 12:59:10 drapeau
- * Two major changes:
- * 1) Cosmetic changes to default Receiver methods. They no longer print
- * a message saying that the particular method has not been implemented.
- * 2) Plugged a memory leak in DestroyReceiver(). The Port information
- * associated with the Receiver was not being de-allocated.
- *
- * Revision 1.36 91/09/26 23:22:34 drapeau
- * Modified CreateSocketOnPort() so that it takes a pointer to an integer.
- * This is so that it can return the actual port number used for the new
- * socket.
- * Also, commented CreateSocketOnPort().
- *
- * Revision 1.35 91/09/18 12:53:05 drapeau
- * - Minor changes to some error messages; they now report as "MAEstro Protocol" in keeping with the
- * project name.
- * - The name of the RPC protocol was changed from "LinkProtocol" to "MAEstro"; several changes in
- * the RPC service code were made as a result.
- * - Took out extraneous code in ReceiverGetSelection(), since the default Selection structure is
- * initialized at the beginning of the function.
- * - Modified the ReceiverGetPortFromName() method so that it returns a PortArray* instead of a Port*,
- * in keeping with the new protocol specification for this message.
- *
- * Revision 1.34 91/09/03 16:56:51 drapeau
- * Made minor cosmetic changes to enhance code readability.
- * Also, changed the definition of ReceiverGetPortFromName() so that
- * it returns a Port* instead of a void*.
- *
- * Revision 1.33 91/06/19 14:05:39 drapeau
- * Added support for five new messages:
- * - PauseSelection
- * - ResumeSelection
- * - HideApplication
- * - ShowApplication
- * - GetAppIcon
- * Also, replaced the "PerformPartialSelection" message with
- * "HaltSelection" message.
- *
- * Specifically, changes occurred in the DispatchTable structure and
- * BuildDispatchTable() function, the addition of new Receiver messages, and
- * modification of the default ReceiverGetSelection() message to return a
- * valid Selection structure with new offset and label fields filled in.
- *
- * Also, minor cosmetic changes (reformatting) of the code.
- *
- * Revision 1.32 91/06/17 18:17:20 drapeau
- * Added copyright notice.
- *
- * Revision 1.31 1991/02/28 07:17:07 drapeau
- * No code changes; this version uses a new version numbering scheme and a new
- * version of RCS.
- *
- * Revision 1.3 1991/02/27 03:39:23 drapeau
- * Changed a comment in "CreateSocketOnPort()" to accurately describe the address
- * to which is to be bound.
- *
- * Revision 1.2 90/11/30 13:58:49 drapeau
- * Modified NewReceiver() -- now, receiver structure is filled in all the time,
- * regardless of whether the Port Manager Sender is valid. This is important
- * for the PortManager application which does not create a Sender to register
- * itself (the PortManager is the authority handling registration, so it
- * should not register itself), because even though it does not have a valid
- * Sender, the Port Manager still has a Receiver and so its information
- * needs to be filled in.
- *
- * Revision 1.1 90/10/24 18:24:10 drapeau
- * Initial revision
- * */
-
- static char ReceiverRcsid[] = "$Header: /Source/Media/drapeau/NetworkProtocol/RCS/Receiver.c,v 1.39 92/09/13 22:43:20 drapeau Exp $";
-
- #include <stdio.h>
- #include <string.h>
- #include <Receiver.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
- static DispatchTable ReceiverDispatchTable =
- {
- ReceiverOpenDocument,
- ReceiverGetCurrentDocName,
- ReceiverGetSelection,
- ReceiverSetSelection,
- ReceiverPerformSelection,
- ReceiverConnectWithPortMgr,
- ReceiverGetOpenApps,
- ReceiverGetPortFromName,
- ReceiverDispatchMessage,
- ReceiverDisconnectFromPortMgr,
- ReceiverPing,
- ReceiverHaltSelection,
- ReceiverPauseSelection,
- ReceiverResumeSelection,
- ReceiverHideApplication,
- ReceiverShowApplication,
- ReceiverGetAppIcon
- };
-
- void BuildDispatchTable(DispatchTable* table)
- {
- if (table == NULL)
- return;
- if (table->openDocumentPtr)
- ReceiverDispatchTable.openDocumentPtr = table->openDocumentPtr;
- if (table->getCurrentDocNamePtr)
- ReceiverDispatchTable.getCurrentDocNamePtr = table->getCurrentDocNamePtr;
- if (table->getSelectionPtr)
- ReceiverDispatchTable.getSelectionPtr = table->getSelectionPtr;
- if (table->setSelectionPtr)
- ReceiverDispatchTable.setSelectionPtr = table->setSelectionPtr;
- if (table->performSelectionPtr)
- ReceiverDispatchTable.performSelectionPtr = table->performSelectionPtr;
- if (table->connectWithPortMgrPtr)
- ReceiverDispatchTable.connectWithPortMgrPtr = table->connectWithPortMgrPtr;
- if (table->getOpenAppsPtr)
- ReceiverDispatchTable.getOpenAppsPtr = table->getOpenAppsPtr;
- if (table->getPortFromNamePtr)
- ReceiverDispatchTable.getPortFromNamePtr = table->getPortFromNamePtr;
- if (table->dispatchMessagePtr)
- ReceiverDispatchTable.dispatchMessagePtr = table->dispatchMessagePtr;
- if (table->disconnectFromPortMgrPtr)
- ReceiverDispatchTable.disconnectFromPortMgrPtr = table->disconnectFromPortMgrPtr;
- if (table->pingPtr)
- ReceiverDispatchTable.pingPtr = table->pingPtr;
- if (table->haltSelectionPtr)
- ReceiverDispatchTable.haltSelectionPtr = table->haltSelectionPtr;
- if (table->pauseSelectionPtr)
- ReceiverDispatchTable.pauseSelectionPtr = table->pauseSelectionPtr;
- if (table->resumeSelectionPtr)
- ReceiverDispatchTable.resumeSelectionPtr = table->resumeSelectionPtr;
- if (table->hideApplicationPtr)
- ReceiverDispatchTable.hideApplicationPtr = table->hideApplicationPtr;
- if (table->showApplicationPtr)
- ReceiverDispatchTable.showApplicationPtr = table->showApplicationPtr;
- if (table->getAppIconPtr)
- ReceiverDispatchTable.getAppIconPtr = table->getAppIconPtr;
- return;
- } /* end function BuildDispatchTable */
-
-
-
- /******************************************************************
- * CreateSocketOnPort
- *
- * This function attempts to create a socket, bind an address
- * to that socket, and return that bound socket to the caller.
- * The function takes as argument a pointer to an integer.
- * The integer pointed to should contain the port number
- * being requested (this function allows the caller to
- * request a specific port number). If the port number
- * passed in as argument is set to the defined constant
- * "AnyPort", this function will let the kernel pick a port
- * number.
- * The function returns the socket descriptor, and will also
- * replace the portNumber passed in as argument with the
- * port number to which the socket is bound.
- * If the function fails, a zero (0) will be returned, and
- * the port number passed in as argument will be set to 0.
- */
-
- int CreateSocketOnPort(int* portNumber)
- {
- int newSocket;
- struct sockaddr_in address;
- int addressLength = sizeof(struct sockaddr_in);
- int result;
-
- if ((newSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) /* Try to create a new socket */
- {
- perror("MAEstro Protocol: Unable to create a socket.");
- *portNumber = 0;
- return(0);
- }
- bzero((char *)&address, sizeof (address)); /* Clear out the address to which to bind the socket */
- address.sin_family = AF_INET;
- address.sin_port = *portNumber;
- result = bind(newSocket, (struct sockaddr *)&address, /* Attempt to make the socket use the port number passed in */
- addressLength);
- if (result == -1)
- {
- perror("MAEstro Protocol: Unable to reserve the port the PortManager requests.");
- *portNumber = 0;
- return(0);
- }
- *portNumber = ntohs(address.sin_port);
- return(newSocket);
- } /* end function CreateSocketOnPort */
-
-
- Receiver* NewReceiver(Sender* portMgrSender, char* appName, int receivingPort)
- {
- Receiver* receiver;
- int transportSocket;
- int tempPortNumber = 0;
-
- tempPortNumber = receivingPort;
- receiver = (Receiver*)malloc(sizeof(Receiver));
- receiver->receiveSocket = 0; /* Initialize member variables */
- receiver->transport = (SVCXPRT*) NULL;
- receiver->createErrorCode = 0;
- receiver->receivePort.portNumber = 0;
- receiver->receivePort.appName = NULL;
- receiver->receivePort.hostName = NULL;
- pmap_unset(MAEstro, FirstTestVersion); /* Unregister this protocol with the portmapper*/
- transportSocket = CreateSocketOnPort(&tempPortNumber); /* Attempt to create a socket bound to the receivingPort */
- if (transportSocket == 0) /* Did the socket creation succeed? */
- { /* No, print an error message and return a NULL Receiver */
- fprintf(stderr,"Unable to create a new Receiver on %d.\n",
- tempPortNumber);
- return((Receiver*)NULL);
- }
- receiver->transport = svctcp_create(transportSocket,0,0); /* Attempt to create port on which to listen for messages*/
- if (receiver->transport == NULL) /* Did the attempt fail?*/
- {
- (void)fprintf(stderr, "cannot create tcp service.\n"); /* Yes, report the error and return an error code*/
- receiver->createErrorCode =1;
- }
- if (!svc_register(receiver->transport, MAEstro, /* Attempt to associate this version of the Link...*/
- FirstTestVersion, /* ...protocol with the DispatchMessage method*/
- ReceiverDispatchMessage, 0))
- {
- (void)fprintf(stderr, /* Failure -- report the error and return an error code*/
- "unable to register (MAEstro, FirstTestVersion, tcp).\n");
- receiver->createErrorCode =1;
- }
- receiver->receivePort.appName = strdup(appName); /* Fill in the name of this application*/
- receiver->receivePort.portNumber = /* Fill Port structure with info from RPC service creation*/
- receiver->transport->xp_port;
- receiver->receivePort.hostName = strdup("localhost");
- receiver->receiveSocket = receiver->transport->xp_sock;
- if (SenderPortNumber(portMgrSender) != 0) /* If the Port Manager Sender is valid, then ...*/
- { /* ...register with the Port Manager.*/
- SenderConnectWithPortMgr(portMgrSender, &(receiver->receivePort));
- }
- return(receiver);
- } /* end function NewReceiver */
-
-
-
- void DestroyReceiver(Sender* portMgrSender, Receiver* receiver)
- {
- int result = 0;
-
- if (portMgrSender) /* Was the Sender passed in valid? */
- {
- result = SenderDisconnectFromPortMgr(portMgrSender, /* Yes, tell the Port Manager "I'm outtahere" */
- &(receiver->receivePort));
- if (result != 0)
- perror("MAEstro Protocol: Could not successfully disconnect from the Port Manager.");
- }
- svc_destroy(receiver->transport); /* Destroy the RPC service data structures */
- if (receiver->receivePort.appName != (char*)NULL) /* Free space taken by Port fields. Cannot use... */
- free(receiver->receivePort.appName); /* ...DestroyPort() here, since receiver->receivePort is... */
- if (receiver->receivePort.hostName != (char*)NULL) /* allocated at compile time (i.e., not by malloc()) */
- free(receiver->receivePort.hostName);
- free(receiver); /* Free space taken by the receiver */
- return;
- } /* end function DestroyReceiver */
-
-
-
- /*******************************************************************
- * This function checks for new incoming RPC requests
- * and dispatches them. It is meant to be used by application
- * programmers who do not have a toolkit that does automatic
- * RPC dispatching (Sun's XView toolkit does RPC dispatching
- * automatically). If the programmer's toolkit does not support
- * RPC dispatching, the programmer should tell the toolkit to call
- * this function every so often (perhaps every second or so).
- */
-
- void ReceiverListenForMessages()
- {
- fd_set rpcSockets; /* Variable holding list of RPC sockets to listen... */
- /* ...on. Used as an argument to select() to determine... */
- /* ...whether there are requests on any RPC socket ... */
- /* ...waiting to be processed. */
- int descriptorTableSize = 0;
- int numSockets = 0; /* Return value from select, tells how many files had... */
- /* ...input ready to be processed. */
- struct timeval waitTime; /* Used to tell select() how long to wait until it returns */
-
- descriptorTableSize = getdtablesize(); /* Get size of descriptor table for later use by select() */
- waitTime.tv_sec = 1; /* Set up a timeval to wait for 1.0 seconds */
- waitTime.tv_usec = 0;
- rpcSockets = svc_fdset; /* Get the list of RPC sockets accepting requests */
- numSockets = select(descriptorTableSize, /* Check for input on RPC sockets */
- &rpcSockets, (int*)0,(int*)0, /* Only concerned with incoming stuff (see select() man page)*/
- &waitTime); /* Tell select how long to wait (1 second, in this case) */
- switch (numSockets) /* Based on how many sockets had input, determine what to do */
- {
- case -1: /* An error occurred */
- break; /* For now, don't do anything */
-
- case 0: /* There was no input to process */
- break;
-
- default: /* There was input to process */
- svc_getreqset(&rpcSockets); /* Handle the incoming RPC requests */
- break;
- } /* end switch */
- return;
- } /* end function ReceiverListenForMessages */
-
-
-
-
- int ReceiverGetReceiverSocket(Receiver* receiver)
- {
- return(receiver->receiveSocket);
- } /* end function ReceiverGetReceiverSocket */
-
-
-
- void ReceiverOpenDocument(char** docName)
- {
- return;
- }
-
-
-
- char** ReceiverGetCurrentDocName(void* unusedArg)
- {
- static char* returnVal = "NoDocument";
-
- return(&returnVal);
- }
-
-
-
- MAESelection* ReceiverGetSelection(void* unusedArg)
- {
- static MAESelection returnVal = {0,0,0,0,"No Label"};
-
- return(&returnVal);
- }
-
-
- void ReceiverSetSelection(MAESelection* selection)
- {
- return;
- }
-
-
- void ReceiverPerformSelection(void* unusedArg)
- {
- return;
- }
-
-
-
- void ReceiverConnectWithPortMgr(Port* app)
- {
- return;
- }
-
-
-
- PortArray* ReceiverGetOpenApps(void* unusedArg)
- {
- static PortArray returnVal;
-
- returnVal.portArray = (Port*) NULL;
- returnVal.numberOfPorts = 0;
- return(&returnVal);
- }
-
-
- PortArray* ReceiverGetPortFromName(Port* appPort)
- {
- static PortArray dummyPortArray;
-
- dummyPortArray.portArray = (Port*) NULL;
- dummyPortArray.numberOfPorts = 0;
- return(&dummyPortArray);
- }
-
-
- void ReceiverDisconnectFromPortMgr(Port* appPort)
- {
- appPort->portNumber = 0; /* Fill in a dummy value*/
- return;
- }
-
-
- void ReceiverPing(void* unusedArg)
- {
- return;
- }
-
-
- void ReceiverHaltSelection(void* unusedArg)
- {
- return;
- }
-
-
- void ReceiverPauseSelection(void* unusedArg)
- {
- return;
- }
-
-
-
- void ReceiverResumeSelection(void* unusedArg)
- {
- return;
- }
-
-
-
- void ReceiverHideApplication(void* unusedArg)
- {
- return;
- }
-
-
-
- void ReceiverShowApplication(void* unusedArg)
- {
- return;
- }
-
-
-
- IconData* ReceiverGetAppIcon(void* unusedArg)
- {
- static IconData returnVal;
-
- returnVal.dataLength = 0;
- returnVal.iconData = (char*) NULL;
- return(&returnVal);
- }
-
-
- void ReceiverDispatchMessage(struct svc_req* requestPtr, SVCXPRT* transport)
- {
- union
- {
- char* opendocument_1_arg;
- MAESelection setselection_1_arg;
- Port connectwithportmgr_1_arg;
- Port getportfromname_1_arg;
- Port disconnectfromportmgr_1_arg;
- } argument;
- char* result;
- char* (*local)();
- bool_t (*xdr_argument)();
- bool_t (*xdr_result)();
- bool_t replyResult;
-
- switch (requestPtr->rq_proc) /* Determine what procedure is being requested*/
- {
- case NULLPROC:
- (void)svc_sendreply(transport, xdr_void, (char *)NULL);
- return;
-
- case OpenDocumentProc:
- xdr_argument = xdr_wrapstring;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.openDocumentPtr;
- break;
-
- case GetCurrentDocNameProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_wrapstring;
- local = (char *(*)()) ReceiverDispatchTable.getCurrentDocNamePtr;
- break;
-
- case GetSelectionProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_MAESelection;
- local = (char *(*)()) ReceiverDispatchTable.getSelectionPtr;
- break;
-
- case SetSelectionProc:
- xdr_argument = xdr_MAESelection;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.setSelectionPtr;
- break;
-
- case PerformSelectionProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.performSelectionPtr;
- break;
-
- case ConnectWithPortMgrProc:
- xdr_argument = xdr_Port;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.connectWithPortMgrPtr;
- break;
-
- case GetOpenAppsProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_PortArray;
- local = (char *(*)()) ReceiverDispatchTable.getOpenAppsPtr;
- break;
-
- case GetPortFromNameProc:
- xdr_argument = xdr_Port;
- xdr_result = xdr_PortArray;
- local = (char *(*)()) ReceiverDispatchTable.getPortFromNamePtr;
- break;
-
- case DisconnectFromPortMgrProc:
- xdr_argument = xdr_Port;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.disconnectFromPortMgrPtr;
- break;
-
- case PingProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.pingPtr;
- break;
-
- case HaltSelectionProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.haltSelectionPtr;
- break;
-
- case PauseSelectionProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.pauseSelectionPtr;
- break;
-
- case ResumeSelectionProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.resumeSelectionPtr;
- break;
-
- case HideApplicationProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.hideApplicationPtr;
- break;
-
- case ShowApplicationProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_void;
- local = (char *(*)()) ReceiverDispatchTable.showApplicationPtr;
- break;
-
- case GetAppIconProc:
- xdr_argument = xdr_void;
- xdr_result = xdr_IconData;
- local = (char *(*)()) ReceiverDispatchTable.getAppIconPtr;
- break;
-
- default:
- svcerr_noproc(transport);
- return;
- } /* end switch (requestPtr->rq_proc)*/
- bzero((void *)&argument, sizeof(argument));
- if (!svc_getargs(transport, xdr_argument, (char*)&argument))
- {
- svcerr_decode(transport); /* Determine if there were errors retrieving the argument*/
- return;
- }
- result = (*local)(&argument, requestPtr); /* Call the function requested*/
- if (result != NULL || /* Determine whether there's a reply to send; if a result... */
- xdr_result == xdr_void) /* ...was returned, or if the called function returns... */
- replyResult = svc_sendreply(transport, xdr_result, result); /* ...void, then try to reply to the remote procedure caller */
- else /* If this stmt is reached, then result must've been NULL... */
- { /* ...and xdr_result was supposed to return data, not... */
- if (result == NULL) /* ...just NULL. This shouldn't happen, and is an error. */
- printf("Message was received but there was an error performing the message.\n");
- return;
- }
- if (replyResult == FALSE) /* Was the reply done, and Did it succeed? */
- {
- svcerr_systemerr(transport); /* No, report an error */
- printf("There was an error performing a received message.\n");
- }
- if (!svc_freeargs(transport, xdr_argument, (char*)&argument)) /* Free space taken by the function argument*/
- {
- (void)fprintf(stderr, "unable to free arguments\n");
- }
- } /* end ReceiverDispatchMessage*/
-