home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / ntwrkprt / sender.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  30.6 KB  |  678 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/drapeau/NetworkProtocol/RCS/Sender.c,v 1.39 92/09/30 16:33:36 drapeau Exp $ */
  25. /* $Log:    Sender.c,v $
  26.  * Revision 1.39  92/09/30  16:33:36  drapeau
  27.  * Modified an error message to provide better information about where errors
  28.  * occur.
  29.  * 
  30.  * Revision 1.38  92/09/24  14:07:04  drapeau
  31.  * Modified code to support asynchronous messaging (actually, to be precise,
  32.  * the code now supports one-way RPC's, but conceptually the programmer should
  33.  * think of the messaging as non-blocking).  In Sun RPC, if an RPC call has
  34.  * a timeout value of zero, the sender will not block waiting for a return.
  35.  * To support this model, a new method was added to the Sender object, called
  36.  * "SenderAsynchronousMessaging()".  It will enable or disable synchronous
  37.  * messaging for the sender passed in as argument.  It does this by modifying
  38.  * the Sender's "timeOut" field.  Also, each message in the Sender object
  39.  * modifies a variable global to the NetworkProtocol library; this variable
  40.  * is called "SenderTimeOut" and is used by each message in the Sender class.
  41.  * When a message is sent, the responsible method first sets the SenderTimeOut
  42.  * variable to the timeOut field of the current Sender.
  43.  * Because of these changes, it is no longer necessary to create default
  44.  * timeout values when a New Sender is created (via the NewSender() method).
  45.  * Thus, the code to do so was removed.
  46.  * A final note: the "sender->timeOut" field is new to this version of the code.
  47.  * 
  48.  * Revision 1.37  92/05/29  12:40:41  drapeau
  49.  * Changed the name of the "Selection" structure to "MAESelection",
  50.  * to avoid name conflicts with other software packages and toolkits
  51.  * that might also define a "Selection" structure.
  52.  * 
  53.  * Revision 1.36  91/09/26  23:28:45  drapeau
  54.  * Two major changes:
  55.  * 1) Significant modification of SenderGetPortFromName();
  56.  * 2) Addition of a new function, SenderLaunchApplication().
  57.  * 
  58.  * SenderGetPortFromName() is extended so that if an application being
  59.  * requested is not already running, this function will now attempt to launch
  60.  * the application.  The function will wait for a period of time, then try to
  61.  * communicate with the application; if necessary, the function will retry a
  62.  * number of times until successful or until the number of retries has been
  63.  * exhausted.
  64.  * 
  65.  * SenderGetPortFromName() also allows the calling application to explicitly
  66.  * launch a new copy of the requested application, regardless of whether the
  67.  * requested application is running or not.  This was done in order to allow
  68.  * multiple copies of the same application to launch.
  69.  * 
  70.  * SenderGetPortFromName() has also been extensively commented, both before
  71.  * the function (to explain the function's algorithm) and during the code
  72.  * itself.
  73.  * 
  74.  * A new function, SenderLaunchApplication() has been added.  This function,
  75.  * written to be called by SenderGetPortFromName(), will fork a new process
  76.  * and try to exec the application whose name is passed in as argument.
  77.  * 
  78.  * Revision 1.35  91/09/18  12:51:11  drapeau
  79.  * Modified the SenderGetPortFromName() method, allowing it to receive a list of matching Ports, not
  80.  * just a single matching Port.  This was done because it is possible that an application will ask
  81.  * for all applications currently open that match a given name (e.g., if an application needs to
  82.  * communicate with several running copies of the same application).
  83.  * 
  84.  * Revision 1.34  91/09/03  16:52:05  drapeau
  85.  * Made minor cosmetic changes to code to better conform to ANSI-C definitions.
  86.  * Also, modified NewSender() to check for the validity of the hostName
  87.  * passed in as part of the senderPort paramater.  If the hostName is not
  88.  * valid, a NULL Sender* will be returned.
  89.  * 
  90.  * Revision 1.33  91/06/19  14:09:13  drapeau
  91.  * Added support for five new messages:
  92.  *  - PauseSelection
  93.  *  - ResumeSelection
  94.  *  - HideApplication
  95.  *  - ShowApplication
  96.  *  - GetAppIcon
  97.  * Also, replaced the "PerformPartialSelection" message with
  98.  * "HaltSelection" message.
  99.  * 
  100.  * 
  101.  * Revision 1.32  91/06/17  18:17:23  drapeau
  102.  * Added copyright notice.
  103.  * 
  104.  * Revision 1.31  1991/02/28  07:25:45  drapeau
  105.  * This version uses a new version numbering scheme and a new version of RCS.
  106.  * Also, several other changes:
  107.  * - Added comments at the end of functions to increase readability.
  108.  * - Modified SenderGetSelection(); it now takes a Selection** and allocates
  109.  *   space for a Selection for the caller.  This was done to provide a
  110.  *   more consistent programming interface to the Sender methods.
  111.  * - Modified SenderGetOpenApps() in a similar fashion to SenderGetSelection().
  112.  *   The method now allocates space for the Port Array for the caller.
  113.  *
  114.  * Revision 1.3  1991/02/27  03:41:07  drapeau
  115.  * Modified DestroySender() so that it frees space taken by the Sender passed
  116.  * in as argument.
  117.  *
  118.  * Revision 1.2  1990/11/30  13:54:39  drapeau
  119.  * Modified SenderGetSelection() to set duration field in selectionReturn as
  120.  * well as the start and end fields.  The previous version of this function
  121.  * incorrectly omitted the duration field.
  122.  *
  123.  * Revision 1.1  90/10/24  18:26:55  drapeau
  124.  * Initial revision
  125.  *  */
  126.  
  127. static char SenderRcsid[] = "$Header: /Source/Media/drapeau/NetworkProtocol/RCS/Sender.c,v 1.39 92/09/30 16:33:36 drapeau Exp $";
  128.  
  129. #include <stdlib.h>
  130. #include <sys/types.h>
  131. #include <sys/socket.h>
  132. #include <netdb.h>
  133. #include <string.h>
  134. #include <stdio.h>
  135. #include <Sender.h>
  136.  
  137. Sender* NewSender(Port* senderPort)
  138. {
  139.   char*            tempHostName;
  140.   struct hostent*    hostEntry;
  141.   struct sockaddr_in    remoteAddress;
  142.   Sender*        newSender;
  143.   
  144.   tempHostName = senderPort->hostName;                    /* Initialize local variables */
  145.   newSender = (Sender*)malloc(sizeof(Sender));
  146.   newSender->clientSocket = RPC_ANYSOCK;
  147.   newSender->portNumber = senderPort->portNumber;
  148.   newSender->clientPtr = (CLIENT*)NULL;
  149.   newSender->timeOut.tv_sec = 25;
  150.   newSender->timeOut.tv_usec = 0;
  151.   if (newSender->portNumber == 0)                    /* If the portNumber passed in is 0, then this...*/
  152.     {                                    /* ...Sender was not meant to be used, so...*/
  153.       return(newSender);                        /* ...just return.*/
  154.     }
  155.   if (tempHostName == (char*)NULL)                        /* Was any name passed in?*/
  156.     {
  157.       tempHostName = (char*)strdup("localhost");            /* No, set default hostname to the local host*/
  158.     }
  159.   hostEntry = gethostbyname(tempHostName);                /* Get host address from the hostname*/
  160.   if (hostEntry == (struct hostent*) NULL)                /* gethostbyname failed, print error and exit this function */
  161.   {
  162.     printf("MAEstro Protocol: Could not get host information for host named %s.\n",
  163.        tempHostName);
  164.     free(newSender);                            /* Free space taken by newSender, which is no longer valid */
  165.     return((Sender*)NULL);
  166.   }
  167.   remoteAddress.sin_port = htons(newSender->portNumber);        /* Set up remoteAddress's port number, address family,...*/
  168.   remoteAddress.sin_family = hostEntry->h_addrtype;            /* ...and Internet address.*/
  169.   bcopy(hostEntry->h_addr,
  170.     (char*)&remoteAddress.sin_addr,
  171.     hostEntry->h_length);
  172.   newSender->clientPtr = clnttcp_create(&remoteAddress,            /* Try to create connection to remote application's...*/
  173.                     MAEstro,            /* ...receiving port */
  174.                     FirstTestVersion,
  175.                     &newSender->clientSocket,
  176.                     0,0);
  177.   if (newSender->clientPtr == (CLIENT*)NULL)                /* Was the client creation successful?*/
  178.     {                                    /* No, report the error message*/
  179.       printf("MAEstro Protocol: Could not create a new Sender to communicate with\n");
  180.       printf("\t\t  Hostname:%s on Port Number:%d.\n",
  181.          tempHostName,newSender->portNumber);
  182.       free(newSender);                            /* Release space allocated for the invalid Sender */
  183.       return((Sender*)NULL);
  184.     }
  185.   return(newSender);
  186. }                                    /* end function NewSender*/
  187.  
  188.  
  189. void DestroySender(Sender* theSender)
  190. {
  191.   if (theSender != (Sender*)NULL)                    /* Was the Sender passed in valid? */
  192.     {                                    /* Yes, clean up and destroy the Sender */
  193.     clnt_destroy(theSender->clientPtr);                    /* Destroy means of communication with remote application */
  194.     close(theSender->clientSocket);                    /* Close low-level socket on which the clientPtr was based*/
  195.     free(theSender);                            /* Free space taken by the Sender */
  196.     }
  197. }                                    /* end function DestroySender */
  198.  
  199.  
  200. int SenderOpenDocument(Sender* sender, char* documentName)
  201. {
  202.   void*    returnVal = (void*)NULL;
  203.  
  204.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  205.   returnVal = opendocument_1(&documentName,sender->clientPtr);
  206.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  207.     {
  208.       return(-1);                            /* Call failed; return a non-zero result */
  209.     }
  210.   return(0);                                /* Call succeeded; return success code (0) */
  211. }                                    /* end function SenderOpenDocument */
  212.  
  213.  
  214. int SenderGetCurrentDocName(Sender* sender, char** documentNameReturn)
  215. {
  216.   char**    returnVal = (char**)NULL;
  217.   
  218.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  219.   returnVal = getcurrentdocname_1((void*)0, sender->clientPtr);
  220.   if (returnVal == (char**)NULL)                    /* Did the call fail? NULL is returned on failure */
  221.     {
  222.       return(-1);                            /* Call failed; return a non-zero result */
  223.     }
  224.   *documentNameReturn = *returnVal;                    /* Call succeeded; set up value to return to caller */
  225.   return(0);                                /* Call succeeded; return success code (0) */
  226. }                                    /* end function SenderGetCurrentDocName */
  227.  
  228.  
  229. int SenderGetSelection(Sender* sender, MAESelection** selectionReturn)
  230. {
  231.   MAESelection*    returnVal = (MAESelection*)NULL;
  232.   MAESelection*    newSelection = (MAESelection*)NULL;
  233.  
  234.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  235.   returnVal = getselection_1((void*)0,sender->clientPtr);
  236.   if (returnVal == (MAESelection*)NULL)                    /* Did the call fail? NULL is returned on failure */
  237.     {
  238.       return(-1);                            /* Call failed; return a non-zero result */
  239.     }
  240.   newSelection = (MAESelection*)malloc(sizeof(MAESelection));        /* Try to allocate space for a new MAESelection structure */
  241.   if (newSelection == (MAESelection*)NULL)                /* Did the allocation succeed? */
  242.     {                                    /* No, make the MAESelection pointer passed in point to... */
  243.       *selectionReturn = (MAESelection*)NULL;                /* ...NULL and return an error condition */
  244.       return(-1);
  245.     }
  246.   *selectionReturn = newSelection;                    /* Yes, the allocation succeeded */
  247.   newSelection->start = returnVal->start;                /* Copy returned MAESelection into... */
  248.   newSelection->end = returnVal->end;                    /* ...newly-allocated MAESelection */
  249.   newSelection->duration = returnVal->duration;
  250.   newSelection->offset = returnVal->offset;
  251.   bcopy(returnVal->label, newSelection->label, LabelLength);
  252.   return(0);                                /* Call succeeded; return success code (0) */
  253. }                                    /* end function SenderGetSelection */
  254.  
  255.  
  256. int SenderSetSelection(Sender* sender, MAESelection* selection)
  257. {
  258.   void*    returnVal = (void*)NULL;
  259.   
  260.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  261.   returnVal = setselection_1(selection,sender->clientPtr);
  262.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  263.     {
  264.       return(-1);                            /* Call failed; return a non-zero result */
  265.     }
  266.   return(0);                                /* Call succeeded; return success code (0) */
  267. }                                    /* end function SenderSetSelection */
  268.  
  269.  
  270.  
  271. int SenderPerformSelection(Sender* sender)
  272. {
  273.   void*    returnVal = (void*)NULL;
  274.   
  275.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  276.   returnVal = performselection_1((void*)0,sender->clientPtr);
  277.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  278.     {
  279.       return(-1);                            /* Call failed; return a non-zero result */
  280.     }
  281.   return(0);                                /* Call succeeded; return success code (0) */
  282. }                                    /* end function SenderPerformSelection */
  283.  
  284.  
  285.  
  286. int SenderConnectWithPortMgr(Sender* sender, Port* receivingPort)
  287. {
  288.   void*    returnVal = (void*)NULL;
  289.   
  290.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  291.   returnVal = connectwithportmgr_1(receivingPort,sender->clientPtr);
  292.   if (returnVal == NULL)                        /* Did the call fail? NULL is returned on failure */
  293.     {
  294.       return(-1);                            /* Call failed; return a non-zero result */
  295.     }
  296.   return(0);                                /* Call succeeded; return success code (0) */
  297. }                                    /* end function SenderConnectWithPortMgr */
  298.  
  299.  
  300.  
  301. int SenderGetOpenApps(Sender* sender, PortArray** openAppsReturn)
  302. {
  303.   PortArray*    returnVal = (PortArray*)NULL;
  304.   PortArray*    newPortArray = (PortArray*)NULL;
  305.  
  306.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  307.   returnVal = getopenapps_1((void*)0,sender->clientPtr);
  308.   if (returnVal == (PortArray*)NULL)                    /* Did the call fail? NULL is returned on failure */
  309.     {
  310.       *openAppsReturn = (PortArray*)NULL;                /* Point to a NULL Port Array, since the call failed */
  311.       return(-1);                            /* Call failed; return a non-zero result */
  312.     }
  313.   newPortArray = (PortArray*)malloc(sizeof(PortArray));            /* Try to allocate space for a new PortArray */
  314.   if (newPortArray == (PortArray*)NULL)                    /* Did the allocation fail? */
  315.     {                                    /* Yes, point "openAppsReturn" to a NULL PortArray and...  */
  316.       *openAppsReturn = (PortArray*)NULL;                /* ...return an error condition */
  317.       return(-1);
  318.     }
  319.   newPortArray->portArray = returnVal->portArray;            /* Point new PortArray's Port list to that returned by RPC */
  320.   newPortArray->numberOfPorts = returnVal->numberOfPorts;        /* Set new PortArray's number of Ports in the above list */
  321.   *openAppsReturn = newPortArray;                    /* Point to newly-allocated array */
  322.   return(0);                                /* Call succeeded; return success code (0) */
  323. }                                    /* end function SenderGetOpenApps */
  324.  
  325.  
  326. /******************************************************************
  327.  *    SenderGetPortFromName
  328.  *
  329.  *    This function is responsible for making sure that the
  330.  *    application specified by the "appNameAndHost" argument is
  331.  *    open and listening for messages.
  332.  *
  333.  *    The function sends a message to the Port Manager to see if
  334.  *    the requested application is already alive.  If not, this
  335.  *    function will attempt to launch the application.
  336.  *    In addition, this function allows the caller to explicitly
  337.  *    request that a new version be launched, even if one is
  338.  *    already running.  To do so, the caller must set the
  339.  *    appNameAndHost->hostName field to the defined constant
  340.  *    "LaunchNewApp".
  341.  *
  342.  *    The function returns a PortArray*, a list of Ports that
  343.  *    match the description passed in by appNameAndHost.  If
  344.  *    no matches were found and if the the desired application
  345.  *    cannot be launched, the function returns a NULL PortArray*.
  346.  *
  347.  *    The algorithm for this function is as follows:
  348.  *    First, the function sends the "GetPortFromName" message to
  349.  *    the PortManager, asking how many applications currently
  350.  *    open match the description specified by appNameAndHost.
  351.  *
  352.  *    Next, the appNameAndHost->hostName field is checked to
  353.  *    determine if the caller wants to explicitly launch a new version
  354.  *    of the requested application.  If so, the variable "numAppsOpen"
  355.  *    is set to the number of matching apps that are currently open;
  356.  *    otherwise, the variable is set to zero.
  357.  *    This variable is used later in the function.
  358.  *
  359.  *    Next, the number of matching apps is checked.  If the caller
  360.  *    does not explicitly need to launch a new copy of the app, then
  361.  *    all the function needs is one matching application.  However,
  362.  *    if the caller explicitly wants an new copy of the app opened,
  363.  *    then the function must assure that there is one more copy of the
  364.  *    requested app than when the function was called.  For example, if
  365.  *    the caller wanted an extra copy of "TextEdit" open and three
  366.  *    "TextEdit"'s were already open, then this function must assure
  367.  *    that four copies are alive before returning successfully.
  368.  *
  369.  *    If the desired number of applications are already open, then
  370.  *    the function will return the list of matches.  This will happen
  371.  *    only in the case that the caller is satisfied with any
  372.  *    version of the requested app; if the caller asked for a new copy,
  373.  *    this test will fail.  Also, if there were no matching apps, this
  374.  *    test will fail.
  375.  *
  376.  *    If the test fails, the function will try to launch a new copy of
  377.  *    the requested app, using the SenderLaunchApplication() function.
  378.  *    The function will sleep for a time, giving the new application
  379.  *    some time to start up.
  380.  *    After waiting, the function sends another GetPortFromName
  381.  *    message to the Port Manager, to see if the new application is
  382.  *    alive and listening for messages.  If so, the function will
  383.  *    return successfully.  If not, the function goes into a loop,
  384.  *    sleeping for about one second, then retrying the GetPortFromName
  385.  *    request.
  386.  *
  387.  *    Eventually, either the loop will succeed, or the number of
  388.  *    retries will be exhausted.  If the app is still not
  389.  *    running after the specified number of retries, the
  390.  *    function will return a failure code and a
  391.  *    NULL PortArray*.
  392.  */
  393.  
  394. int SenderGetPortFromName(Sender* sender,
  395.               Port* appNameAndHost,
  396.               PortArray** matchingPortsReturn)
  397. {
  398.   PortArray*    returnVal = (PortArray*)NULL;
  399.   PortArray*    newPortArray = (PortArray*)NULL;
  400.   int        result = 0;
  401.   int        numRetries = 20;
  402.   int        attemptNumber = 0;                    /* Counter variable used in re-trying GetPortFromName msg. */
  403.   int        numAppsOpen;
  404.  
  405.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  406.   returnVal = getportfromname_1(appNameAndHost,sender->clientPtr);  /* Find out how many matching apps are open */
  407.   if (returnVal == (PortArray*)NULL)                    /* Did the call fail? NULL is returned on failure */
  408.   {
  409.     perror("MAEstro Protocol: GetPortFromName message failed.");    /* Failure; report the error, return an error code... */
  410.     *matchingPortsReturn = (PortArray*)NULL;                /* ...and a NULL PortArray. */
  411.     return(-1);
  412.   }
  413.   if (appNameAndHost->hostName != (char*)NULL)                /* Check if the caller wants to force a new copy... */
  414.   {                                    /* ...of the application to be launched */
  415.     if (strcmp(appNameAndHost->hostName,LaunchNewApp) == 0)
  416.       numAppsOpen = returnVal->numberOfPorts;                /* Caller explicitly wanted a new version of the app... */
  417.     else                                /* Caller does not need a new version of the app, only... */
  418.       numAppsOpen = 0;                            /* ...one will do */
  419.   }
  420.   if (returnVal->numberOfPorts > numAppsOpen)                /* Were any matches found? */
  421.   {                                    /* Yes, return right away; no need to try any longer */
  422.     newPortArray = (PortArray*)malloc(sizeof(PortArray));        /* Try to allocate space for a new PortArray */
  423.     if (newPortArray == (PortArray*)NULL)                /* Did the allocation fail? */
  424.     {                                    /* Yes, point "openAppsReturn" to a NULL PortArray and...  */
  425.       *matchingPortsReturn = (PortArray*)NULL;                /* ...return an error condition */
  426.       return(-1);
  427.     }
  428.     newPortArray->portArray = returnVal->portArray;            /* Point new PortArray's Port list to that returned by RPC */
  429.     newPortArray->numberOfPorts = returnVal->numberOfPorts;        /* Set new PortArray's number of Ports in the above list */
  430.     *matchingPortsReturn = newPortArray;                /* Point to newly-allocated array */
  431.     return(0);                                /* Call succeeded; return success code (0) */
  432.   }                                    /* end if ((returnVal... */
  433.   result = SenderLaunchApplication(appNameAndHost->appName);        /* If this stmt. is reached, no matches were found */
  434.   if (result == -1)                            /* Did attempted launch fail? (-1 is returned on failure) */
  435.   {                                    /* Yes, failure; report the error and return an error code */
  436.     *matchingPortsReturn = (PortArray*)NULL;                /* Return a NULL PortArray, since the call failed */
  437.     return(-1);
  438.   }    
  439.   usleep(WaitTimeInMicroSeconds);                    /* Give the child a chance to launch the application */
  440.   for (attemptNumber = 1;                        /* Wait for newly-launched app to register itself with... */
  441.        attemptNumber <= numRetries;                    /* ...the Port Manager; retry 20 times sleeping,...  */
  442.        attemptNumber++)                            /* ...for 1 second between tries */
  443.   {
  444.     returnVal = getportfromname_1(appNameAndHost,            /* Ask the PortManager again if the application is...  */
  445.                   sender->clientPtr);            /* ...listening for messages */
  446.     if ((returnVal != (PortArray*)NULL) &&                /* Did the call succeed, and... */
  447.     (returnVal->numberOfPorts > numAppsOpen))            /* ...was a match found? */
  448.     {                                    /* Yes, return right away; no need to try any longer */
  449.       newPortArray = (PortArray*)malloc(sizeof(PortArray));        /* Try to allocate space for a new PortArray */
  450.       if (newPortArray == (PortArray*)NULL)                /* Did the allocation fail? */
  451.       {                                    /* Yes, point "openAppsReturn" to a NULL PortArray and...  */
  452.     *matchingPortsReturn = (PortArray*)NULL;            /* ...return an error condition */
  453.     return(-1);
  454.       }
  455.       newPortArray->portArray = returnVal->portArray;            /* Point new PortArray's Port list to that returned by RPC */
  456.       newPortArray->numberOfPorts = returnVal->numberOfPorts;        /* Set new PortArray's number of Ports in the above list */
  457.       *matchingPortsReturn = newPortArray;                /* Point to newly-allocated array */
  458.       return(0);                            /* Call succeeded; return success code (0) */
  459.     }                                    /* end if ((returnVal... */
  460.     usleep(OneSecond);                            /* Wait a short time between calls */
  461.   }                                    /* end (for attemptNumber... */
  462.   if (returnVal == (PortArray*)NULL)                    /* If this code is reached, then failure occurred */
  463.   {                                    /* This failure means the call itself failed */
  464.     perror("MAEstro Protocol: GetPortFromName message failed.");    /* Report the error, return an error code... */
  465.   }
  466.   *matchingPortsReturn = (PortArray*)NULL;                /* Return a NULL PortArray, since the call failed */
  467.   return(-1);
  468. }                                    /* end function SenderGetPortFromName */
  469.  
  470.  
  471.  
  472. int SenderPortNumber(Sender* sender)
  473. {
  474.   return(sender->portNumber);
  475. }                                    /* end function SenderPortNumber */
  476.  
  477.  
  478.  
  479. int SenderDisconnectFromPortMgr(Sender* sender, Port* appPort)
  480. {
  481.   void*    returnVal = (void*)NULL;
  482.   
  483.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  484.   returnVal = disconnectfromportmgr_1(appPort,sender->clientPtr);
  485.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  486.     {
  487.       return(-1);                            /* Call failed; return a non-zero result */
  488.     }
  489.   return(0);                                /* Call succeeded; return success code (0) */
  490. }                                    /* end function SenderDisconnectFromPortMgr */
  491.  
  492.  
  493.  
  494. int SenderPing(Sender* sender)
  495. {
  496.   void*    returnVal = (void*)NULL;
  497.   
  498.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  499.   returnVal = ping_1((void*)0, sender->clientPtr);
  500.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  501.     {
  502.       return(-1);                            /* Call failed; return a non-zero result */
  503.     }
  504.   return(0);                                /* Call succeeded; return success code (0) */
  505. }                                    /* end function SenderPing */
  506.  
  507.  
  508.  
  509. int SenderHaltSelection(Sender* sender)
  510. {
  511.   void*    returnVal = (void*)NULL;
  512.   
  513.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  514.   returnVal = haltselection_1((void*)0, sender->clientPtr);
  515.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  516.     {
  517.       return(-1);                            /* Call failed; return a non-zero result */
  518.     }
  519.   return(0);                                /* Call succeeded; return success code (0) */
  520. }                                    /* end function SenderHaltSelection */
  521.  
  522.  
  523. int SenderPauseSelection(Sender* sender)
  524. {
  525.   void*    returnVal = (void*)NULL;
  526.   
  527.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  528.   returnVal = pauseselection_1((void*)0, sender->clientPtr);
  529.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  530.     {
  531.       return(-1);                            /* Call failed; return a non-zero result */
  532.     }
  533.   return(0);                                /* Call succeeded; return success code (0) */
  534. }                                    /* end function SenderPauseSelection */
  535.  
  536.  
  537. int SenderResumeSelection(Sender* sender)
  538. {
  539.   void*    returnVal = (void*)NULL;
  540.   
  541.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  542.   returnVal = resumeselection_1((void*)0, sender->clientPtr);
  543.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  544.     {
  545.       return(-1);                            /* Call failed; return a non-zero result */
  546.     }
  547.   return(0);                                /* Call succeeded; return success code (0) */
  548. }                                    /* end function SenderResumeSelection */
  549.  
  550.  
  551. int SenderHideApplication(Sender* sender)
  552. {
  553.   void*    returnVal = (void*)NULL;
  554.   
  555.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  556.   returnVal = hideapplication_1((void*)0,sender->clientPtr);
  557.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  558.     {
  559.       return(-1);                            /* Call failed; return a non-zero result */
  560.     }
  561.   return(0);                                /* Call succeeded; return success code (0) */
  562. }                                    /* end function SenderHideApplication */
  563.  
  564.  
  565. int SenderShowApplication(Sender* sender)
  566. {
  567.   void*    returnVal = (void*)NULL;
  568.   
  569.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  570.   returnVal = showapplication_1((void*)0,sender->clientPtr);
  571.   if (returnVal == (void*)NULL)                        /* Did the call fail? NULL is returned on failure */
  572.     {
  573.       return(-1);                            /* Call failed; return a non-zero result */
  574.     }
  575.   return(0);                                /* Call succeeded; return success code (0) */
  576. }                                    /* end function SenderShowApplication */
  577.  
  578.  
  579. int SenderGetAppIcon(Sender* sender, IconData** iconDataReturn)
  580. {
  581.   IconData*    returnVal = (IconData*)NULL;
  582.   IconData*    newIconData = (IconData*)NULL;
  583.   
  584.   SenderTimeOut = &(sender->timeOut);                    /* Use the timeout value for this Sender */
  585.   returnVal = getappicon_1((void*)0,sender->clientPtr);
  586.   if (returnVal == (IconData*)NULL)                    /* Did the call fail? NULL is returned on failure */
  587.     {
  588.       return(-1);                            /* Call failed; return a non-zero result */
  589.     }
  590.   newIconData = (IconData*) malloc (sizeof (IconData));            /* Try to allocate space for a new IconData structure */
  591.   if (newIconData == (IconData*)NULL)                    /* Did the allocation succeed? */
  592.   {                                    /* No, make the IconData pointer passed in point to... */
  593.     *iconDataReturn = (IconData*)NULL;                    /* ...NULL and return an error condition */
  594.     return(-1);
  595.   }
  596.   *iconDataReturn = newIconData;                    /* Yes, the allocation succeeded */
  597.   newIconData->iconData = (char*)NULL;
  598.   newIconData->iconData = malloc(returnVal->dataLength);        /* Try to allocate space for copy of application icon */
  599.   if (newIconData->iconData == (char*)NULL)                /* Did the allocation fail? */
  600.   {                                    /* Yes, failure: */
  601.     free(newIconData);                            /* Free space taken by newIconData */
  602.     return(-1);                                /* Return an error code */
  603.   }
  604.   bcopy(returnVal->iconData,newIconData->iconData,            /* Copy icon data to the newly-allocated structure */
  605.     returnVal->dataLength);
  606.   newIconData->dataLength = returnVal->dataLength;
  607.   return(0);                                /* Call succeeded; return success code (0) */
  608. }                                    /* end function SenderGetAppIcon */
  609.  
  610.  
  611. /*******************************************************************
  612.  *    SenderLaunchApplication
  613.  *
  614.  *    This function attempts to launch the application specified
  615.  *    by the string "appName" passed in as argument.
  616.  *    The function first tries to fork a new process.  If the
  617.  *    fork is unsuccessful, and error will be printed and an
  618.  *    error code will be returned.
  619.  *    If the fork is successful, the function will then try to
  620.  *    exec the new process, using the "execlp()" function.
  621.  *    The execlp() function uses the calling environment's search
  622.  *    path to look for the application to be launched; therefore,
  623.  *    the full pathname of the application need not be known.
  624.  *    This function returns -1 if the launch failed; if the
  625.  *    launch is successful, the parent part of the fork will
  626.  *    return the process ID of the child process, and the child
  627.  *    part of the fork will not return at all (since a
  628.  *    successful exec() does not return; see the man page for
  629.  *    exec() for more details).
  630.  *
  631.  */
  632.  
  633. int SenderLaunchApplication(char* appName)
  634. {
  635.   int        processID = 0;
  636.   int        result = 0;
  637.   char        errorString[256];
  638.   
  639.   processID = fork();                            /* Try to fork and exec the new application */
  640.   if (processID == -1)
  641.   {
  642.     perror("MAEstro Protocol: Could not create a new process in which to launch the application.");
  643.     return(processID);
  644.   }
  645.   if (processID == 0)                            /* This is the child process part of the code */
  646.   {
  647.     if (appName != (char*)NULL)                        /* Try to launch the app, only if a valid app name was... */
  648.       result = execlp(appName, appName, (char*)0);            /* ..passed in as argument */
  649.     if (result == -1)                            /* Did the execlp fail? */
  650.     {                                    /* Yes, report the error and return an error code */
  651.       sprintf(errorString,
  652.           "MAEstro Protocol: Could not find the application %s to launch.\n",
  653.           appName);
  654.       perror(errorString);
  655.       return(result);
  656.     }
  657.   }                                    /* End child part of the fork */
  658.   else                                    /* This is the parent part of the fork  */
  659.     return(processID);
  660. }                                    /* end function LaunchApplication */
  661.  
  662.  
  663.  
  664. int SenderSynchronousMessaging(Sender* sender, int onOff)
  665. {
  666.   if (onOff == On)
  667.   {
  668.     sender->timeOut.tv_sec = 25;
  669.     sender->timeOut.tv_usec = 0;
  670.   }
  671.   else
  672.   {
  673.     sender->timeOut.tv_sec = 0;                        /* In Sun RPC, if the timeout value for an RPC call is zero,... */
  674.     sender->timeOut.tv_usec = 0;                    /* ...the sender will not block waiting for a return.  In... */
  675.   }                                    /* ...effect, a zero-timeout value makes RPC's non-blocking. */
  676.   return(0);
  677. }                                    /* end function SenderSynchronousMessaging */
  678.