/*
 * Distributed ticker-tape server.
 *
 * g++ -g -I/usr/local/include/sfs -I/usr/local/include ticker-server.C ticker.C -L/usr/local/lib -L/usr/local/lib/sfs -lasync -larpc -ldmalloc -o ticker-server
 */

#include "amisc.h"
#include "async.h"
#include "arpc.h"
#include "ticker.h"
#include "dns.h"

class TS {
public:
  TS::TS(int my_id, int my_port);
  void add_peer(char *hostname, int port);

private:
  int my_id;

  int ss;
  ptr<axprt> sx;
  ptr<asrv> s;

  struct peer_info {
    struct sockaddr_in sin;
    ptr<peer_info> next;
  };
  ptr<peer_info> peers;

  void do_submit(submit_args *, submit_result *);
  static void dispatch(TS *, svccb *);

  void add_peer_cb(ptr<peer_info> pi, ptr<hostent> h, int err);
};

TS::TS(int my_id, int my_port)
{
  this->my_id = my_id;

  peers = 0;

  ss = inetsocket(SOCK_DGRAM, my_port, INADDR_ANY);
  if(ss < 0){
    fprintf(stderr, "ticker-server: inetsocket failed\n");
    exit(1);
  }
  sx = axprt_dgram::alloc(ss);
  s = asrv::alloc(sx, ticker_prog_1, wrap(TS::dispatch, this));
}

void
TS::do_submit(submit_args *arg, submit_result *res) {
  printf("%s\n", (const char *) arg->msg);
  res->ok = 1;
}

void
TS::dispatch(TS *ts, svccb *sbp)
{
  submit_result submit_res;

  switch(sbp->proc()){
  case TICKER_SUBMIT:
    ts->do_submit(sbp->template getarg<submit_args> (), &submit_res);
    sbp->reply(&submit_res);
    break;
  default:
    sbp->reject(PROC_UNAVAIL);
    break;
  }
}

void
TS::add_peer_cb(ptr<peer_info> pi, ptr<hostent> h, int err)
{
  if(!h){
    fprintf(stderr, "ticker-server: could not resolve peer host name\n");
    exit(1);
  }
  pi->sin.sin_addr = *(in_addr*)h->h_addr;
  pi->next = peers;
  peers = pi;
}

void
TS::add_peer(char *hostname, int port)
{
  ref<peer_info> pi = New refcounted<peer_info> ();
  bzero(&(pi->sin), sizeof(pi->sin));
  pi->sin.sin_family = AF_INET;
  pi->sin.sin_port = htons(port);

  dns_hostbyname(hostname, wrap(this, &TS::add_peer_cb, pi), true, true);
}

main(int argc, char *argv[])
{
  if(argc < 3){
    fprintf(stderr, "Usage: ticker-server my-unique-id my-port host1 port1 ...\n");
    exit(1);
  }

  // Don't buffer the standard output.
  // This is required to make sure test-ticker.pl sees each
  // printed trade even when the output is redirected to a file.
  setlinebuf(stdout);

  TS *xxx = new TS(atoi(argv[1]), atoi(argv[2]));

  int i;
  for(i = 3; i+1 < argc; i += 2)
    xxx->add_peer(argv[i], atoi(argv[i+1]));

  amain();
}
