/*<ATGCOPYRIGHT>
 * Copyright (C) 1997 Art Technology Group, Inc.
 * All Rights Reserved.  No use, copying or distribution of this
 * work may be made except in accordance with a valid license
 * agreement from Art Technology Group.  This notice must be
 * included on all copies, modifications and derivatives of this
 * work.
 *
 * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES 
 * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, 
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 * "Dynamo" is a trademark of Art Technology Group, Inc.
 </ATGCOPYRIGHT>*/

/* 
   CMLDRP.h - interface for CMLDRP subsystem
   ("Connection-Module Load-Distribution Request Protocol", or something)
 */


#ifndef _CMLDRP_H_
#define _CMLDRP_H_

#include <time.h>

#ifdef WIN32
/* NT */
#include <process.h>
#else
/* UNIXen */
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef _IRIX
#include <bstring.h>
#endif
#ifdef SOLARIS2_6
#include <sys/int_types.h>
#endif
#endif

#include "DRPTypes.h"
#include "DRPClient.h"

#ifdef _DRP_MTHREAD
#include "rwLocks.h"

extern RWLock gLoadDataLock;   /* defined in CMLDRP.c */
void setEnforceMaxHandlers(int flag);
void setMaxHandlers(int count);
void setBackoffInterval(time_t interval);
int acquireHandler();
void releaseHandler();

#include "io.h"   /* libw3 io.h */
#define kCMLDRP_DefaultTcpTimeout 10000  /* milliseconds */
#endif


#define kCMLDRP_DefaultTimeoutSec   3
#define kCMLDRP_DefaultTimeoutUsec  0


/*
 * These intervals used to be 1 second for the minimum poll interval and
 * 250 msec for the SleepTime.  I believe that this is because of the
 * forceUpdateCM stuff in DRPClient.c which does not work anyway.
 *
 * Instead, I think we should sleep slightly longer than the min poll 
 * interval so that we end up waking up, polling, sleeping, waking up polling
 * etc.
 */
#define kCMLDRP_MinimumPollInterval  2  /* seconds */

#define kCMLDRP_Sleeptime  2500  /* milliseconds */

#define kCMLDRP_MaxIdentifierLength   48   /* includes some extra */
#define kCMLDRP_MaxHttpHostLength     18


#define kCMLDRP_IOBufferSize   1064 /* 1018 is large enough for 100 records */
#define kCMLDRP_MaxCMLDRPRecords   kMaxDRPRecords
#define kCMLDRP_BaseResponseSize 18
#define kCMLDRP_LoadRecordSize   10


#define kCMLDRP_RequestVersion 1


/* offsets into request buffer */
#define kCMLDRP_RequestVersionOffset   0
#define kCMLDRP_RequestTypeOffset      2
#define kCMLDRP_RequestSequenceOffset  4
#define kCMLDRP_RequestIDLengthOffset  6
#define kCMLDRP_RequestIDOffset        8

/* offsets into response buffer */
#define kCMLDRP_ResponseVersionOffset     0
#define kCMLDRP_ResponseTypeOffset        2
#define kCMLDRP_ResponseSequenceOffset    4
#define kCMLDRP_ResponseFlagsOffset       6
#define kCMLDRP_ResponseNextHostOffset    8
#define kCMLDRP_ResponseNextPortOffset    12
#define kCMLDRP_ResponseIntervalOffset    14
#define kCMLDRP_ResponseNumRecsOffset     16
#define kCMLDRP_ResponseRecordOffset      18

/* offsets into load records in a buffer */
#define kCMLDRP_RecordHostOffset     0
#define kCMLDRP_RecordPortOffset     4
#define kCMLDRP_RecordProbOffset     6
#define kCMLDRP_RecordFlagsOffset    8


#define kCMLDRP_RequestType       0xDABA
#define kCMLDRP_ResponseType      0xABBA


#define kCMLDRP_DefaultCMLDRPPort    8890


#define kDrpServerFlags_Active    0x0002
#define kDrpServerFlags_AcceptingNewSessions 0x0001
#define kDrpServerFlags_Overloaded 0x0004
#define kDrpServerFlags_SeemsDown 0x0008

#define kCMLDRPFlags_Initialized  0x0001


#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN   256
#endif

#ifndef SOCKET_ERROR
#define SOCKET_ERROR     -1
#endif

/*
** The standard C library function getpid() returns the current
** process id. In the WIN32 API the equivalent function is _getpid().
*/

#ifdef WIN32
#ifndef getpid
#define getpid     _getpid
#endif
#endif

