⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bind.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
字号:
/*
 *
 *   BSD sockets functionality for Waterloo TCP/IP
 *
 *   Version
 *
 *   0.5 : Dec 18, 1997 : G. Vanem - created
 */

#include "socket.h"

#if defined(USE_BSD_FUNC)

#ifndef IPPORT_ANY
#define IPPORT_ANY 0
#endif

/*
 * Bind:
 *  The purpose of bind is to fill in the information for the local IP
 *  address and local port (local_addr). In this respect, it is the
 *  opposite of connect(). connect() fills in the destination IP address
 *  and destination port (remote_addr).
 *  In most situations, one does not need to call bind().
 *
 *  Calling bind() on a SOCK_DGRAM socket and for multiple addresses
 *  ('myaddr->sin_addr.s_addr == INADDR_ANY') requires special attention:
 *  Wattcp's 'udp_handler()' doesn't store address information for
 *  broadcast.
 *
 *  We therefore install a 's->dataHandler' pointing to '_recvdaemon()'
 *  which queues up SOCK_DGRAM messages. This queue is polled (by
 *  'sock_recv_from') when we call 'receive()' on such a socket.
 *  Thus the '*from' address in 'receive()' will be correctly set to
 *  source address/port of peer.
 */

int bind (int s, const struct sockaddr *myaddr, int namelen)
{
  Socket             *socket = _socklist_find (s);
  struct sockaddr_in *addr   = (struct sockaddr_in*) myaddr;
  BOOL   bind_any;
  WORD   local_port;

  SOCK_PROLOGUE (socket, "\nbind:%d", s);

  if (!addr || namelen < sizeof(*addr))
  {
    SOCK_DEBUGF ((socket, ", EINVAL"));
    SOCK_ERR (EINVAL);
    return (-1);
  }

  if (addr->sin_family != AF_INET)
  {
    SOCK_DEBUGF ((socket, ", EAFNOSUPPORT"));
    SOCK_ERR (EAFNOSUPPORT);
    return (-1);
  }

  VERIFY_RW (addr, sizeof(*addr));

  if (socket->so_type == SOCK_STREAM &&
      IN_MULTICAST(ntohl(addr->sin_addr.s_addr)))
  {
    SOCK_DEBUGF ((socket, ", EINVAL (mc)"));
    SOCK_ERR (EINVAL);
    return (-1);
  }

  /* binding to anyone (including local machine?)
   */
  bind_any = (addr->sin_addr.s_addr == INADDR_ANY);

  if (socket->local_addr)
  {
    u_short port = socket->local_addr->sin_port;
    u_long  ip   = socket->local_addr->sin_addr.s_addr;

    if ((addr->sin_port != IPPORT_ANY && addr->sin_port == port) ||
        (!bind_any && ip == addr->sin_addr.s_addr))
    {
      SOCK_DEBUGF ((socket, ", EADDRINUSE"));
      SOCK_ERR (EADDRINUSE);
      return (-1);
    }
    /* !!to-do: check for "sleeping" ports (lport_inuse in pctcp.c)
     *          also and give EADDRINUSE if local port not free.
     */
  }
  else
  {
    socket->local_addr = SOCK_CALLOC (sizeof(*socket->local_addr));
    if (!socket->local_addr)
    {
      SOCK_DEBUGF ((socket, ", ENOMEM"));
      SOCK_ERR (ENOMEM);
      return (-1);
    }
  }

  if (addr->sin_port == IPPORT_ANY)
  {
    local_port = findfreeport (0, TRUE);
    addr->sin_port = htons (local_port);
  }
  else  /* check if requested port is vacant */
  {
    local_port = ntohs (addr->sin_port); 
    if (grab_localport (local_port) > 0)
    {
      SOCK_DEBUGF ((socket, ", EADDRINUSE"));
      SOCK_ERR (EADDRINUSE);
      return (-1);
    }
  }

  socket->local_addr->sin_port   = addr->sin_port;
  socket->local_addr->sin_addr   = addr->sin_addr;
  socket->local_addr->sin_family = AF_INET;

  SOCK_DEBUGF ((socket, ", %s, (%d)",
                bind_any ? "INADDR_ANY" : inet_ntoa(addr->sin_addr),
                ntohs(addr->sin_port)));


  /* Since SOCK_DGRAM sockets are connectionless, the application need
   * not use connect() or accept(). Hence we need to use _UDP_listen()
   */
  if (socket->so_type == SOCK_DGRAM)
  {
    if (bind_any)
       socket->so_state |= SS_PRIV; /* privileged for broadcast reception */

    if (_UDP_listen (socket, addr->sin_addr, addr->sin_port) < 0)
       return (-1);
  }
  return (0);
}


