/*
 * ----------------------------------------------------------------
 * Night Light File Descriptor Debugging Functions
 * ----------------------------------------------------------------
 * Copyright (C) 2003-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 (02.07.2003)
 *
 */

#define FDCALLS_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 0		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 0		/* 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 0		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 0		/* 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 0			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */

#include "includes.h"

#if !FDDEBUG
  #error "fdcalls.h included, but FDDEBUG not defined TRUE."
#endif

#ifdef SOCKET_REDEFINE
  #error "Sanity check: socket() can't be redefined in here!"
#endif

/* VARIABLES - JONAS (01.07.2003) */

struct FDTable_Struct *FDTable_Head = NULL;
struct FDTable_Struct *FDTable_Tail = NULL;
struct SockTable_Struct *SockTable_Head = NULL;
struct SockTable_Struct *SockTable_Tail = NULL;
unsigned long int G_FDs = 0;
unsigned long int G_Sockets = 0;

/* FDTABLE_ADD - JONAS (01.07.2003) */

void fdtable_add(FILE *FD, const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const char *const PathPT, const char *const ModePT) {

  struct FDTable_Struct *FDTableS = NULL;
  struct FDTable_Struct *FDTableS_NEW = NULL;

  assert(FD != NULL);
  assert(FilePT != NULL);
  assert(FunctionPT != NULL);
  assert(PathPT != NULL);
  assert(ModePT != NULL);

  FDTableS_NEW = malloc(sizeof(struct FDTable_Struct));
  if (FDTableS_NEW == NULL) {
    return;
  }
  memset(FDTableS_NEW, 0, sizeof(struct FDTable_Struct));

  FDTableS_NEW->FD = FD;
  FDTableS_NEW->File = (const char *const) FilePT;
  FDTableS_NEW->Line = (const unsigned short int) Line;
  FDTableS_NEW->Function = (const char *const) FunctionPT;
  FDTableS_NEW->Time = NOW;

  if (FDTable_Head == NULL) {
    FDTable_Head = FDTableS_NEW;
    FDTable_Tail = FDTableS_NEW;
  }
  else {
    FDTableS = FDTable_Tail;
    FDTableS->Next = FDTableS_NEW;
    FDTableS_NEW->Prev = FDTableS;
    FDTable_Tail = FDTableS_NEW;
  }

  G_FDs++;

  DEBUGPRINT(BITMASK_DEBUG_FD, "FD DEBUG: Function: %s() - FD: %p - File: %s - Line: %d - Function: %s - Path: %s - Mode: %s", __FUNCTION__, FD, FilePT, Line, FunctionPT, PathPT, ModePT);

}

/* FDTABLE_REM - JONAS (01.07.2003) */

void fdtable_rem(struct FDTable_Struct *FDTableS) {

  assert(FDTableS != NULL);

  if (FDTableS->Prev == NULL) { FDTable_Head = FDTableS->Next; }
  else { FDTableS->Prev->Next = FDTableS->Next; }

  if (FDTableS->Next == NULL) { FDTable_Tail = FDTableS->Prev; }
  else { FDTableS->Next->Prev = FDTableS->Prev; }

  G_FDs--;

  DEBUGPRINT(BITMASK_DEBUG_FD, "FD DEBUG: Function: %s() - FD: %p - File: %s - Line: %d - Function: %s", __FUNCTION__, FDTableS->FD, FDTableS->File, FDTableS->Line, FDTableS->Function);

  free(FDTableS);

}

/* FDTABLE_GET - JONAS (01.07.2003) */

struct FDTable_Struct *fdtable_get(const FILE *const FD) {

  struct FDTable_Struct *FDTable = NULL;

  for (FDTable = FDTable_Head ; FDTable != NULL ; FDTable = FDTable->Next) {
    if (FDTable->FD == FD) { return(FDTable); }
  }
  return(NULL);

}

/* FDTABLE_CLEAR - JONAS (01.07.2003) */

void fdtable_clear(void) {

  while (FDTable_Head != NULL) { fdtable_rem(FDTable_Head); }

}

