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

📄 socket.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  for (sock = sk_list; sock; sock = next)
  {
    int s = sock->fd;
    next  = sock->next;

    if (!FD_ISSET(s,&inuse[0]))
       continue;

    if (sock->local_addr == NULL)  /* not bound to anything yet */
       continue;

#if 0
    _sock_debugf (NULL, "\nsock_daemon:%d", sock->fd);
#endif

    switch (sock->so_type)
    {
      case SOCK_STREAM:
           if (sock->tcp_sock)
              next = tcp_sock_daemon (sock, sock->tcp_sock);
           break;
      case SOCK_DGRAM:
           if (sock->udp_sock)
              next = udp_sock_daemon (sock, sock->udp_sock);
           break;
    }
  }
}

/*
 * Start and stop critical regions from letting `sk_list' be
 * destroyed (e.g. in sock_daemon) and thus confusing select(),
 * connect() etc.
 */
void _sock_start_crit (void)
{
  if (sk_block < INT_MAX)
    ++sk_block;
}

void _sock_stop_crit (void)
{
  if (sk_block > 0)
  {
    --sk_block;

#ifdef SIGALRM         /* handle SIGALRM raised in crit-section */
    /* !!to-do */
#endif

    if (!sk_block)
       sock_daemon();  /* run blocked sock_daemon() */
  }
}


#if defined(USE_BSD_FORTIFY) && defined(USE_DEBUG)
static void fortify_exit (void)
{
  Socket *sock;

  for (sock = sk_list; sock; sock = sock->next)
  {
    char *type = "<?>";
    void *data = NULL;
    tcp_Socket *tcp;

    switch (sock->so_type)
    {
      case SOCK_STREAM:
           type = "TCP";
           data = sock->tcp_sock;
           break;
      case SOCK_DGRAM:
           type = "UDP";
           data = sock->udp_sock;
           break;
      case SOCK_RAW:
           type = "Raw";
           data = sock->raw_sock;
           break;
    }
    SOCK_DEBUGF ((NULL, "\n%2d: inuse %d, type %s, data %08lX",
                  sock->fd, FD_ISSET(sock->fd,&inuse[0]) ? 1 : 0,
                  type, (DWORD)data));

    tcp = sock->tcp_sock;
    if (tcp)
    {
      if (tcp->ip_type == TCP_PROTO)
           SOCK_DEBUGF ((NULL, " (ip_type %d, state %s, ports %u/%u, rdatalen %d)",
                         TCP_PROTO, tcpState[tcp->state],
                         tcp->myport, tcp->hisport, tcp->rdatalen));
      else if (sock->so_state & SS_ISDISCONNECTING)
           SOCK_DEBUGF ((NULL, " (closed)"));
      else SOCK_DEBUGF ((NULL, " (aborted?)"));
    }
  }

  Fortify_ListAllMemory();
  Fortify_OutputStatistics();
}
#endif /* USE_BSD_FORTIFY && USE_DEBUG */


static int InitSockets (void)
{
  extern int __pull_neterr_module;  /* to make linker pull in */
  __pull_neterr_module = 0;         /* correct sys_errlist[]  */

  _watt_do_exit = 0;    /* don't make sock_init() call exit() */
  if (sock_init())
     return (0);

#ifdef __DJGPP__
  {
    struct rlimit r;
    getrlimit (RLIMIT_NOFILE, &r);
    r.rlim_max = MAX_SOCKETS;     /* We don't know this before we try it */
    setrlimit (RLIMIT_NOFILE, &r);
  }
  sk_last = MAX_SOCKETS;
#else
  sk_last = SK_FIRST;
#endif  /* __DJGPP__ */

  sk_list = NULL;
  memset (&inuse, 0, sizeof(inuse));
  addwattcpd (sock_daemon);

#if defined(USE_BSD_FORTIFY) && defined(USE_DEBUG)
  (void) Fortify_EnterScope();
  (void) Fortify_SetOutputFunc (bsd_fortify_print);
  atexit (fortify_exit);
#endif
  return (1);
}          

/*
 * _socklist_find
 *   Returns a pointer to the structure that contains the socket ID passed
 *   to the function. If socket `s' was not found, NULL is returned
 */
Socket *_socklist_find (int s)
{
  Socket *sock;

  if (!sk_init)
  {
    if (!InitSockets())
       return (NULL);
    sk_init = 1;
  }
  for (sock = sk_list; sock; sock = sock->next)
      if (sock->fd == s)
         return (sock);
  return (NULL);
}