/*
 * A small test djgpp program
 */
#if defined(TEST_PROG)

#define MY_PORT_ID  6060
#undef  close

#include <unistd.h>
#include <conio.h>
#include "pcdbug.h"

int main (int argc, char **argv)
{
  struct sockaddr_in addr;
  int    sock, quit;

  dbug_init();

  sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if (sock < 0)
  {
    perror ("socket");
    return (-1);
  }

  memset (&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;

  if (argc >= 2 && !strcmp(argv[1],"-frag")) /* test Tx of large datagrams */
  {
    #define CHUNK_SIZE 500
    char data [3*CHUNK_SIZE];
#if 1
    int i;
    for (i = 0; i < sizeof(data);  i++)
        data[i] = i;
#else
    memset (&data[0], '1', CHUNK_SIZE);
    memset (&data[CHUNK_SIZE], '2', CHUNK_SIZE);
    memset (&data[2*CHUNK_SIZE], '3', CHUNK_SIZE);
#endif

    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
    addr.sin_port        = IPPORT_ANY;

    if (sendto (sock, &data, sizeof(data), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0)
       perror ("sendto");

    close (sock);
    return (-1);
  }

  /* INADDR_ANY will take all the address of the system
   */
  addr.sin_addr.s_addr = htonl (INADDR_ANY);
  addr.sin_port        = htons (MY_PORT_ID);

  if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
  {
    perror ("bind");
    close (sock);
    return (-1);
  }

#if 0
  if (listen (sock, 5) < 0)
  {
    perror ("listen");
    close (sock);
    return (-1);
  }
#endif

  quit = 0;

  while (!quit)
  {
    struct timeval  tv;
    struct sockaddr from;
    fd_set fd_read, fd_write, fd_exc;
    int    num, from_len = sizeof(from);

    FD_ZERO (&fd_read);
    FD_ZERO (&fd_write);
    FD_ZERO (&fd_exc);
    FD_SET (STDIN_FILENO, &fd_read);
    FD_SET (sock, &fd_read);
    FD_SET (sock, &fd_write);
    FD_SET (sock, &fd_exc);
    tv.tv_usec = 0;
    tv.tv_sec  = 1;

    num = select (sock+1, &fd_read, &fd_write, &fd_exc, &tv);

    if (FD_ISSET(sock, &fd_read))  fputc ('r', stderr);
    if (FD_ISSET(sock, &fd_write)) fputc ('w', stderr);
    if (FD_ISSET(sock, &fd_exc))   fputc ('x', stderr);

    if (FD_ISSET(STDIN_FILENO, &fd_read))
    {
      int ch = getch();
      quit = (ch == 27);
      fputc (ch, stderr);
    }

    if (FD_ISSET(sock, &fd_read) &&
        accept (sock, &from, &from_len) < 0)
    {
      perror ("accept");
      break;
    }
    if (num < 0)
    {
      perror ("select");
      break;
    }
    fputc ('.', stderr);
    usleep (300000);   /* 300ms */
  }

  close (sock);
  return (0);
}
#endif  /* TEST_PROG */

#endif /* (USE_BSD_FUNC) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -