home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / portmngr / portlist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  12.6 KB  |  283 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/PortManager/RCS/PortList.c,v 1.72 92/10/07 18:26:03 drapeau Exp $ */
  25. /* $Log:    PortList.c,v $
  26.  * Revision 1.72  92/10/07  18:26:03  drapeau
  27.  * Made a slight change to ScanPortListForDeadApps().  Before, the function
  28.  * would remove at most one dead application from PM's internal app list
  29.  * when the function was called, even if there were more than one dead app
  30.  * at the time.  The reason this was the case was due to the way that
  31.  * PortManager checked to see if an application was running: PortManager used
  32.  * to send a Ping message to the application.  However, this would incur a wait
  33.  * until the RPC timed out, the default time being 25 seconds.  That means that
  34.  * PortManager would not be available to respond to messages for 25 seconds per
  35.  * dead application.
  36.  * However, the new method for checking if an application is alive is to try and
  37.  * create a new Sender; this function returns almost immediately, and so wastes
  38.  * typically much less than a second.  Because of this improvement, it is now
  39.  * worthwhile to have the PortManager remove all dead applications at once when
  40.  * possible.  The new code does this.
  41.  * 
  42.  * Revision 1.71  92/01/17  10:52:07  drapeau
  43.  * Modified NewPortList(); incorrect malloc() call was only allocating
  44.  * space for a pointer to a PortList, not for the PortList itself.
  45.  * 
  46.  * Revision 1.7  91/11/25  11:39:38  drapeau
  47.  * Plugged a memory leak in the PortListAddPortToList() function.  The
  48.  * function was allocating memory that was already allocated by the
  49.  * caller.
  50.  * 
  51.  * Revision 1.6  91/09/18  13:08:54  drapeau
  52.  * Minor cosmetic changes to the code.  Also, removed unused variables in the PortListPrint()
  53.  * function.
  54.  * 
  55.  * Revision 1.5  91/09/09  18:27:10  drapeau
  56.  * Changed all diagnostic messages to go through the PrintDiagnostic() routine.
  57.  * 
  58.  * Revision 1.4  91/09/03  17:02:05  drapeau
  59.  * * Made cosmetic changes to conform to coding specifications.
  60.  * * Modified ScanPortListForDeadApps() to improve performance:  previously,
  61.  *   the function called both NewSender() and SenderPing().  The latter
  62.  *   message was sent to verify not only that the application was
  63.  *   running but that it was also listening for messages.  Much testing
  64.  *   of the applications indicated that this extra test is not necessary;
  65.  *   it is enough to test if the network connection is still valid
  66.  *   (NewSender tests the validity of the network connection).  If the
  67.  *   connection is valid, that means that the receiving application is
  68.  *   still using the network port and is listening for messages.
  69.  *   SenderPing() causes problems when the receiving application is in
  70.  *   a long wait, as when the vcrEdit applicaition is waiting for the VCR
  71.  *   to search (a process that can take several minutes).  When the
  72.  *   receiving application is in such a wait, it cannot respond to the
  73.  *   SenderPing() message, and so the PortManager thinks the application
  74.  *   has stopped running.  However, since the current timeout period for
  75.  *   the RPC message is 25 seconds, the PortManager is blocked until the
  76.  *   Ping returns failure.  In short, the long search time of vcrEdit in
  77.  *   this case has caused the PortManager to be unavailable for 25 seconds.
  78.  * 
  79.  *   To fix this problem, the PortManager no longer sends the SenderPing()
  80.  *   message.  The NewSender() message typically takes only a few
  81.  *   milliseconds to complete, thereby greatly improving the performance of
  82.  *   the PortManager.
  83.  * 
  84.  * Revision 1.3  91/07/31  11:15:22  drapeau
  85.  * Minor cosmetic changes made to conform to coding standards.
  86.  * 
  87.  * Revision 1.2  91/06/17  18:14:04  drapeau
  88.  * Added copyright notice.
  89.  * 
  90.  * Revision 1.1  90/11/30  13:44:26  drapeau
  91.  * Initial revision
  92.  *  */
  93.  
  94. static char portListRcsid[] ="$Header: /Source/Media/drapeau/PortManager/RCS/PortList.c,v 1.72 92/10/07 18:26:03 drapeau Exp $";
  95.  
  96. #include <stdio.h>
  97. #include <string.h>
  98. #include "PortList.h"
  99. #include <Receiver.h>
  100. #include <sys/types.h>
  101. #include <sys/socket.h>
  102. #include <netinet/in.h>
  103. #include <arpa/inet.h>
  104. #include <netdb.h>
  105.  
  106. extern Receiver*    portMgrReceiver;
  107. extern char        diagMessage[];
  108. extern void        PrintDiagnostic(char*);
  109.  
  110. PortList* NewPortList()
  111. {
  112.   PortList*    newPortList;
  113.   
  114.   newPortList = (PortList*)malloc(sizeof(PortList));
  115.   if (newPortList == (PortList*)NULL)
  116.     return((PortList*)NULL);
  117.   newPortList->port = NULL;
  118.   newPortList->next = NULL;
  119.   return(newPortList);
  120. }                                    /* end function NewPortList */
  121.  
  122.  
  123.  
  124. void DestroyPortList(PortList* portList)
  125. {
  126.   PortList*    tempHead;
  127.   PortList*    tempNext;
  128.   
  129.   if (portList == NULL)                            /* Was the PortList passed in empty? */
  130.   {
  131.     return;                                /* Yes, don't bother trying to free up the PortList */
  132.   }
  133.   else
  134.     for (tempHead = portList; tempHead; tempHead = tempNext)        /* Traverse the PortList, deleting one member at a time */
  135.     {
  136.       tempNext = tempHead->next;                    /* Point to the next element of the list */
  137.       DestroyPort(tempHead->port);                    /* Free this element's Port structure */
  138.       free(tempHead);                            /* Free this element */
  139.     }
  140.   return;
  141. }                                    /* end function DestroyPortList */
  142.  
  143.  
  144.  
  145. void PortListAddPortToList(PortList** portListPtr, Port* newPort)
  146. {
  147.   PortList*        tempPtr;
  148.   
  149.   if (*portListPtr == NULL)                        /* Has a PortList been created yet? */
  150.   {
  151.     *portListPtr = NewPortList();                    /* Yes, get a new PortList and make it the 1st element...*/
  152.     tempPtr = *portListPtr;                        /* ...of the PortList */
  153.   }
  154.   else                                    /* No, a PortList already exists; find the end and... */
  155.   {                                    /* ...insert a new element there */
  156.     for (tempPtr = *portListPtr;                    /* Traverse the PortList until the end is reached */
  157.      tempPtr->next; tempPtr = tempPtr->next)
  158.       ;
  159.     tempPtr->next = NewPortList();                    /* Create a new element and insert it at the end of the list */
  160.     tempPtr = tempPtr->next;
  161.   }
  162.   tempPtr->port = newPort;
  163.   return;
  164. }                                    /* end function PortListAddPortToList*/
  165.  
  166.  
  167. void PortListRemovePortFromList(PortList** portListPtr,
  168.                 Port* portToRemove)
  169. {
  170.   PortList*    current;
  171.   PortList*    last;
  172.   int        found = 0;
  173.   
  174.   if (*portListPtr == NULL)                        /* Has a PortList been created yet? */
  175.     return;                                /* No, don't try to remove anything from an empty list */
  176.   current = *portListPtr; last = current;                /* Point to the beginning of the PortList */
  177.   while ((current) && (!found))                        /* Search through the list until end reached or desired... */
  178.   {                                    /* ...element is found */
  179.     if ((current->port->portNumber == portToRemove->portNumber) &&  /* Compare current Port in PortList to the Port to be... */
  180.     (strcmp(current->port->appName,                    /* ...removed.  Do they match on each attribute? */
  181.         portToRemove->appName) == 0) &&
  182.     (strcmp(current->port->hostName,
  183.         portToRemove->hostName) == 0))
  184.     {                                    /* Yes, remove the current Port from the list */
  185.       if (current == *portListPtr)                    /* Is the current Port the first in the list? */
  186.       {
  187.     *portListPtr = current->next;                    /* Yes, make the PortList point to the 2nd element now */
  188.       }
  189.       else                                /* No, re-route pointers: make the last element point... */
  190.       {                                    /* ...to the next element so the current element can be... */
  191.     last->next = current->next;                    /* ...freed from the PortList */
  192.       }
  193.       DestroyPort(current->port);
  194.       free(current);                            /* Free the current element from the PortList */
  195.       found = 1;                            /* Set a flag indicating that the desired element was found */
  196.     }                                    /* end if (current... */
  197.     else                                /* No, current element on the List was not the one desired */
  198.     {                                    /* Advance to the next element on the PortList and... */
  199.       last = current;                            /* ...update temporary pointers */
  200.       current = current->next;
  201.     }
  202.   }                                    /* end while */
  203.   return;
  204. }                                    /* end PortListRemovePortFromList */
  205.  
  206.  
  207. void PortListPrint(PortList* portList)
  208. {
  209.   PortList*        current;
  210.   
  211.   if (portList == NULL)
  212.   {
  213.     sprintf(diagMessage, "\n\n\nNo applications are currently registered.\n");
  214.     PrintDiagnostic(diagMessage);
  215.     return;
  216.   }
  217.   sprintf(diagMessage, "\n\n\nList of currently open applications:\n");
  218.   PrintDiagnostic(diagMessage);
  219.   for (current = portList; current; current = current->next)
  220.   {
  221.     sprintf(diagMessage, "App Name: %s, Host Name: %s, Port Number: %d.\n",
  222.         current->port->appName,
  223.         current->port->hostName,
  224.         current->port->portNumber);
  225.     PrintDiagnostic(diagMessage);
  226.   }                                    /* end for...*/
  227.   return;
  228. }                                    /* end PortListPrint*/
  229.  
  230.  
  231.  
  232. /********************************************************************
  233.  *    ScanPortListForDeadApps
  234.  *
  235.  *    This function scans through a list of Ports, looking for applications that are no longer listening on their
  236.  *    Receiver's for whatever reason (probably because the app is no longer running).  The function goes through the
  237.  *    list passed in as argument, and tries to check each item on the list.  If each item on the list is still
  238.  *    listening for messages, then this function will scan the whole list.  But, if one app on the list doesn't respond,
  239.  *    this function will remove its entry from the port list.
  240.  *    In addition, not too much time should be spent in this function, since it takes away from time this app should
  241.  *    be listening for messages.  So, when appropriate, this function calculates the time it has been executing; when
  242.  *    it has been executing longer than a specified time ("maxTimePassed"), the function returns.
  243.  */
  244.  
  245. void ScanPortListForDeadApps(PortList** portListPtr)            /* Takes one argument, a pointer to the head of a PortList */
  246. {
  247.   PortList*        thisPort;
  248.   Sender*        aSender;
  249.   int            result;
  250.   int            maxTimePassed = 1;                /* Max number of seconds to be spent in this func. */
  251.   struct timeval    startTime, now;                    /* Used to calculate time has spent in this func. */
  252.   
  253.   if (*portListPtr == NULL)                        /* Is the Port List empty? */
  254.     return;                                /* Yes, don't do anything; exit this function */
  255.   result = gettimeofday(&now,(struct timezone*)NULL);            /* Get current time */
  256.   if (result)                                /* Was there a problem getting the time of day? */
  257.   {                                    /* Yes, print an error and exit the program */
  258.     sprintf(diagMessage, "Could not get the time of day.  Exiting.\n");
  259.     PrintDiagnostic(diagMessage);
  260.     exit(result);
  261.   }
  262.   startTime.tv_sec = now.tv_sec;                    /* Initialize time this function started */
  263.   startTime.tv_usec = now.tv_usec;
  264.   for (thisPort = *portListPtr; thisPort; thisPort = thisPort->next) /* Traverse the list of Ports, doing the following: */
  265.   {
  266.     aSender = NewSender(thisPort->port);                /* Create a new Sender to communicate with this application */
  267.     if (aSender == (Sender*)NULL)                    /* If the creation failed, assume the application is... */
  268.     {                                    /* ...gone. */
  269.       PortListRemovePortFromList(portListPtr,thisPort->port);        /* Remove this port from the list of active ports */
  270.     }
  271.     DestroySender(aSender);                        /* Destroy Sender used to test, since it's no longer needed */
  272.     result = gettimeofday(&now,(struct timezone*)NULL);            /* Get current time for later comparison with startTime */
  273.     if (result)                                /* Was there a problem getting the time of day? */
  274.     {                                    /* Yes, print an error and exit the program */
  275.       sprintf(diagMessage, "Could not get the time of day.  Exiting.\n");
  276.       PrintDiagnostic(diagMessage);
  277.       exit(result);
  278.     }
  279.     if ((now.tv_sec - startTime.tv_sec) >= maxTimePassed)        /* Has the maximum allowed time elapsed in this function? */
  280.       return;                                /* Yes, leave this function without doing anymore checks */
  281.   }                                    /* end for (thisPort... */
  282. }                                    /* end function ScanPortListForDeadApps */
  283.