/*
 * sock_list_add
 *   Adds a new socket to the sk_list
 */
static Socket *sock_list_add (int s, int type, int proto)
{
  Socket *sock = SOCK_CALLOC (sizeof(*sock));
  void   *proto_sk;

  if (!sock)
     return (NULL);

  switch (proto)
  {
    case IPPROTO_TCP:
         /* Only tcp times out on inactivity
          */
         sock->timeout     = sock_delay;
         sock->linger_time = TCP_LINGERTIME;
         sock->tcp_sock    = proto_sk = SOCK_CALLOC (sizeof(*sock->tcp_sock));
         if (!sock->tcp_sock)
         {
           free (sock);
           return (NULL);
         }
         break;

    case IPPROTO_UDP:
         sock->udp_sock = proto_sk = SOCK_CALLOC (sizeof(*sock->udp_sock));
         if (!sock->udp_sock)
         {
           free (sock);
           return (NULL);
         }
         break;

    default:
         sock->raw_sock = proto_sk = SOCK_CALLOC (sizeof(*sock->raw_sock));
         if (!sock->raw_sock)
         {
           free (sock);
           return (NULL);
         }
         sock->raw_sock->ip_type = IP_TYPE;
         sock->raw_sock->next = NULL; /* !!to-do: make list of MAX_RAW_BUFS */
         break;
  }

#if defined(USE_FSEXT) && defined(__DJGPP__)
  if (!__FSEXT_set_data (s,sock))
  {
    free (proto_sk);
    free (sock);
    SOCK_FATAL (("%s (%d) Fatal: cannot grow FSEXT table\r\n",
                __FILE__, __LINE__));
    return (NULL);
  }
#else
  ARGSUSED (proto_sk);
#endif

  /* Link 'sock' into the 'sk_list'
   */
  if (!sk_list)
  {
    sock->next = NULL;
    sk_list    = sock;
  }
  else
  {
    sock->next = sk_list;
    sk_list    = sock;
  }
  sock->fd         = s;
  sock->so_type    = type;
  sock->so_proto   = proto;
  sock->so_state   = SS_UNCONNECTED;
  sock->send_lowat = DEFAULT_SEND_LOWAT;
  sock->recv_lowat = DEFAULT_RECV_LOWAT;
  sock->ip_ttl     = IPDEFTTL;
  sock->ip_tos     = 0;
  sock->cookie     = SAFETYTCP;

  return (sock);
}

/*
 * Select (and check) a suitable protocol for socket-type
 */
static __inline int set_proto (int type, int *proto)
{
  if (type == SOCK_STREAM)
  {
    if (*proto == 0)
        *proto = IPPROTO_TCP;

    else if (*proto != IPPROTO_TCP)
    {
      SOCK_DEBUGF ((NULL, "\nsocket: invalid STREAM protocol (%d)", *proto));
      return (-1);
    }
    _tcp_find_hook = sock_find_tcp;
  }
  else if (type == SOCK_DGRAM)
  {
    if (*proto == 0)
        *proto = IPPROTO_UDP;

    else if (*proto != IPPROTO_UDP)
    {
      SOCK_DEBUGF ((NULL, "\nsocket: invalid DGRAM protocol (%d)", *proto));
      return (-1);
    }
  }
  else if (type == SOCK_RAW)
  {
    if (*proto == IPPROTO_RAW)     /* match all IP-protocols */
        *proto = IPPROTO_IP;
    _raw_ip_hook = sock_raw_recv;  /* hook for _ip_handler() */
  }
  return (0);
}

/*
 * socket
 *  Parameters:
 *    family   - The protocol family.  Only supports the AF_INET family
 *    type     - SOCK_STREAM (tcp), SOCK_DGRAM (udp) or SOCK_RAW (ip)
 *    protocol - IPPROTO_TCP, IPPROTO_UDP or 0
 *
 *  Return value - The socket ID number
 */
