/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Connection I/O SSL Functions
 * ----------------------------------------------------------------
 * Copyright (C) 2006-2007 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * 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
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Last modified by:
 * Jonas Kvinge (24.11.2007)
 *
 */

#define CONN_IO_SSL_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 0			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 1		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 1		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 1		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 0			/* Signal functions */
#define NEED_SYS_SOCKET_H 1		/* Socket functions */
#define NEED_NETDB_H 1			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */
#define NEED_ARES 0			/* Functions needed for ares */
#define NEED_SSL 1			/* Needed for SSL support */

#include "includes.h"
#include "irc.h"

#include "conn.h"
#include "conn_connection.h"
#include "conn_parser.h"
#include "conn_io_ssl.h"

#include "client_notice.h"

/* CONN_RECV_SSL FUNCTION - JONAS (24.11.2007) */

void conn_recv_ssl(struct Conn_Struct *ConnS) {

  signed long int Result = 0;
  unsigned long int OldLen = 0;
  unsigned long int NewLen = 0;
  char RecvBuffer[RECVBUFFERLEN+1] = "";
  char *RecvBufferPT = NULL;

  assert(ConnS != NULL);
  assert(Conn_IsSocket(ConnS));
  assert(ConnS->FD != FD_NONE);

  if ((Conn_IsConnectProc(ConnS)) && (Host_IsResolved(ConnS->ResolveFlags))) {
    conn_connect(ConnS);
    if (!Conn_IsSocket(ConnS)) { return; }
    if (!Conn_IsSSLHandshake(ConnS)) { return; }
  }

  ConnS->LastRecvTime = NOW;

  do {
    memset(&RecvBuffer, 0, sizeof(RecvBuffer));
    Result = SSL_read(ConnS->SSL_H, RecvBuffer, RECVBUFFERLEN);
    if (Result <= 0) {
      signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result);
      if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { break; }
      conn_disconnect(ConnS, "Connection %s: Read error to %s(%s):%ld: [%ld] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, sslerrno, ERR_error_string(sslerrno, NULL));
      return;
    }
    if (Result == 0) {
      if (ConnS->RecvBuffer != NULL) { conn_parser(ConnS); }
      conn_disconnect(ConnS, "Connection %s: EOF to %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH);
      return;
    }

    if (ConnS->RecvBuffer == NULL) { OldLen = 0; }
    else { OldLen = strlen(ConnS->RecvBuffer); }
    NewLen = OldLen + Result + 1;
    RecvBufferPT = realloc(ConnS->RecvBuffer, NewLen);
    if (RecvBufferPT == NULL) {
      conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno));
      return;
    }
    ConnS->RecvBuffer = RecvBufferPT;
    RecvBufferPT += OldLen;
    strcpy(RecvBufferPT, RecvBuffer);
  }
  while (Result >= RECVBUFFERLEN);

  if (Conn_IsSentQuit(ConnS)) { return; }

  conn_parser(ConnS);

}

/* CONN_SEND_SSL FUNCTION - JONAS (24.11.2007) */

void conn_send_ssl(struct Conn_Struct *ConnS) {

  char *SendBufferPT = NULL;
  char SendBuffer[SENDBUFFERLEN+1] = "";
  unsigned long int SendLen = 0;
  unsigned long int SentLen = 0;
  signed long int Result = 0;

  assert(ConnS != NULL);
  assert(Conn_IsSocket(ConnS));
  assert(ConnS->FD != FD_NONE);
  assert(ConnS->SendBuffer != NULL);

  if ((Conn_IsConnectProc(ConnS)) && (Host_IsResolved(ConnS->ResolveFlags))) {
    conn_connect(ConnS);
    if (!Conn_IsSocket(ConnS)) { return; }
    if (!Conn_IsSSLHandshake(ConnS)) { return; }
  }

  for (SendBufferPT = ConnS->SendBuffer ; *SendBufferPT != 0 ; SendBufferPT += SentLen) {
    SendLen = strlen(SendBufferPT);
    if (SendLen > SENDBUFFERLEN) { SendLen = SENDBUFFERLEN; }
    memset(&SendBuffer, 0, sizeof(SendBuffer));
    strncpy(SendBuffer, SendBufferPT, SendLen);
    Result = SSL_write(ConnS->SSL_H, SendBufferPT, SendLen);
    if (Result <= 0) {
      signed long int sslerrno = SSL_get_error(ConnS->SSL_H, Result);
      if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) {
        unsigned long int Len = 0;
        client_noticealluser(ConnS->User, "Connection %s: Write error to %s(%s):%ld: [%ld] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, sslerrno, ERR_error_string(sslerrno, NULL));
        Len = strlen(SendBufferPT) + 1;
        memmove(ConnS->SendBuffer, SendBufferPT, Len);
        SendBufferPT = realloc(ConnS->SendBuffer, Len);
        assert(SendBufferPT != NULL);
        ConnS->SendBuffer = SendBufferPT;
        return;
      }
      conn_disconnect(ConnS, "Connection %s: Write error to %s(%s):%ld: [%ld] %s", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, sslerrno, ERR_error_string(sslerrno, NULL));
      return;
    }
    SentLen = Result;
    assert(SentLen == SendLen);
  }

  FREE(ConnS->SendBuffer);

}


syntax highlighted by Code2HTML, v. 0.9.1