/* squidClass.cpp */
//DEBUG: section 91

#include "squid.h"

 #define INCL_DOS
 #include <os2.h>

char * GetOS2ErrorMessage(int ierr);

int squid_fde::GetSocket(void)
{
   if(type != FD_SOCKET)
   {  debug(91, 0) ("squid_fde: WARNING: GetSocket for type != FD_SOCEKET(%i)\n",type);
      return -1;
   }
   return fh;
}

int squid_fde::GetFileHandle(void)
{
   if(type == FD_SOCKET)
   {  debug(91, 0) ("squid_fde: WARNING: GetFileHandle for type = FD_SOCKET\n");
      return -1;
   } else if(type == FD_NONE) {
      debug(91, 0) ("squid_fde: WARNING: GetFileHandle for type = FD_NONE\n");
      return -1;
   }
   return fh;
}

void squid_fde::sFD_SET(fd_set *readfds)
{
   if(type != FD_SOCKET)
   {  debug(91, 0) ("squid_fde: WARNING: FD_SET for type != FD_SOCKET(%d)\n",type);
      return;
   }
    FD_SET(fh,readfds);
}

void squid_fde::sFD_CLR(fd_set *readfds)
{
   if(type != FD_SOCKET)
   {  debug(91, 0) ("squid_fde: WARNING: FD_CLR for type != FD_SOCKET(%d)\n",type);
      return;
   }

   FD_CLR(fh,readfds);
}
int squid_fde::sFD_ISSET(fd_set *readfds)
{
   if(type != FD_SOCKET)
   {  debug(91, 0) ("squid_fde: WARNING: FD_ISSET for type != FD_SOCKET(%d)\n",type);
      return 0;
   }
     return FD_ISSET(fh,readfds);
}

int squid_fde::write(char *buf, int len)
{  int rc=-1;

//int _EvgSockList[2048];
//int NumsockListWrite = 5,num;

   if(fh < 0)
      fatalf("Attempt to Write with uninitialized handle %i bytes", len);

   switch(type)
   {  case FD_SOCKET:

//     num = select( _EvgSockList,0, NumsockListWrite,0, 100);
          if(fh < 0)
          {  debug(91, 0) ("squid_fde::write WARNING: fh=%i\n",fh);
             rc = -1;
             break;
          }
          rc = send(fh, (char *)buf, len,0 /* MSG_DONTWAIT ? */);
          if(rc < 0)
          {   debug(91, 3) ("squid_fde::write(send) %i len failed\n",len);
          }
          break;
      case FD_NONE:
             fatalf("Attempt to Write with FD_NONE type handle %i bytes", len);
           return -1;
      case FD_PIPE:
      case FD_PIPE_WRITE:
/*************************************/
      { ULONG  Type, Attr;
        int     rc1;   /*  Return Code. */

        rc1 = DosQueryHType(fh, &Type, &Attr);
        if(rc1)
        {    fatalf("WARNING:squid_fde::write error %d %s", rc, GetOS2ErrorMessage(rc) );
        } else {
          rc = ::write(fh, buf, len);
        }
      }
          break;
/*************************************/

      default:
           rc = ::write(fh, buf, len);
  }
  if(rc>0) bytes_written += rc;
  return rc;
}


int squid_fde::read(char *buf, int len)
{  int rc=-1;
   if(fh < 0)
      fatalf("Attempt to Read with uninitialized handle %i bytes", len);
   if(len <= 0)
   {  debug(91, 0) ("squid_fde::read WARNING: Attempt to read %i bytes, type=%i\n",len,type);
   }
   switch(type)
   {  case FD_SOCKET:
          if(fh < 0)
          {  debug(91, 0) ("squid_fde::read WARNING: fh=%i\n",fh);
             rc = -1;
             break;
          }
         rc = recv(fh, buf, len, 0 /* MSG_DONTWAIT ? */);
          break;
      case FD_NONE:
             fatalf("Attempt to Read with FD_NONE type handle %i bytes", len);
           return -1;
      case FD_PIPE:
      case FD_PIPE_READ:
/*************************************/
      { ULONG Type, Attr;
        int     rc1;   /*  Return Code. */

        rc1 = DosQueryHType(fh, &Type, &Attr);
        if(rc1)
        {    fatalf("WARNING:squid_fde::read error %d %s", rc, GetOS2ErrorMessage(rc) );
        } else {
          rc = ::read(fh, buf, len);
        }
      }
/*************************************/
          break;
      default:
          rc = ::read(fh, buf, len);
  }
  if(rc>0) bytes_read += rc;
  return rc;
}

int squid_fde::close(void)
{  int rc = -1;

  switch(type)
   {
//////////////////////////////////////////
      case FD_SOCKET:
      {
/*     extern fd_set global_readfds;
       extern fd_set global_writefds;
       extern int nreadfds;
       extern int nwritefds;

        if (FD_ISSET(fh, &global_readfds))
       {       FD_CLR(fh, &global_readfds);
               nreadfds--;
       }
       if (FD_ISSET(fh, &global_writefds))
       {       FD_CLR(fh, &global_writefds);
               nwritefds--;
       }
*/
      if(fh <0) debug(91, 0) ("WARNING:squid_fde::close: soclose(%i)\n",fh);
      else
      {       rc = soclose(fh);
      }
     debug(91, 6) ("squid_fde::close: soclose(%i), rc = %i\n",fh,rc);

       }
      break;
//////////////////////////////////////////
      case FD_NONE:
           if(fh == -1) /* already deleted */
                return 0;
           fatalf("Attempt to close with FD_NONE type handle");
           return rc;
      default:
       assert(read_handler == NULL);
       assert(write_handler == NULL);

            rc = ::close(fh);
  }
  flags.open = 0;
  timeout = 0;
  type = FD_NONE;
    read_handler  = 0; //необязательно ?
    write_handler = 0;//необязательно ?
    timeout_handler = 0;
    close_handler = 0;
    bytes_read = bytes_written = 0;
    memset((void *)&disk,0,sizeof(disk));
  memset((void *)&flags,0,sizeof(flags));
    desc[0] = 0;
    read_data =0;
    write_data=0;
    timeout_data = 0;
    defer_data = 0;
    defer_check = NULL;
    rwstate     = NULL;
    uses = 0;
#if USE_SSL
    ssl = NULL;
    ssl_shutdown = 0;
#endif
  fh = -1;
  return rc;
}

int squid_fde::check()
{   int rc = 0;
    if(fh < 0)
       return -1;
}

/* really not open */
int squid_fde::open(const char *_desc)
{
    if (_desc)
       xstrncpy(desc, _desc, FD_DESC_SZ);
   bytes_read = bytes_written = 0;
   local_port = remote_port = 0;

   memset((void *)&local_addr,0,sizeof(local_addr));
   memset((void *)&flags,0,sizeof(flags));
   flags.open = 1;
   memset((void *)&disk,0,sizeof(disk));
   switch(type)
   {  case FD_SOCKET:
        //
            break;
      case FD_NONE:
             fatalf("Attempt to open with FD_NONE type handle");
           return -1;
      default:
           break;
  }
  return 0;
}

int  squid_fdeArray::Add(int fh, int type)
{   int i,is;
       if(type == FD_NONE)
       {  debug(90, 0) ("squid_fdeArray Add: WARNING: type FD_NONE\n");
          return -1;
       }
       if(fd_table[iCurrent].type == FD_NONE)
       { if(iCurrent == 0 && n == 0) n++;
         else if(iCurrent >= n)
         {   if(iCurrent > n +8) goto SEARCH_FREE;  /* We don't like to make sparse array */
              n = iCurrent+1;
             if(n +8 > nAllocated ) goto SEARCH_FREE;  /*  Array almost full ? */
         }
       } else
           if( iCurrent > 0 && fd_table[iCurrent-1].type == FD_NONE) {
           iCurrent--;
       } else
           if( iCurrent < n-1 && fd_table[iCurrent+1].type == FD_NONE) {
           iCurrent++;
       } else
           if( n < nAllocated-8 /* 1 */ && fd_table[n].type == FD_NONE) {
           iCurrent = n++;
       } else {
SEARCH_FREE:
         is = 0;
         for(i=0;i<n;i++)
         {   if(fd_table[i].type == FD_NONE)
             { is = 1;
               iCurrent = i;
               break;
             }
         }
         if(!is)
         {    fatalf("Out of filedescriptors, please increase SQUID_MAXFD (%i)", SQUID_MAXFD);
              return -1;
         }
       }

       if(fd_table[iCurrent].type == FD_SOCKET)
       {  SocketToIndex[fd_table[iCurrent].GetSocket()] = -1;
       }

       fd_table[iCurrent].Change(fh,type);

       if(fd_table[iCurrent].type == FD_SOCKET)
       {  if(fh > NumSocketToIndex)
          {  int n1, *npSTI;
             n1 = fh+16;
             npSTI = (int *) xrealloc(SocketToIndex, n1 * sizeof(int));
             if(npSTI == NULL)
             { debug(90, 0) ("squid_fdeArray::Add: WARNING: can't realloc SocketToIndex for %i sockets\n", n1);
               fatalf("squid_fdeArray::Add no memory ???");
             }
             SocketToIndex = npSTI;
             for(i=NumSocketToIndex; i < n1; i++) SocketToIndex[i] = -1;
             NumSocketToIndex = n1;
          }
          SocketToIndex[fh] = iCurrent;
          if(fh > MaxSocket) 
          {  if(MaxSocket == -1) MinSocket = fh;   
             MaxSocket = fh;
          }   
          if(fh < MinSocket) MinSocket = fh;
       }
       if(type == FD_PIPE_READ)
                  AddPipe(iCurrent, FD_PIPE_READ);
       if(type == FD_PIPE_WRITE)
                  AddPipe(iCurrent, FD_PIPE_WRITE);

       return iCurrent;
}

int squid_fdeArray::AddPipe(int index, int type)
{  int rc;
   if(QueryPipe(index, 0x7))
              return 1;
   if(NumPipes >= 256)
              return 2;
   listPipes[NumPipes].index = index;
   listPipes[NumPipes].type =  0x04;
   if(type ==  FD_PIPE_READ)
          listPipes[NumPipes].type |=  0x01;
   if(type ==  FD_PIPE_WRITE)
          listPipes[NumPipes].type |=  0x02;
   NumPipes++;
   return 0;
}

int squid_fdeArray::DelPipe(int index)
{  int i,rc;
   rc = QueryPipe(index, 0x7);
   if(!rc)
              return 1;
   rc--; /* rc = index+1 */
   for(i=rc;i< NumPipes-1;i++)
          listPipes[i] = listPipes[i+1];
   NumPipes--;
   return 0;
}


void squid_fdeArray::sFD_SET(int index, fd_set *readfds)
   {
       if(index < 0 || index > n)
       {  debug(90, 0) ("squid_fdeArray sFD_SET: WARNING: bad index %i\n", index);
          return;
       }
       if(readfds == NULL)
       {  debug(90, 0) ("squid_fdeArray sFD_SET: WARNING: bad pointer readfds!\n");
          return;
       }
       if(fd_table[index].type != FD_SOCKET)
       {  debug(90, 0)
            ("squid_fdeArray sFD_SET: WARNING: fd_table[%i].type != FD_SOCKET(%i!=%i)i'\n",
             index,fd_table[index].type,FD_SOCKET);
          return;
       }
       fd_table[index].sFD_SET(readfds);
   }

int squid_fdeArray::sFD_ISSET(int index, fd_set *readfds, int id)
   {
       if(index < 0 || index > n)
       {  debug(90, 0) ("squid_fdeArray sFD_ISSET: WARNING: bad index %i, n=%i, id=%i\n", index, n, id);
          return 0;
       }
       if(readfds == NULL)
       {  debug(90, 0) ("squid_fdeArray sFD_ISSET: WARNING: bad pointer readfds!\n");
          return 0;
       }
       if(fd_table[index].type != FD_SOCKET)
       {  debug(90, 0)
            ("squid_fdeArray sFD_ISSET: WARNING: fd_table[%i].type != FD_SOCKET(%i!=%i), id=%i'\n",
             index,fd_table[index].type,FD_SOCKET, id);
          return 0;
       }
       return fd_table[index].sFD_ISSET(readfds);
   }

void squid_fdeArray::sFD_CLR(int index, fd_set *readfds)
   {   if(index < 0 || index > n)
       {  debug(90, 0) ("squid_fdeArray sFD_CLR: WARNING: bad index %i\n", index);
          return;
       }
       if(readfds == NULL)
       {  debug(90, 0) ("squid_fdeArray sFD_CLR: WARNING: bad pointer readfds!\n");
          return;
       }
       if(fd_table[index].type != FD_SOCKET)
       {  debug(90, 0)
            ("squid_fdeArray sFD_CLR: WARNING: fd_table[%i].type != FD_SOCKET(%i!=%i)i'\n",
             index,fd_table[index].type,FD_SOCKET);
          return;
       }
       fd_table[index].sFD_CLR(readfds);
   }

int squid_fdeArray::open(int &index,int fh, unsigned int type, const char *desc)
   { int rc;
     index = 0;
     rc = Add(fh, type);
     if(rc < 0) return -1;
     index = rc;
     fd_table[index].open(desc);
     Number_FD++;
     debug(91, 6)
     ("squid_fdeArray::open:fh %d->%d type %i %s\n",fh,index,type,desc);
     debug(91, 7) /* squid_fdeArray::open: */
     ("iCurrent %i Number_FD %i\n",iCurrent,Number_FD);
     return 0;
   }

int squid_fdeArray::check(int index, int number)
{  int rc;
    if(index < 0 || index > n)
    {  debug(91, 0) ("squid_fdeArray check: WARNING: bad index %i,n=%i,num=%i\n", index, n, number);
       return 1;
    }
    if(fd_table[index].type == FD_NONE)
    {  debug(91, 0) ("squid_fdeArray check: WARNING: bad type for index %i,num=%i\n", index,  number);
       return 2;
    }
    if(fd_table[index].check() < 0)
    {  debug(91, 0) ("squid_fdeArray check: WARNING: bad handle %i for index %i,num=%i\n",  index,  number);
       return 2;
    }
    return 0;
}

int squid_fdeArray::checkSocket(int index, int number)
{  int rc;
    if(index < 0 || index > n)
    {  debug(91, 0) ("squid_fdeArray checkSocket: WARNING: bad index %i,n=%i,num=%i\n", index, n, number);
       return 1;
    }
    if(fd_table[index].type != FD_SOCKET)
    {  debug(91, 0) ("squid_fdeArray checkSocket: WARNING: non-FD_SOCKET type %i for index %i,num=%i\n", fd_table[index].type, index,  number);
       return 2;
    }
    if(fd_table[index].check() < 0)
    {  debug(91, 0) ("squid_fdeArray checkSocket: WARNING: bad handle %i for index %i,num=%i\n",  index,  number);
       return 2;
    }
    return 0;
}