int socket (int family, int type, int protocol)
{
  Socket *sock;
  int     s, ss;

  if (!sk_init && !InitSockets())
  {
    SOCK_ERR (ENETDOWN);
    return (-1);
  }
  sk_init = 1;

  if (family != AF_INET)
  {
    SOCK_DEBUGF ((NULL, "\nsocket: invalid family (%d)", family));
    SOCK_ERR (EAFNOSUPPORT);
    return (-1);
  }

  if (type != SOCK_STREAM &&
      type != SOCK_DGRAM  &&
#if defined(USE_LIBPCAP)
      type != SOCK_PACKET &&
#endif
      type != SOCK_RAW)
  {
    SOCK_DEBUGF ((NULL, "\nsocket: invalid type (%d)", type));
    SOCK_ERR (ESOCKTNOSUPPORT);
    return (-1);
  }

  if (type == SOCK_RAW && (protocol < 0 || protocol > 255))
  {
    SOCK_DEBUGF ((NULL, "\nsocket: invalid SOCK_RAW proto (%d)", protocol));
    SOCK_ERR (EINVAL);
    return (-1);
  }

  if (set_proto (type, &protocol) < 0)
  {
    SOCK_ERR (EPROTONOSUPPORT);
    return (-1);
  }

  s = sock_get_fd();
  if (s < 0)
  {
    SOCK_ERR (EMFILE);
    return (-1);
  }

  sock = sock_list_add (s, type, protocol);
  ss   = (sock ? s : -1);

  switch (type)
  {
    case SOCK_STREAM:
         SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:STREAM, proto %d, %d",
                       protocol, ss));
         break;
    case SOCK_DGRAM:
         SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:DGRAM, proto %d, %d",
                       protocol, ss));
         break;
    case SOCK_RAW:
         SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:RAW, proto %d, %d",
                       protocol, ss));
         break;
#if defined(USE_LIBPCAP)
    case SOCK_PACKET:
         SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:PACK, proto %d, %d",
                       protocol, ss));
         break;
#endif
  }

  if (!sock)
  {
    SOCK_ERR (ENOMEM);
    return (-1);
  }

#if defined(USE_LIBPCAP)
  if (type == SOCK_PACKET) /* promiscuous mode */
  {
    char err_buf[256];

    _pcap_w32 = pcap_open_live ("pkt", ETH_MAX, 1, 0, err_buf);
    if (!_pcap_w32)
    {
      SOCK_ERR (EHOSTDOWN);
      /* !!to-do: plug memory leak
       */
      return (-1);
    }
  }
#endif

  return (s);
}

/*
 *  Callback handlers for "ICMP Port/Host Unreachable" or
 *  "ICMP Parameter Problem" issued by lower layer (udp_cancel()
 *  and tcp_cancel() in pctcp.c)
 *
 *  Note: a single ICMP message might apply to several sockets,
 *        but currrently there is a 1-to-1 relation between a
 *        'socket' and a 'tcp' (or 'udp') structure.
 */
static int stream_cancel (const tcp_Socket *tcp)
{
  Socket *socket;

  for (socket = sk_list; socket; socket = socket->next)
      if (socket->so_type == SOCK_STREAM && tcp == socket->tcp_sock)
      {
        socket->so_state |= SS_CONN_REFUSED;
        socket->so_error  = ECONNREFUSED;
      }
  return (1);
}

static int dgram_cancel (const udp_Socket *udp)
{
  Socket *socket;

  for (socket = sk_list; socket; socket = socket->next)
      if (socket->so_type == SOCK_DGRAM && udp == socket->udp_sock)
      {
        socket->so_state |= SS_CONN_REFUSED;
        socket->so_error  = ECONNREFUSED;
      }
  return (1);
}

static int sol_callback (void *p, int icmp_type)
{
  sock_type *s = (sock_type*)p;
 
  SOCK_DEBUGF ((NULL, "\nsol_callback (s=%08lX, IP-type=%d, ICMP-type %d)",
                (DWORD)p, s->udp.ip_type, icmp_type));

  if (icmp_type == ICMP_UNREACH || icmp_type == ICMP_PARAMPROB)
  {
    if (s->udp.ip_type == UDP_PROTO)
       return dgram_cancel (&s->udp);

    if (s->udp.ip_type == TCP_PROTO)
       return stream_cancel (&s->tcp);
  }
  return (0);
}


/*
 * Open and listen routines for SOCK_DGRAM at the socket-level
 */
int _UDP_open (Socket *socket, struct in_addr host, WORD loc_port, WORD rem_port)
{
  DWORD ip = ntohl (host.s_addr);

  loc_port = ntohs (loc_port);
  rem_port = ntohs (rem_port);

  if (!udp_open (socket->udp_sock, loc_port, ip, rem_port, NULL))
     return (0);

  set_rcv_buf ((sock_type*)socket->udp_sock);
  socket->udp_sock->sol_callb = sol_callback;
  return (1);
}

