Example: Implementing a two-port advisor

The following example shows how to implement a two-port advisor. This custom advisor sample demonstrates the capability to detect failure for one port of a server based upon both its own status and on the status of a different server daemon that is running on another port on the same server machine.

For example, if the HTTP daemon on port 80 stops responding, you might also want to stop routing traffic to the SSL daemon on port 443.

This advisor is more aggressive than standard advisors, because it considers any server that does not send a response to have stopped functioning, and marks it as down. Standard advisors consider unresponsive servers to be very slow. This advisor marks a server as down for both the HTTP port and the SSL port based on a lack of response from either port.

To use this custom advisor, the administrator starts two instances of the advisor: one on the HTTP port, and one on the SSL port. The advisor instantiates two static global hash tables, one for HTTP and one for SSL. Each advisor tries to communicate with its server daemon and stores the results of this event in its hash table. The value that each advisor returns to the base advisor class depends on both the ability to communicate with its own server daemon and the ability of the partner advisor to communicate with its daemon.

The following custom methods are used.
The following error conditions are detected:
This sample is written to link ports 80 for HTTP and 443 for SSL, but it can be tailored to any combination of ports:
package CustomAdvisors;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Date;
import com.ibm.internet.lb.advisors.*;
import com.ibm.internet.lb.common.*; 
import com.ibm.internet.lb.manager.*; 
import com.ibm.internet.lb.server.SRV_ConfigServer; 

//-------- 
// Define the table element for the hash tables used in this custom advisor 

class ADV_nte implements Cloneable { 
  private String sCluster; 
  private int iPort; 
  private String sServer; 
  private int iLoad; 
  private Date dTimestamp; 

//-------- 
// constructor 

  public ADV_nte(String sClusterIn, int iPortIn, String sServerIn, 
                 int iLoadIn) { 
    sCluster = sClusterIn; 
    iPort = iPortIn; 
    sServer = sServerIn; 
    iLoad = iLoadIn; 
    dTimestamp = new Date(); 
  } 

//-------- 
// check whether this element is current or expired 
  public boolean isCurrent(ADV_twop oThis) { 
    boolean bCurrent; 
    int iLifetimeMs = 3 * 1000 * oThis.getInterval();     // set lifetime as 
                                                          // 3 advisor cycles 
    Date dNow = new Date(); 
    Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); 

    if (dNow.after(dExpires)) { 
      bCurrent = false; 
    } else { 
      bCurrent = true; 
    } return bCurrent; 
  } 

//-------- 
// value accessor(s) 

 public int getLoadValue() { return iLoad; } 

//-------- 
// clone (avoids corruption between threads) 

 public synchronized Object Clone() { 
   try { 
     return super.clone(); 
   } catch (cloneNotSupportedException e) { 
     return null; 
    } 
  } 

} 

//-------- 
// define the custom advisor

