#include <click/config.h>
#include <click/confparse.hh>
#include <click/sync.hh>
#include <click/glue.hh>
#include <click/error.hh>
#include <click/element.hh>
#include "sockcontrol.hh"
#include <sys/types.h>
#include <sys/socket.h>
CLICK_DECLS

int SockControl :: configure(Vector<String> &conf, ErrorHandler *errh){
  int res = cp_va_parse(conf, this, errh,
    cpElement, "ToDevice element", &todev,
    cpEnd);
  if (res < 0)
    return res;
  if (todev->cast("ToDevice") != 0) {
    return 0;
  }
  return errh->error("element failed to cast as ToDevice");
}

static String
sockcontrol_get(Element *e, void *thunk)
{
    int fd = ((SockControl *)e) -> fd();
    int tmp = -1;
    socklen_t tmplen = sizeof(tmp);
    getsockopt(fd, SOL_SOCKET, (int)thunk, &tmp, &tmplen);
    return String(tmp) + "\n";
}

static int
sockcontrol_set(const String & in_s,  Element *e, void *p, ErrorHandler * errh)
{
    int fd = ((SockControl*)e) ->fd();
    int opt = (int)p;
    int val;
    if(!cp_integer(in_s, &val)) {
        return errh->error("value must be integer");
    }

    if (setsockopt(fd, SOL_SOCKET, opt, &val, sizeof(val)) < 0) {
      return errh->error("failure setting opt for socket %d", fd);
    }
    return 0;
}


void SockControl :: add_handlers() {
    add_write_handler("sndbuf", sockcontrol_set, (void *)SO_SNDBUF);
    add_read_handler("sndbuf", sockcontrol_get, (void *)SO_SNDBUF);
    add_write_handler("rcvbuf", sockcontrol_set, (void *)SO_RCVBUF);
    add_read_handler("rcvbuf", sockcontrol_get, (void *)SO_RCVBUF);
}

CLICK_ENDDECLS
EXPORT_ELEMENT(SockControl)

