/* 
  Copyright 2018-2023 Thorsten Alteholz <libcontra@alteholz.eu>

  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; version 2 of the License

  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 (see the file COPYING included with this
  distribution); if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*!
*************************************************************************
*
* \file libcontra_bind.c
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \brief wrapper for bind()
*
* bind a name to the socket
* man 2 bind
*
*
* \addtogroup libcontra
* The group of the library.
* @{
************************************************************************/

#include <libcontra.h>
#include <libcontra_log.h>

extern bool	libcontra_logBind; /*!< this is needed to control the output in the logging function */
extern bool	libcontra_isInitialized; /*!< this is needed to control the output in the logging function */

/*!
*************************************************************************
*
* \fn int bind(int socket, const struct sockaddr *address, socklen_t address_len)
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \brief wrapper around libc::bind()
*
* @param[in]     socket       socket created by socket(2)
* @param[in]     *address     a pointer to a address structure
*                             the actual structure depends on the address family
* @param[in]     address_len  size of address structure in bytes
*
* \return On success, return 0
*         On error, return -1, errno is set
*
************************************************************************/
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
{
  int (*libc_bind)(int socket, const struct sockaddr *address, socklen_t address_len);
  int rc;
  char addrStr[INET6_ADDRSTRLEN];
  
  if (libcontra_isInitialized==false) {
    libcontra_init();
  } 

  if (libcontra_logBind) {
    struct sockaddr_in *si;
    si=(struct sockaddr_in *)address;
    libcontra_log(LOGLEVEL_DEBUG, "D: bind start");
    libcontra_log(LOGLEVEL_INFO,  "I: bind socket v(%i) to family %s (%s:%d)",socket, libcontra_af2string(si->sin_family), inet_ntop(AF_INET, &(((struct sockaddr_in *)si)->sin_addr), addrStr, INET6_ADDRSTRLEN), ntohs(si->sin_port));
  }

  *(void **)(&libc_bind) = dlsym(RTLD_NEXT, "bind");
  if(dlerror()) {
    errno = EACCES;
    return -1;
  }

  rc = (*libc_bind)(socket, address, address_len);
  
  if (libcontra_logBind) {
    libcontra_log(LOGLEVEL_INFO, "I: bind rc: %i", rc);
    libcontra_log(LOGLEVEL_DEBUG, "D: bind end");
  }

  return rc;
}

/*! @} */