public class ADV_twop extends ADV_Base 
   implements ADV_MethodInterface, ADV_AdvisorVersionInterface { 
   static final int ADV_TWOP_PORT_HTTP = 80; 
   static final int ADV_TWOP_PORT_SSL = 443; 

   //-------- 
   // define tables to hold port-specific history information 

   static HashTable htTwopHTTP = new Hashtable(); 
   static HashTable htTwopSSL = new Hashtable(); 
   static final String ADV_TWOP_NAME = "twop"; 
   static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; 
   static final int ADV_TWOP_DEF_INTERVAL = 7; 
   static final String ADV_HTTP_REQUEST_STRING = 
      "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + 
      "IBM_LB_Custom_Advisor\r\n\r\n"; 

   //-------- 
   // create byte array with SSL client hello message 

   public static final byte[] abClientHello = { 
     (byte)0x80, (byte)0x1c, 
     (byte)0x01,                                // client hello 
     (byte)0x03, (byte)0x00,                    // SSL version 
     (byte)0x00, (byte)0x03,                    // cipher spec len (bytes) 
     (byte)0x00, (byte)0x00,                    // session ID len (bytes) 
     (byte)0x00, (byte)0x10,                    // challenge data len (bytes) 
     (byte)0x00, (byte)0x00, (byte)0x03,        // cipher spec
     (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20,    // challenge data
     (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, 
     (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, 
     (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; 

  //-------- 
  // constructor 

  public ADV_twop() { 
    super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT,
          ADV_TWOP_DEF_INTERVAL, "",
          false);                         // false = load balancer times the response 
    setAdvisor ( this ); 
  } 

  //-------- 
  // ADV_AdvisorInitialize 

  public void ADV_AdvisorInitialize() { 
    return; } 

  //-------- 
  // synchronized PUT and GET access routines for the hash tables 
  
  synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { 
    ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); 
    if (null != nte) { 
      nte = (ADV_nte)nte.clone(); 
    } 
    return nte;
  } 
 synchronized void putNte(Hashtable ht, String sName, String sHashKey, 
                          ADV_nte nte) { ht.put(sHashKey,nte); return; 
} 


  //-------- 
  // getLoadHTTP - determine HTTP load based on server response 

  int getLoadHTTP(int iConnectTime, ADV_Thread caller) { 
    int iLoad = ADV_HOST_INACCESSIBLE; 
    int iRc = caller.send(ADV_HTTP_REQUEST_STRING);   // send request message 
                                                    // to server 
    if (0 <= iRc) {                                 // did the request return a failure? 
      StringBuffer sbReceiveData = new StringBuffer("") // allocate a buffer 
                                                        // for the response 
      iRc = caller.receive(sbReceiveData);              // get response from server 
      
      if (0 <= iRc) {                             // did the receive return a failure? 
        if (0 < sbReceiveData.length()) {         // is data there? 
          iLoad = SUCCESS;                        // ignore retrieved data and 
                                                  // return success code 
      } 
    } 
  } 
  return iLoad; 
} 


//-------- 
// getLoadSSL() - determine SSL load based on server response 

int getLoadSSL(int iConnectTime, ASV_Thread caller) { 
  int iLoad = ADV_HOST_INACCESSIBLE; 
  int iRc; 

  CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( 
                                                  abClientHello); 
  Socket socket = caller.getSocket(); 
  
  try { 
      socket.getOutputStream().write(abClientHello); // Perform a receive. 
      socket.getInputStream().read();                // If receive is successful,
                                                     // return load of 0. We are not
                                                     // concerned with data's contents,
                                                     // and the load is calculated by 
                                                     // the ADV_Thread thread. 
      iLoad = 0; 
  } catch (IOException e) {           // Upon error, iLoad will default to it. 
  } 
  return iLoad; 
} 


//-------- 
// getLoad - merge results from the HTTP and SSL methods 

public int getLoad(int iConnectTime, ADV_Thread caller) { 
  int iLoadHTTP; 
  int iLoadSSL; 
  int iLoad; 
  int iRc; 
  
  String sCluster = caller.getCurrentClusterId();  // current cluster address 
  int iPort = getAdviseOnPort(); 
  String sServer = caller.getCurrentServerId(); 
  String sHashKey = sCluster = ":" + sServer;      // hash table key 

  if (ADV_TWOP_PORT_HTTP == iPort) {                // handle an HTTP server 
    iLoadHTTP = getLoadHTTP(iConnectTime, caller);  // get the load for HTTP 
    
    ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); 
    putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP);     // save HTTP load 
                                                       // information 
    ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey);  // get SSL 
                                                          // information
      if (null != nteSSL) { 
        if (true == nteSSL.isCurrent(this)) {              // check the time stamp 
          if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) {    // is SSL 
                                                                   // working? 
            iLoad = iLoadHTTP; 
          } else {                      // SSL is not working, so mark the HTTP server down 
            iLoad= ADV_HOST_INACCESSIBLE; 
          } 
        } else {                 // SSL information is expired, so mark the 
                                 // HTTP server down 
          iLoad = ADV_HOST_INACCESSIBLE; 
       } 
     } else {                   // no load information about SSL, report 
                                // getLoadHTTP() results 
       iLoad = iLoadHTTP; 
     } 
   } 
   else if (ADV_TWOP_PORT_SSL == iPort) {             // handle an SSL server 
     iLoadSSL = getLoadSSL(iConnectTime, caller);     // get load for SSL 
  
     ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); 
     putNte(htTwopSSL, "SSL", sHashKey, nteSSL);      // save SSL load info. 

     ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey);   // get HTTP 
                                                              // information 
     if (null != nteHTTP) { 
       if (true == nteHTTP.isCurrent(this)) {                 // check the timestamp 
         if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) {   // is HTTP 
                                                                  // working? 
           iLoad = iLoadSSL; 
         } else {             // HTTP server is not working, so mark SSL down 
           iLoad = ADV_HOST_INACCESSIBLE; 
         } 
       } else {     // expired information from HTTP, so mark SSL down 
         iLoad = ADV_HOST_INACCESSIBLE; 
       } 
     } else {                 // no load information about HTTP, report 
                              // getLoadSSL() results 
       iLoad = iLoadSSL; 
     } 
   } 

 //-------- 
 // error handler 

   else { 
     iLoad = ADV_HOST_INACCESSIBLE; 
   } 
   return iLoad; 
  } 
} 
Reference topic    

Terms and conditions for information centers | Feedback

Last updated: September 10, 2012 09:00 AM EDT
File name: rprf_advex2port.html