int _UDP_listen (Socket *socket, struct in_addr host, WORD port)
{
  udp_Socket *udp = socket->udp_sock;

  port = ntohs (port);

  if (socket->so_state & SS_PRIV)
  {
    int   pool_size  = sizeof(recv_buf) * MAX_DGRAMS;
    void *pool = malloc (pool_size);
    DWORD addr;

    if (!pool)
    {
      SOCK_FATAL (("%s (%d) Fatal: Allocation failed\r\n",
                  __FILE__, __LINE__));
      SOCK_ERR (ENOMEM);
      return (-1);
    }
    socket->bcast_pool = (recv_buf**) pool;

    /* Mapping `INADDR_ANY' to `INADDR_BROADCAST' causes udp_handler()
     * to demux to the correct watt-socket; s->hisaddr = 0xFFFFFFFF in
     * passive socket demux loop.
     */
    if (host.s_addr == INADDR_ANY)
         addr = INADDR_BROADCAST;
    else addr = ntohl (host.s_addr);

    udp_listen (udp, port, addr, 0, NULL);

    /* Setup _recvdaemon() to enqueue broadcast/"unconnected" messages
     */
    sock_recv_init (udp, pool, pool_size);
  }
  else
  {
    DWORD ip = ntohl (host.s_addr);
    udp_listen (udp, port, ip, 0, NULL);
  }
  udp->sol_callb = sol_callback;
  return (1);
}


/*
 * Open and listen routines for SOCK_STREAM at the socket-level
 */
int _TCP_open (Socket *socket, struct in_addr host, WORD loc_port, WORD rem_port)
{
  DWORD dest = ntohl (host.s_addr);

  loc_port = ntohs (loc_port);
  rem_port = ntohs (rem_port);

  if (!tcp_open (socket->tcp_sock, loc_port, dest, rem_port, NULL))
     return (0);

  /*
   * The paramters to tcp_open() is a bit tricky, but the internal Wattcp
   * socket 's' contains the following elements that must match in the
   * first 'for-loop' of tcp_handler().
   *
   * s->hisport != 0                i.e. active (non-listening) port
   * s->myaddr  == ip->destination, our IP-address
   * s->hisaddr == ip->source,      above 'dest' address
   * s->myport  == tcp->dstPort,    above 'loc_port'
   * s->hisport == tcp->srcPort,    above 'rem_port'
   */

  /* Advertise a large rcv-win from the next ACK
   */
  set_rcv_buf ((sock_type*)socket->tcp_sock);
  socket->tcp_sock->sol_callb = sol_callback;
  return (1);
}

int _TCP_listen (Socket *socket, struct in_addr host, WORD port)
{
  DWORD addr     = ntohl (host.s_addr);
  WORD  loc_port = ntohs (port);

  tcp_listen (socket->tcp_sock, loc_port, addr, 0, NULL, 0);
  socket->tcp_sock->sol_callb = sol_callback;
  return (1);
}

#ifdef NOT_USED
/*
 * _sock_half_open -
 *   Return true if peer closed his side.
 *   There might still be data to read
 */
int _sock_half_open (const tcp_Socket *s)
{
  if (!s || s->ip_type == UDP_PROTO || s->ip_type == IP_TYPE)
     return (0);

  return (s->state >= tcp_StateFINWT1 &&
          s->state <= tcp_StateCLOSED);
}
#endif

#if 0  /* not finished */
/*
 * socketpair() - Create a pair of connected sockets.
 * Modified version based on Linux's version.
 */
int socketpair (int family, int type, int protocol, int usockvec[2])
{
  Socket *sock1, *sock2;
  int     s1, s2;

  if ((s1 = socket (family, type, protocol)) < 0)
     return (fd1);

  sock1 = socklist_find (s1);

  /* Now grab another socket and try to connect the two together.
   */
  if ((s2 = socket (family, type, protocol)) < 0)
  {
    close_s (s1);
    return (-EINVAL);
  }

  sock2 = socklist_find (s2);

  sock1->conn = sock2;
  sock2->conn = sock1;
  sock1->so_state = SS_CONNECTED;
  sock2->so_state = SS_CONNECTED;

  usockvec[0] = s1;
  usockvec[1] = s2;
  return (0);
}
#endif

#endif /* USE_BSD_FUNC */

⌨️ 快捷键说明

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