/* Socks Server 5
 * Copyright (C) 2002 - 2006 by Matteo Ricchetti - <matteo.ricchetti@libero.it>

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * B
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include"SS5Main.h"
#include"SS5Defs.h"
#include"SS5Mod_proxy.h"


S5RetCode InitModule( struct _module *m )
{
  m->ReceivingData = ReceivingData;
  m->SendingData   = SendingData;
  m->UdpReceivingData = UdpReceivingData;
  m->UdpSendingData   = UdpSendingData;
  
  return OK;
}


S5RetCode 
  IFEPOLL( ReceivingData( struct _SS5ClientInfo *ci, int applicationSocket, struct _SS5ProxyData *pd, struct epoll_event *events ) )
  IFSELECT( ReceivingData( struct _SS5ClientInfo *ci, int applicationSocket, struct _SS5ProxyData *pd, fd_set *s5array ) )
{
  /* 
   * Receive data from client
   */
  IFEPOLL( if( events[0].data.fd == ci->Socket ) { )
  IFSELECT( if( FD_ISSET(ci->Socket,s5array) ) { )
    memset(pd->Recv,0,sizeof(pd->Recv));
    pd->TcpRBufLen = recv(ci->Socket,pd->Recv,sizeof(pd->Recv),0);
    pd->Fd = 0;
  }

  /* 
   * Receive data from application
   */
  IFEPOLL( else if( events[0].data.fd == applicationSocket ) { )
  IFSELECT( else if( FD_ISSET(applicationSocket,s5array) ) { )
    memset(pd->Recv,0,sizeof(pd->Recv));
    pd->TcpRBufLen = recv(applicationSocket,pd->Recv,sizeof(pd->Recv),0);
    pd->Fd = 1;
  }
  return OK;
} 

S5RetCode 
SendingData( struct _SS5ClientInfo *ci, int applicationSocket, struct _SS5ProxyData *pd )
{
  if( pd->Fd == 1 ) {
   memset(pd->Send,0,sizeof(pd->Send));
   memcpy(pd->Send,pd->Recv,pd->TcpRBufLen);
   pd->TcpSBufLen = send(ci->Socket,pd->Send,pd->TcpRBufLen,SS5_SEND_OPT);
  }
  else {
   memset(pd->Send,0,sizeof(pd->Send));
   memcpy(pd->Send,pd->Recv,pd->TcpRBufLen);
   pd->TcpSBufLen = send(applicationSocket,pd->Send,pd->TcpRBufLen,SS5_SEND_OPT);
  }
  return OK;
}

S5RetCode 
UdpReceivingData( int applicationSocket, struct _SS5ProxyData *pd )
{
  unsigned int len;
  unsigned int fd;

  struct timeval tv;

  fd_set arrayFd;

  struct sockaddr_in applicationSsin;

  char logString[128];

  pid_t pid;

  /*
   *    Get child/thread pid
   */
  if( NOTTHREADED() )
    pid=getpid();
  else
    pid=(unsigned int)pthread_self();

  bzero((char *)&applicationSsin, sizeof(struct sockaddr_in));

  len = sizeof(struct sockaddr_in);
  memset(pd->UdpRecv,0,sizeof(pd->UdpRecv));

  FD_ZERO(&arrayFd);
  FD_SET(applicationSocket,&arrayFd);

  tv.tv_sec  = UDP_TIMEOUT;
  tv.tv_usec = 0;

  if( (fd = select(applicationSocket+1,&arrayFd,NULL,NULL,&tv)) ) {
    if( FD_ISSET(applicationSocket,&arrayFd) ) {
      if( (pd->UdpRBufLen=recvfrom(applicationSocket,pd->UdpRecv,sizeof(pd->UdpRecv),0,(struct sockaddr *)&applicationSsin,(socklen_t *)&len)) == -1 ) {
        ERRNO(pid)
        return ERR;
      }
    }
  }
  else {
    /*
     *    Timeout expired receiving data from remote application
     */
    return (-1 * S5REQUEST_TTLEXPIRED);
  }
  return OK;
}

S5RetCode 
UdpSendingData( int applicationSocket, struct _SS5UdpRequestInfo *uri , struct _SS5ProxyData *pd  )
{
  unsigned int len;

  char logString[128];

  pid_t pid;

  struct sockaddr_in applicationSsin;

  /*
   *    Get child/thread pid
   */
  if( NOTTHREADED() )
    pid=getpid();
  else
    pid=(unsigned int)pthread_self();

  len = sizeof(struct sockaddr_in);

  memset((char *)&applicationSsin, 0, sizeof(struct sockaddr_in));
  applicationSsin.sin_family      = AF_INET;
  applicationSsin.sin_port        = htons(uri->DstPort);
  applicationSsin.sin_addr.s_addr = inet_addr(uri->DstAddr);

  if( (pd->UdpSBufLen=sendto(applicationSocket,pd->UdpSend,pd->UdpSBufLen,0,(struct sockaddr *)&applicationSsin,(socklen_t)len)) == -1 ) {
    ERRNO(pid)
    return ERR;
  }

  return OK;
}


syntax highlighted by Code2HTML, v. 0.9.1