/* OPENFD - JONAS (01.07.2003) */

FILE *openfd(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const char *const PathPT, const char *const ModePT) {

  FILE *FD = NULL;

  DEBUGPRINT(BITMASK_DEBUG_FD, "FD DEBUG: Function: %s() - File: %s - Line: %d - Function: %s - Path: %s - Mode: %s", __FUNCTION__, FilePT, Line, FunctionPT, PathPT, ModePT);

  FD = fopen(PathPT, ModePT);
  if (FD != NULL) { fdtable_add(FD, FilePT, Line, FunctionPT, PathPT, ModePT); }

  return(FD);

}

/* CLOSEFD - JONAS (01.07.2003) */

signed short int closefd(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, FILE *FD) {

  struct FDTable_Struct *FDTableS = NULL;
  signed short int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_FD, "FD DEBUG: Function: %s() - File: %s - Line: %d - Function: %s - Pointer: %p", __FUNCTION__, FilePT, Line, FunctionPT, FD);

  if (FD == NULL) { return(SUCCESS); }

  FDTableS = fdtable_get(FD);
  if (FDTableS == NULL) {
    sysprint(BITMASK_ERROR, "Wild FD %p from function %s (%s:%d) passed to function fclose().", FD, FunctionPT, FilePT, Line);
    return(ERROR);
  }

  Result = fclose(FD);
  if (Result == SUCCESS) { fdtable_rem(FDTableS); }
  return(Result);

}

/* SOCKTABLE_ADD - JONAS (01.07.2003) */

void socktable_add(signed long int Socket, const char *const FilePT, const unsigned short int Line, const char *const FunctionPT) {

  struct SockTable_Struct *SockTableS = NULL;
  struct SockTable_Struct *SockTableS_NEW = NULL;

  assert(FilePT != NULL);
  assert(FunctionPT != NULL);

  SockTableS_NEW = malloc(sizeof(struct SockTable_Struct));
  if (SockTableS_NEW == NULL) {
    return;
  }
  memset(SockTableS_NEW, 0, sizeof(struct SockTable_Struct));

  SockTableS_NEW->Socket = Socket;
  SockTableS_NEW->File = (const char *const) FilePT;
  SockTableS_NEW->Line = (const unsigned short int) Line;
  SockTableS_NEW->Function = (const char *const) FunctionPT;
  SockTableS_NEW->Time = NOW;

  if (SockTable_Head == NULL) {
    SockTable_Head = SockTableS_NEW;
    SockTable_Tail = SockTableS_NEW;
  }
  else {
    SockTableS = SockTable_Tail;
    SockTableS->Next = SockTableS_NEW;
    SockTableS_NEW->Prev = SockTableS;
    SockTable_Tail = SockTableS_NEW;
  }

  G_Sockets++;

  DEBUGPRINT(BITMASK_DEBUG_FD, "SOCKET DEBUG: Function: %s() - Socket: %ld - File: %s - Line: %d - Function: %s", __FUNCTION__, Socket, FilePT, Line, FunctionPT);

}

/* SOCKTABLE_REM - JONAS (01.07.2003) */

void socktable_rem(struct SockTable_Struct *SockTableS) {

  assert(SockTableS != NULL);

  if (SockTableS->Prev == NULL) { SockTable_Head = SockTableS->Next; }
  else { SockTableS->Prev->Next = SockTableS->Next; }

  if (SockTableS->Next == NULL) { SockTable_Tail = SockTableS->Prev; }
  else { SockTableS->Next->Prev = SockTableS->Prev; }

  G_Sockets--;

  DEBUGPRINT(BITMASK_DEBUG_FD, "SOCKET DEBUG: Function: %s() - Socket: %ld - File: %s - Line: %d - Function: %s", __FUNCTION__, SockTableS->Socket, SockTableS->File, SockTableS->Line, SockTableS->Function);

  free(SockTableS);

}

/* SOCKTABLE_GET - JONAS (01.07.2003) */

struct SockTable_Struct *socktable_get(signed long int Socket) {

