#include "esystem_osx.h"

#include "ebasicarray.h"
#include "evar.h"
#include "ethread.h"

#include <stdio.h>
//#include <MacMemory.h>

#import <Cocoa/Cocoa.h>



#import <sys/sysctl.h>
#import <mach/host_info.h>
#import <mach/mach_host.h>
#import <mach/task_info.h>
#import <mach/task.h>



#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>

#include <sys/types.h>
#include <unistd.h>
#include <mach-o/dyld.h>

//emutex callbackMutex;

esystemCallback::esystemCallback(esystemCallbackArray *_cbarr): cbarr(_cbarr),readEnabled(false),writeEnabled(false),lcount(0) {}
esystemCallback::~esystemCallback()
{
//  remove();
}

void esystemCallback::retain()
{
  ++lcount;
}

void esystemCallback::release()
{
  --lcount;
}


void esystemCallback::enableReadWrite()
{
//  callbackMutex.lock();
  if (!readEnabled)
    cbarr->enableRead();
  if (!writeEnabled)
    cbarr->enableWrite();
  readEnabled=true;
  writeEnabled=true;
//  callbackMutex.unlock();
}

void esystemCallback::enableRead()
{
//  callbackMutex.lock();
  if (!readEnabled)
    cbarr->enableRead();
  readEnabled=true;
//  callbackMutex.unlock();
}

void esystemCallback::enableWrite()
{
//  callbackMutex.lock();
  if (!writeEnabled)
    cbarr->enableWrite();
  writeEnabled=true;
//  callbackMutex.unlock();
}

void esystemCallback::disableReadWrite()
{
//  callbackMutex.lock();
  if (readEnabled)
    cbarr->disableRead();
  if (writeEnabled)
    cbarr->disableWrite();
  readEnabled=false;
  writeEnabled=false;
//  callbackMutex.unlock();
}

void esystemCallback::disableRead()
{
//  callbackMutex.lock();
  if (readEnabled)
    cbarr->disableRead();
  readEnabled=false;
//  callbackMutex.unlock();
}

void esystemCallback::disableWrite()
{
//  callbackMutex.lock();
  if (writeEnabled)
    cbarr->disableWrite();
  writeEnabled=false;
//  callbackMutex.unlock();
}

void esystemCallback::remove()
{
  disableReadWrite();
  release();
/*
  linfo("removing socket callback, cb: "+estr(this)+" fd: "+estr(cbarr->fd));
//  callbackMutex.lock();
  int i=cbarr->callbacks.find(this);
  ldieif(i==-1,"removed socket callback twice?");
  cbarr->callbacks.erase(i);
  if (cbarr->callbacks.size()==0)
    getSystem().fdCallbacks.erase(cbarr->fd);
//  callbackMutex.unlock();
*/
}


esystemCallbackArray::esystemCallbackArray(int _fd): fd(_fd),writeCount(0),readCount(0) {}
esystemCallbackArray::~esystemCallbackArray() {}

esystemSocketCallbackArray::esystemSocketCallbackArray(int fd): esystemCallbackArray(fd)
{
  CFSocketContext sContext;
  bzero(&sContext,sizeof(sContext));
  sContext.version=0;
  sContext.info=(void*)this;

//  sref = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack|kCFSocketWriteCallBack,esystem::handleSocketCallback,&sContext);
  sref = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack|kCFSocketWriteCallBack,esystem::handleSocketCallback,&sContext);
  ldieif(sref==NULL,"osxfd is NULL");

  /* Clear the close-on-invalidate flag. */
  CFOptionFlags sockopt = CFSocketGetSocketFlags(sref);
  sockopt &= ~kCFSocketCloseOnInvalidate;
  sockopt |= kCFSocketAutomaticallyReenableWriteCallBack;
  CFSocketSetSocketFlags(sref,sockopt);

  source=CFSocketCreateRunLoopSource(kCFAllocatorDefault,sref, 0);
  CFRunLoopAddSource(CFRunLoopGetMain(),source,kCFRunLoopDefaultMode);
}

esystemSocketCallbackArray::~esystemSocketCallbackArray()
{
  CFRunLoopRemoveSource(CFRunLoopGetMain(),source,kCFRunLoopDefaultMode);
  CFRunLoopSourceInvalidate(source);
  CFRelease(source);
  CFSocketInvalidate(sref);
  CFRelease(sref);
}