typedef struct _CMLDRP_ServerInfo   CMLDRP_ServerInfo;
typedef struct _CMLDRP_Block        CMLDRP_Block;

/* CMLDRP_ServerInfo: associates the host name with a port for a single
   CMLDRP server */
struct _CMLDRP_ServerInfo {
  char * host;
  unsigned short port;
};


/* CMLDRP_Block: block of data maintained by the CMLDRP subsystem; in the
   multithreaded case, an instance of this block will be associated with
   the CMLDRP thread via thread-local-storage (see threadabstr.h) */
struct _CMLDRP_Block {
  socket_t sock; /* used for UDP port */

#ifdef _DRP_MTHREAD
  InputStream *inputStream;  /* used for TCP input stream */
  OutputStream *outputStream; /* used for TCP output stream */
#endif

  /* numCMDLRPServers is number of records in cmldrpServers field;
     cmldrpServers is the ordered collection of CMDLRP server info passed
       in at init time
     nextServerToContactIdx is index into cmldrpServers indicating next
       CMLDRP server to contact for load info; a value of -1 indicates
       that the 1st (0th) server should be used next
     tempCMLDRPServer is a temporary storage place to hold CMLDRP server
       contact info received from a CMLDRP server that is not already 
       present in the cmldrpServers field
     nextServerToContact points to the sockaddr_in describing the next
       CMLDRP server to contact for load information; could be pointing
       at tempCMLDRPServer or into cmldrpServers
     lastTimeSilenceReported indicates the time (in seconds since the epoch)
       at which the CMLDRP system last logged the unavailability of the 
       server indicated by nextServerToContact or nextServerToContactIdx;
       NB: this value MUST be reset to zero whenever nextServerToContact[Idx]
       is updated.
       */
  struct sockaddr_in cmldrpServers[kCMLDRP_MaxCMLDRPRecords];
  int numCMLDRPServers;
  int nextServerToContactIdx;
  struct sockaddr_in tempCMLDRPServer;
  struct sockaddr_in * nextServerToContact;
  time_t lastTimeSilenceReported;

  struct timeval timeout;

  char identifier[kCMLDRP_MaxIdentifierLength];
  unsigned short identifierLength;

  char httpHost[kCMLDRP_MaxHttpHostLength];
  unsigned short httpPort;

  unsigned short pollInterval;

  time_t nextUpdateTime;

  unsigned char ioBuffer[kCMLDRP_IOBufferSize];

  unsigned short cmldrpVersion;
  unsigned short cmldrpFlags;

  unsigned short sequenceNumber;

  LogMessage_fn logFunction;
  void * logShellData;

  char debugEnabled;
};

extern CMLDRP_Block gCMLDRPBlock;
extern drpServerRecord gDrpServers[];        /* NB: not sorted */
extern drpServerRecord * gDrpServerPtrs[];   /* NB: sorted by IP:addr */
extern int gNumDrpServers;

int cmldrpInitialize(int iNumServers, CMLDRP_ServerInfo * iServers,
		     const char * iBindAddress, unsigned short iHTTPPort,
		     LogMessage_fn iLogFunction, void * iLogShellData);
void cmldrpShutdown();

void cmldrpSetDebug(int pFlag);

void cmldrpSetManagerRotationEnabled(int flag);

/* signals shutdown to the CMLDRP thread (MT only) */
extern unsigned short gCMLDRP_Shutdown;  

/* current version of DRP server load info */
extern unsigned int gCMLDRP_InfoVersion;

/* signals forced-update to CMLDRP thread (MT only) */
extern unsigned short gCMLDRP_UpdateNow;


drpServerRecord ** getDrpServerRecord(const drpServerRecord ** iServerPtrs, 
				      int iNumServers, unsigned long iAddr,
				      unsigned short iPort);
int compareDRPServerRecPtrs_ipPort(const void * iPtr1, const void * iPtr2);

CMLDRP_ServerInfo * parseDynamoManagers(char * iDynamoManagers, 
					int * oNumServers);

#ifndef _DRP_MTHREAD
int cmldrpUpdate_MP(CMLDRP_Block * pBlock);
#endif



typedef struct _DebugInfo  DebugInfo;

/* _DebugInfo: information useful during debugging */
struct _DebugInfo {
  int numRequestThreads;
  int numActiveRequests;
  int numWaitingOnReadLock;
  int numWaitingOnPool;
  int numWaitingToConnect;
  int numSendingRequest;
  int numWaitingForResponse; 
};

#endif

