// process.h
//
// bully election algorithm

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>

#define MUL 3           	// delay factor
#define PS 2            	// number of processes in the distrib. system
#define IP_LEN 15       	// max length of IP number: xxx.xxx.xxx.xxx
#define TIMEOUT 30    		// timeout interval in seconds
#define Td 5*MUL            	// at most Td seconds required for message to reach destination
#define Tr 5*MUL            	// at most Tr seconds required for processor to respond to msg
#define T (2*Td + Tr)*MUL      	// time to wait before process declared "failed"
#define TIME_TO_SLEEP 10*MUL  	// sleep between are-you-alive polls
#define MAX_LISTEN 64     	// maximum simultaneous connections to listen to
#define UNDEFINED -1
#define MSG_SIZ 16       	// maximum message size

#define SIG_START    1
#define SIG_SOFTKILL 2
#define SIG_REVIVE   3
#define SIG_HARDKILL 4

typedef enum {false,true} bool;
typedef enum {down,in_election,reorganization,normal} status_type; // election status
typedef enum {running,halted} def_type;      // state info for appl. task being performed
typedef enum {lively,softkilled,dead} ctrl_sig_type;

typedef struct {
  char address[IP_LEN];      	// address of the machine this process is running on
} PID_type;

// note that the keepalive thread is borrowing the election port this simplifies design
const int ctrl_PORT      = 11111; // port used for control signals
const int elect_PORT     = 22222; // port used for election algorithm
const int keepalive_PORT = 22222; // port used to find out if bully participants are alive
const int appalive_PORT  = 44444; // port on which the application is running

const char app_address [IP_LEN] = "129.22.16.210"; // ip of machine on which distibuted app lives
const char P0 [IP_LEN] = "129.22.16.210";   // p0 is kiss.cwru.edu
const char P1 [IP_LEN] = "129.22.16.226";  // p1 is megadeth.cwru.edu

PID_type PID [PS];       
int up [PS-1];             	// set of names of processors known to be in group
int haltid;              	// identity of processor that notified you of current election

int self;			// me
int coordinator;		// the current coordinator
status_type status;
def_type definition;
ctrl_sig_type ctrl_sig;        	// control signals 


//static pthread_mutex_t mp=PTHREAD_MUTEX_INITIALIZER;       // threads stuff (mutex)
//pthread_cond_t skill_cond=PTHREAD_COND_INITIALIZER;  // condition variable

pthread_t dapptid;        	// distributed app
pthread_t rsttid;         	// restarter thread
pthread_t apptid;         	// application restarter thread
pthread_t etid;           	// election thread id
pthread_t eetid;          	// EnterElection thread id
pthread_t ctid;           	// controller thread id

char *esend(int, char *);
void election(void);
void dapp(void);


void init(void)
{
  int i;

  ctrl_sig = lively;
  self = UNDEFINED;

  strcpy (PID [0].address, P0);  // load up the IP of first process 
  strcpy (PID [1].address, P1);  // load up IP of second process

  status = normal;
  definition = running;
  coordinator = UNDEFINED;  	// by default, coordinator is not known
  haltid = UNDEFINED;

  for (i = 0; i < PS; i++)
    up [i] = i;
}


// read from a socket but do not hang the thread while doing so
// if have not read anything in TIMEOUT seconds, return NULL
// otherwise return whatever was read from the socket.
char *waited_read(int sock, int t)
{
  int len, err;
  time_t t1, t2;
  static char buf[BUFSIZ];

  err = fcntl (sock, F_SETFL, O_NONBLOCK);  // create non-blocking socket
  t1 = time (NULL);
  do {
    t2 = time (NULL);
    bzero (buf, MSG_SIZ);
    len = read (sock, buf, BUFSIZ);
    if (len != -1) return buf;
  } while( (t2 - t1) < TIMEOUT);

  return NULL;
}

int sizeofup(void)
{
  int i,j=0;

  for(i=0;i<PS;i++)
    if(up[i]==1) j++;
  return j;
}