void esystemSocketCallbackArray::disableRead()
{
  --readCount;
  if (readCount==0)
    CFSocketDisableCallBacks(sref,kCFSocketReadCallBack);
}

void esystemSocketCallbackArray::disableWrite()
{
  --writeCount;
  if (writeCount==0)
    CFSocketDisableCallBacks(sref,kCFSocketWriteCallBack);
}

void esystemSocketCallbackArray::enableRead()
{
  ++readCount;
  if (readCount==1)
    CFSocketEnableCallBacks(sref,kCFSocketReadCallBack);
}

void esystemSocketCallbackArray::enableWrite()
{
  ++writeCount;
  if (writeCount==1)
    CFSocketEnableCallBacks(sref,kCFSocketWriteCallBack);
}


esystemFileCallbackArray::esystemFileCallbackArray(int _fd): esystemCallbackArray(_fd)
{
  CFFileDescriptorContext fdContext;
  bzero(&fdContext,sizeof(fdContext));
  fdContext.version=0;
  fdContext.info=(void*)this;

  fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, false, esystem::handleFileCallback, &fdContext);
  ldieif(fdref==NULL,"fdref is NULL");

  CFFileDescriptorEnableCallBacks(fdref,kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack);
  source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault,fdref,0);
  CFRunLoopAddSource(CFRunLoopGetMain(),source,kCFRunLoopDefaultMode);
//  CFFileDescriptorEnableCallBacks(fdref,kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack);
}

esystemFileCallbackArray::~esystemFileCallbackArray()
{
  CFRunLoopRemoveSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
  CFRelease(source);
  CFFileDescriptorInvalidate(fdref);
  CFRelease(fdref);
}

void esystemFileCallbackArray::disableRead()
{
  --readCount;
  if (readCount==0)
    CFFileDescriptorDisableCallBacks(fdref, kCFFileDescriptorReadCallBack);
}

void esystemFileCallbackArray::disableWrite()
{
  --writeCount;
  if (writeCount==0)
    CFFileDescriptorDisableCallBacks(fdref, kCFFileDescriptorWriteCallBack);
}

void esystemFileCallbackArray::enableRead()
{
  ++readCount;
  if (readCount==1)
    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
}

void esystemFileCallbackArray::enableWrite()
{
  ++writeCount;
  if (writeCount==1)
    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorWriteCallBack);
}





estrarray esystem::getLocalAddresses()
{
  estrarray tmpstr;
  struct ifaddrs * ifAddrStruct=NULL;
  struct ifaddrs * ifa=NULL;
  void * tmpAddrPtr=NULL;

  getifaddrs(&ifAddrStruct);

  for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
    if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
      // is a valid IP4 Address
      tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
      char addressBuffer[INET_ADDRSTRLEN];
      inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
      printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
      tmpstr.add(ifa->ifa_name,addressBuffer);
    }
/*
    else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
      // is a valid IP6 Address
      tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
      char addressBuffer[INET6_ADDRSTRLEN];
      inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
      printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
    }
*/
  }
  if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
  return(tmpstr);
}

estr esystem::getExecutablePath() const
{
  estr tmpstr;
  tmpstr.reserve(4096);
  uint32_t size = 4096;
  if (_NSGetExecutablePath(tmpstr._str, &size)==0){
    tmpstr._str[size]=0x00;
    tmpstr._strlen=size;
  }
  return(tmpstr);
}

estr esystem::getHostname() const
{
  estr tmpstr;
  tmpstr.reserve(1024);
  ldieif(::gethostname(tmpstr._str,1024)==-1,"unable to get hostname");
  tmpstr._strlen=strlen(tmpstr._str);
  return(tmpstr);
}

int esystem::getPID() const
{
  return(getpid());
}





long int esystem::getMemLimit()
{
  return(-1); // unlimited
}

int esystem::getTotalRam()
{
  int mib[6]; 
  mib[0] = CTL_HW;
  mib[1] = HW_PAGESIZE;

  int pagesize;
  size_t length;
  length = sizeof (pagesize);
  if (sysctl (mib, 2, &pagesize, &length, NULL, 0) < 0)
  {
    fprintf (stderr, "getting page size");
  }

  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;

  vm_statistics_data_t vmstat;
  if (host_statistics (mach_host_self (), HOST_VM_INFO, (host_info_t) &vmstat, &count) != KERN_SUCCESS)
  {
    fprintf (stderr, "Failed to get VM statistics.");
  }

//  double total = vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.free_count;
//   double wired = vmstat.wire_count / total;
//  double active = vmstat.active_count / total;
//  double inactive = vmstat.inactive_count / total;
//  double free = vmstat.free_count / total;

//  task_basic_info_64_data_t info;
//  unsigned size = sizeof (info);
//  task_info (mach_task_self (), TASK_BASIC_INFO_64, (task_info_t) &info, &size);

//  double unit = 1024 * 1024;
//  memLabel.text = [NSString stringWithFormat: @"% 3.1f MB\n% 3.1f MB\n% 3.1f MB", vmstat.free_count * pagesize / unit, (vmstat.free_count + vmstat.inactive_count) * pagesize / unit, info.resident_size / unit];
  return(((double)vmstat.wire_count+(double)vmstat.active_count+(double)vmstat.inactive_count+(double)vmstat.free_count)*(double)pagesize/1024);
}

int esystem::getFreeRam()
{
  int mib[6]; 
  mib[0] = CTL_HW;
  mib[1] = HW_PAGESIZE;

  int pagesize;
  size_t length;
  length = sizeof (pagesize);
  if (sysctl (mib, 2, &pagesize, &length, NULL, 0) < 0)
  {
    fprintf (stderr, "getting page size");
  }

  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;

  vm_statistics_data_t vmstat;
  if (host_statistics (mach_host_self (), HOST_VM_INFO, (host_info_t) &vmstat, &count) != KERN_SUCCESS)
  {
    fprintf (stderr, "Failed to get VM statistics.");
  }

  return((double)vmstat.free_count*(double)pagesize/1024);
}

int esystem::getBufferRam()
{
  int mib[6]; 
  mib[0] = CTL_HW;
  mib[1] = HW_PAGESIZE;

  int pagesize;
  size_t length;
  length = sizeof (pagesize);
  if (sysctl (mib, 2, &pagesize, &length, NULL, 0) < 0)
  {
    fprintf (stderr, "getting page size");
  }

  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;

  vm_statistics_data_t vmstat;
  if (host_statistics (mach_host_self (), HOST_VM_INFO, (host_info_t) &vmstat, &count) != KERN_SUCCESS)
  {
    fprintf (stderr, "Failed to get VM statistics.");
  }

  return((double)vmstat.inactive_count*(double)pagesize/1024);
}



esystem *esystem::cursystem=0x00;

esystem& getSystem()
{
  if (!esystem::cursystem)
    esystem::cursystem=new esystem;
  return(*esystem::cursystem);
}

esystem::esystem(): waitcb(0x00)
{
//  GetCurrentProcess(&PSN);
//  setFrontProcess();
  [NSApplication sharedApplication];
  [NSApp setDelegate: NSApp];
//  cout << "initialized esystem" << endl;
}

void esystem::setFrontProcess()
{
  const ProcessSerialNumber psn = { 0, kCurrentProcess };
  TransformProcessType(&psn, kProcessTransformToForegroundApplication);
  SetFrontProcess(&psn);
}

void esystem::handleSocketCallback(CFSocketRef sref, CFSocketCallBackType callbackTypes, CFDataRef address, const void *data, void *info)
{
//  cout << "handleSocketCallback"<<endl;
  esystemCallbackArray *cbarr=(esystemCallbackArray*)info;
  ldinfo("socket callback, fd: "+estr(cbarr->fd)+" readflag: "+estr((void *)callbackTypes));

//  callbackMutex.lock();
  for (int i=0; i<cbarr->callbacks.size(); ++i){
    esystemCallback *cb=cbarr->callbacks.at(i);
    if (cb->lcount<0) continue;
    cb->retain();
    if ((callbackTypes & kCFSocketReadCallBack) && cb->readEnabled && cb->readCallback.isSet())
      cb->readCallback.call(cb->readData);
    if ((callbackTypes & kCFSocketWriteCallBack) && cb->writeEnabled && cb->writeCallback.isSet())
      cb->writeCallback.call(cb->writeData);
    cb->release();
  }

//  callbackMutex.unlock();

  // stops the loop from running and returns if the user called the ::wait function
  esystem *psystem=&getSystem();
  if (psystem->waitcb && psystem->waitcb->cbarr==cbarr)
    CFRunLoopStop(CFRunLoopGetMain());
}

void esystem::handleFileCallback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
{
  int i;
  esystemFileCallbackArray *cbarr=(esystemFileCallbackArray*)info;

//  callbackMutex.lock();
  for (int i=0; i<cbarr->callbacks.size(); ++i){
    esystemCallback *cb=cbarr->callbacks.at(i);
    if ((callBackTypes & kCFFileDescriptorReadCallBack) && cb->readEnabled && cb->readCallback.isSet())
      cb->readCallback.call(cb->readData);
    if ((callBackTypes & kCFFileDescriptorWriteCallBack) && cb->writeEnabled && cb->writeCallback.isSet())
      cb->writeCallback.call(cb->writeData);
  }
//  callbackMutex.unlock();
  CFOptionFlags newFlags=0x00;
  if (cbarr->readCount>0)
    newFlags|=kCFFileDescriptorReadCallBack;
  if (cbarr->writeCount>0)
    newFlags|=kCFFileDescriptorWriteCallBack;
  CFFileDescriptorEnableCallBacks(cbarr->fdref, newFlags);

  // stops the loop from running and returns if the user called the ::wait function
  esystem *psystem=&getSystem();
  if (psystem->waitcb && psystem->waitcb->cbarr==cbarr)
    CFRunLoopStop(CFRunLoopGetMain());
}


void esystem::handleTimerCallback(CFRunLoopTimerRef tmref, void *info)
{
  esystemTimer *t=(esystemTimer*)info;
  t->callback.call(t->data);
// Deleting esystemTimer is a problem in the cases where the user keeps a pointer in order to delete the timer, but if the system triggers the timer, then this pointer will be invalid
// Not deleting a timer is a problem because the user might assume the timer self-deletes
// Solution: the user should always delete the timer!
// Alternative: instead of passing the user a systemTimer pointer, pass a smartpointer, then the user can check if the systemtimer is no longer valid before trying to cancel the timer event

//  if (t->repeat<=0.0l)  // if there are no more repeats delete esystemTimer
//    delete t;
  
}