  struct SockTable_Struct *SockTable = NULL;

  for (SockTable = SockTable_Head ; SockTable != NULL ; SockTable = SockTable->Next) {
    if (SockTable->Socket == Socket) { return(SockTable); }
  }
  return(NULL);

}

/* SOCKTABLE_CLEAR - JONAS (01.07.2003) */

void socktable_clear(void) {

  while (SockTable_Head != NULL) { socktable_rem(SockTable_Head); }

}

/* OPENSOCK - JONAS (01.07.2003) */

signed short int opensock(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, signed short int Domain, signed short int Type, signed short int Protocol) {

  signed long int Socket = 0;

  DEBUGPRINT(BITMASK_DEBUG_FD, "SOCKET DEBUG: Function: %s() - File: %s - Line: %d - Function: %s", __FUNCTION__, FilePT, Line, FunctionPT);

  Socket = socket(Domain, Type, Protocol);
  if (Socket > ERROR) { socktable_add(Socket, FilePT, Line, FunctionPT); }

  return(Socket);

}

/* ACCEPTSOCK - JONAS (01.07.2003) */

signed short int acceptsock(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, signed short int ListenSocket, struct sockaddr *SockAddr, accept_addrlen_type *SockAddrLen) {

  signed long int NewSocket = 0;

  DEBUGPRINT(BITMASK_DEBUG_FD, "SOCKET DEBUG: Function: %s() - File: %s - Line: %d - Function: %s", __FUNCTION__, FilePT, Line, FunctionPT);

  NewSocket = accept(ListenSocket, SockAddr, SockAddrLen);
  if (NewSocket > ERROR) { socktable_add(NewSocket, FilePT, Line, FunctionPT); }

  return(NewSocket);

}

/* CLOSESOCK - JONAS (01.07.2003) */

signed short int closesock(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, signed short int Socket) {

  struct SockTable_Struct *SockTableS = NULL;
  signed short int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_FD, "SOCKET DEBUG: Function: %s() - File: %s - Line: %d - Function: %s - Socket: %d", __FUNCTION__, FilePT, Line, FunctionPT, Socket);

  SockTableS = socktable_get(Socket);
  if (SockTableS == NULL) {
    sysprint(BITMASK_ERROR, "Wild socket %d from function %s (%s:%d) passed to function close().", Socket, FunctionPT, FilePT, Line);
    return(ERROR);
  }

  Result = close(Socket);
  if (Result == SUCCESS) { socktable_rem(SockTableS); }
  return(Result);

}

/* FD_PRINT - JONAS (01.07.2003) */

void fd_print(void) {

  struct FDTable_Struct *FDTableS = NULL;
  struct SockTable_Struct *SockTableS = NULL;

  DEBUGPRINT(BITMASK_DEBUG_FD, "%s()", __FUNCTION__);

  for (FDTableS = FDTable_Head ; FDTableS != NULL ; FDTableS = FDTableS->Next) {
    if ((FDTableS->FD == stdin) || (FDTableS->FD == stdout) || (FDTableS->FD == stderr)) { continue; }
    if ((strcmp(FDTableS->File, "syscalls.c") == FALSE) && (strcmp(FDTableS->Function, "sysopenfiles_fg") == FALSE)) { continue; }
    if ((strcmp(FDTableS->File, "syscalls.c") == FALSE) && (strcmp(FDTableS->Function, "sysopenfiles_bg") == FALSE)) { continue; }
    sysprint(BITMASK_ERROR, "Open file descriptor: %p File: %s Line: %d Function: %s", FDTableS->FD, FDTableS->File, FDTableS->Line, FDTableS->Function);
  }
  for (SockTableS = SockTable_Head ; SockTableS != NULL ; SockTableS = SockTableS->Next) {
    if (SockTableS->Socket <= 2) { continue; }
    sysprint(BITMASK_ERROR, "Open socket: %ld File: %s Line: %d Function: %s", SockTableS->Socket, SockTableS->File, SockTableS->Line, SockTableS->Function);
  }

}



syntax highlighted by Code2HTML, v. 0.9.1