int squid_fdeArray::close(int index)
{  int rc;
    if(index < 0 || index > n)
    {  debug(91, 0) ("squid_fdeArray close: WARNING: bad index %i\n", index);
       return -1;
    }

    if(fd_table[index].type == FD_SOCKET)
    {  int i, fh;
       fh = fd_table[index].GetSocket();
     debug(91, 6)
     ("squid_fdeArray::close: %d(%i) type %i %s\n",index,fh,fd_table[index].type,fd_table[index].desc);
       SocketToIndex[fh] = -1;
       if(fh  == MaxSocket)
       {  for(i = fh; i>=0; i--)
          { if(SocketToIndex[i] >= 0)
                  break;
          }
          MaxSocket  = i;
       }
       if(fh  == MinSocket)
       {  int msock = -1,fh1;
          for(i = 0; i < n; i++)
          {  if(i == index) continue;
             if(fd_table[i].type == FD_SOCKET)
             {  fh1 =  fd_table[i].GetSocket();
                if(msock == 0 || fh1 < msock)
                           msock = fh1;
             }
          }
       }

          if(fh < MinSocket) MinSocket = fh;

      commSetSelect(index, COMM_SELECT_READ|COMM_SELECT_WRITE, NULL, NULL, 0);
   } else {
     debug(91, 6)
     ("squid_fdeArray::close: %d type %i %s\n",index,fd_table[index].type,fd_table[index].desc);
   }
   if(fd_table[index].type == FD_PIPE_READ || fd_table[index].type == FD_PIPE_WRITE)
                               DelPipe(index);
    rc = fd_table[index].close();
    iCurrent = index;
    Number_FD--;
    if(index == n-1)
    {  do
         { n--;
           index = n -1;
         } while(n>0 && fd_table[index].type == FD_NONE);
         iCurrent = index;
    }
     debug(91, 7) /*"squid_fdeArray::close:  */
     ("iCurrent %i Number_FD %i\n",iCurrent,Number_FD);


  return rc;
}
int squid_fdeArray::closeAll(void)
{  int i, j, n0=n;
   if(fd_table && n > 0)
     for(i=0;i<n0;i++)
     {  j = n0 - i - 1;
        if(j < n)
             close(j); /* в обратном порядке */
     }
}


/* проверка устовлена ли пометка готовности на чтение-запись */
int squid_fdeArray::QueryPipe(int index, int mask)
{   int i;

    for(i=0; i< NumPipes; i++)
     {   if(listPipes[i].index == index) /* есть */
         {  if(listPipes[i].type & mask)
                               return i+1;
            else
                               return 0;
         }
    }
    return 0;
}

int squid_fdeArray::MarkReadReadyPipe(int index)
{  int i,rc,id;
   if(fd_table[index].type != FD_PIPE_READ)
   {  debug(91, 0)
       ("squid_fdeArray::MarkReadyPipe: Warning: FD type(%d) != FD_PIPE_READ",fd_table[index].type);
      return 1;
   }
   rc =  QueryPipe(index,0x04);
   if(rc==0) /* нет такого */
   {  debug(91, 0)
       ("squid_fdeArray::MarkReadyPipe: Warning: no pipe %d",index);
          return 1;
   }
   id = rc -1;
   listPipes[id].type |= 0x01;
   NumReadReadyPipes++;
   return 0;
}

int squid_fdeArray::MarkWriteReadyPipe(int index)
{  int i,id,rc;
   if(fd_table[index].type != FD_PIPE_WRITE)
   {  debug(91, 0)
       ("squid_fdeArray::MarkWritePipe: Warning: FD type(%i) != FD_PIPE_WRITE",fd_table[index].type);
      return 1;
   }

   rc =  QueryPipe(index,0x04);
   if(rc==0) /* нет такого */
   {  debug(91, 0)
       ("squid_fdeArray::MarkWritePipe: Warning: no pipe %d",index);
          return 1;
   }
   id = rc -1;
   listPipes[id].type |= 0x02;
   NumWriteReadyPipes++;

   return 0;
}

int squid_fdeArray::MarkClearReadyPipe(int index, int mask)
{  int i,id,rc;

   if(fd_table[index].type != FD_PIPE_READ && fd_table[index].type != FD_PIPE_WRITE)
   {  debug(91, 0)
       ("squid_fdeArray::MarkWritePipe: Warning: FD type(%i) != FD_PIPE_R/W",fd_table[index].type);
      return 1;
   }
   rc =  QueryPipe(index,0x04);

   if(rc==0) /* нет такого */
   {  debug(91, 0)
       ("squid_fdeArray::MarkClearReadyPipe: Warning: no pipe %d",index);
          return 1;
   }
   id = rc -1;
   if(mask & 0x01 && listPipes[id].type & 0x01)
   {   listPipes[id].type &= (~0x01);
       NumReadReadyPipes--;
   }
   if(mask & 0x02 && listPipes[id].type & 0x02)
   {   listPipes[id].type &= (~0x02);
       NumWriteReadyPipes--;
   }

   return 0;
}