esystemCallback *esystem::addSocketReadWriteCallback(int fd,const efunc& readCallback,const evararray& readData,const efunc& writeCallback,const evararray& writeData)
{
  esystemCallbackArray *cbarr;
/*
  for (int i=0; i<fdCallbacks.size(); ++i){
    cbarr=&fdCallbacks.values(i);
    for (int j=0; j<cbarr->callbacks.size(); ++j){
      if (cbarr->callbacks[j]->lcount<0){
        delete cbarr->callbacks[j];
        cbarr->callbacks.erase(j);
        --j;
      }
    }
    if (cbarr->callbacks.size()==0){
      delete cbarr;
      fdCallbacks.erase(i);
      --i;
    }
  }
*/
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemSocketCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->readCallback=readCallback;
  cb->readData=readData;
  cb->writeCallback=writeCallback;
  cb->writeData=writeData;
  cb->enableReadWrite();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutexun.lock();
  linfo("adding socket read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

esystemCallback *esystem::addSocketWriteCallback(int fd,const efunc& writeCallback,const evararray& writeData)
{
  esystemCallbackArray *cbarr;
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemSocketCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->writeCallback=writeCallback;
  cb->writeData=writeData;
  cb->enableWrite();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutex.unlock();
  linfo("adding socket read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

esystemCallback *esystem::addSocketReadCallback(int fd,const efunc& readCallback,const evararray& readData)
{
  esystemCallbackArray *cbarr;
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemSocketCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->readCallback=readCallback;
  cb->readData=readData;
  cb->enableRead();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutex.unlock();
  linfo("adding socket read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

esystemTimer::esystemTimer(): tmref(0x00) {}

esystemTimer::~esystemTimer()
{
  CFRunLoopTimerInvalidate(tmref);
}


esystemTimer *esystem::addTimer(const efunc& callback,const evararray& data,double secs,double repeat)
{
  esystemTimer *t=new esystemTimer;
  t->callback=callback;
  t->data=data;
  t->secs=secs;
  t->repeat=repeat;

  CFRunLoopTimerContext tmContext;
  bzero(&tmContext,sizeof(tmContext));
  tmContext.version=0;
  tmContext.info=(void*)t;

  t->tmref = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()+secs, repeat , 0, 0, esystem::handleTimerCallback, &tmContext);
  lassert(t->tmref==NULL);

  CFRunLoopAddTimer(CFRunLoopGetMain(), t->tmref, kCFRunLoopDefaultMode);
//  timers.addref((long int)t->tmref,t);
  return(t);
}

/*
void esystem::removeTimer(long int tid)
{
  int i;
  i=timers.findkey(tid);
  ldieif(i==-1,"timer not found with id: "+estr(tid));

  CFRunLoopTimerInvalidate(timers.values(i).tmref);
  timers.erase(i);
}
*/

esystemCallback *esystem::addReadWriteCallback(int fd,const efunc& readCallback,const evararray& readData,const efunc& writeCallback,const evararray& writeData)
{
  esystemCallbackArray *cbarr;
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemFileCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->readCallback=readCallback;
  cb->readData=readData;
  cb->writeCallback=writeCallback;
  cb->writeData=writeData;
  cb->enableReadWrite();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutex.unlock();
  linfo("adding file read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

esystemCallback *esystem::addWriteCallback(int fd,const efunc& writeCallback,const evararray& writeData)
{
  esystemCallbackArray *cbarr;
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemFileCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->writeCallback=writeCallback;
  cb->writeData=writeData;
  cb->enableWrite();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutex.unlock();
  linfo("adding file read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

esystemCallback* esystem::addReadCallback(int fd,const efunc& readCallback,const evararray& readData)
{
  esystemCallbackArray *cbarr;
  if (!fdCallbacks.exists(fd)){
    cbarr=new esystemFileCallbackArray(fd);
    fdCallbacks.addref(fd,cbarr);
  }else{
    cbarr=&fdCallbacks.values(fd);
  }

  esystemCallback *cb=new esystemCallback(cbarr);
  cb->readCallback=readCallback;
  cb->readData=readData;
  cb->enableRead();
//  callbackMutex.lock();
  cbarr->callbacks.add(cb);
//  callbackMutex.unlock();
  linfo("adding file read/write callback, cb: "+estr(cb)+" fd: "+estr(fd));
  return(cb);
}

void esystem::run()
{
  [NSApp run];
/*
  EventRef theEvent;
  EventTargetRef theTarget;

  theTarget = GetEventDispatcherTarget();
  while  (ReceiveNextEvent(0, NULL,kEventDurationForever,true,&theEvent) == noErr){
    SendEventToEventTarget (theEvent, theTarget);
    ReleaseEvent(theEvent);
  }
*/
}

void esystem::process()
{
  EventRef theEvent;
  EventTargetRef theTarget;

  theTarget = GetEventDispatcherTarget();
  while ( ReceiveNextEvent(0, NULL,0,true, &theEvent) == noErr ){
    SendEventToEventTarget (theEvent, theTarget);
    ReleaseEvent(theEvent);
  }

//  return(true);
//  CFRunLoopRunInMode(kCFRunLoopDefaultMode,0,false);
}

void esystem::wait(int fd)
{
  if (fd!=-1){
    ldieif(waitcb!=0x00,"already waiting, not allowed to call wait inside a wait");
    waitcb=addReadCallback(fd,efunc(),evararray());
    linfo("waiting: "+estr(fd)+", running loop");
  }

  CFRunLoopRun();
  linfo("ended loop");

  if (fd!=-1){
    waitcb->remove();
    waitcb=0x00;
  }
}

void esystem::waitSocket(int fd)
{
  if (fd!=-1){
    ldieif(waitcb!=0x00,"already waiting, not allowed to call wait inside a wait");
    waitcb=addSocketReadCallback(fd,efunc(),evararray());
    linfo("waiting: "+estr(fd)+", running loop: "+estr(waitcb));
  }

  CFRunLoopRun();
  linfo("ended loop");

  if (fd!=-1){
    waitcb->remove();
    waitcb=0x00;
  }
}
