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

📄 sflsock.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sflsock.c
    Title:      TCP/IP, UDP/IP socket functions
    Package:    Standard Function Library (SFL)

    Written:    1996/02/03  iMatix SFL project team <sfl@imatix.com>
    Revised:    2000/01/19

    Notes:      The BeOS port of sflsock is incomplete: at last testing,
                BeOS 4.5 gave consistent errors on its select() function,
                apparently due to timer interrupt signals.

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sfllist.h"                    /*  List-management functions        */
#include "sflmem.h"                     /*  Memory-allocation functions      */
#include "sflsymb.h"                    /*  Symbol-table functions           */
#include "sfltok.h"                     /*  Token-handling functions         */
#include "sfluid.h"                     /*  User/group functions             */
#include "sflcons.h"                    /*  Console i/o functions            */
#include "sflfile.h"                    /*  File handling functions          */
#include "sflprint.h"                   /*  snprintf functions               */
#include "sflsock.h"                    /*  Prototypes for functions         */

/*  Implementation notes
 *
 *  These functions work on 16-bit Windows, 32-bit Windows, 32-bit UNIX,
 *  64-bit UNIX, Digital OpenVMS.  The size of a socket handle varies from
 *  16 bits to 64 bits.  All native socket functions define a socket handle
 *  as 'int'.  However, we need a fixed-length external representation.  So,
 *  we define a type, 'sock_t', which is a qbyte (32 bits).  Outside this
 *  package, sockets are always a 'sock_t'.  Internally, we always use an
 *  (SOCKET) cast when passing s sock_t to a system function like connect().
 *  If the system does not support sockets we fake them just a little.
 *
 *  Modifications Oct 7 1998 for Unix by Grant McDorman <grant@isgtec.com> to
 *  allow running with the program suid root; it will run as the user until
 *  the socket must be opened; at that time, it will briefly switch to root
 *  and then return to the actual user id.
 */

/*  Global variables                                                         */

int
    ip_portbase = 0;                    /*  Base for created services        */
Bool
    ip_nonblock = TRUE;                 /*  Create non-blocking sockets      */
qbyte
    ip_passive = INADDR_ANY;            /*  IP address for passive connects  */
int
    ip_sockets = 0;                     /*  Number of open sockets           */


/*  The connect_error_value holds the last recorded error cause after a      */
/*  connection attempt.                                                      */

static int
    connect_error_value = 0;
char
    *connect_errlist [] = {             /*  Corresponding error messages     */
        "No errors",
        "System does not support sockets",
        "Host is not known",
        "Service or port not known",
        "Protocol not known",
        "Connection failed on socket()",
        "Connection failed on connect()",
        "Port is already used by another server",
        "Connection failed on listen()"
    };

/*  Internal functions used to create passive and active connections         */

#if (defined (DOES_SOCKETS))
static void   prepare_socket (sock_t handle);
#   if (defined (__WINDOWS__))
static int    win_error      (int rc);
#   endif
#endif


/*  ---------------------------------------------------------------------[<]-
    Function: sock_init

    Synopsis: Initialise the internet protocol.  On most systems this is a
    null call.  On some systems this loads dynamic libraries.  Returns 0
    0 if everything was okay, else returns SOCKET_ERROR.  You should call
    sock_term() when your program ends.
    ---------------------------------------------------------------------[>]-*/

int
sock_init (void)
{
#if (defined (__WINDOWS__))
    WORD
        wVersionRequested;              /*  We really want Winsock 1.1       */
    WSADATA
        wsaData;

    wVersionRequested = 0x0101;         /*  ... but we'll take 1.1           */
    if (WSAStartup (wVersionRequested, &wsaData) == 0)
        return (0);
    else
        return ((int) SOCKET_ERROR);

#elif (defined (__UTYPE_BEOS))
    /*  BeOS numbers sockets from 0 upwards, but this causes havoc with
     *  programs that expect a BSD-style numbering of 1 or higher.  We
     *  force compatibility by creating (and wasting) one socket so that
     *  further socket handles are guaranteed >0.
     */
    create_socket ("tcp");
    return (0);

#elif (defined (DOES_SOCKETS))
    return (0);

#elif (defined (FAKE_SOCKETS))
    return (0);

#else
    connect_error_value = IP_NOSOCKETS;
    return ((int) SOCKET_ERROR);        /*  Sockets not supported            */
#endif
}


/*  ---------------------------------------------------------------------[<]-
    Function: sock_term

    Synopsis: Shuts-down the internet protocol.  On most systems this is a
    null call.  On some systems this unloads dynamic libraries.  Returns -1
    if there was an error, or 0 if everything was okay.  See sock_init().
    ---------------------------------------------------------------------[>]-*/

int
sock_term (void)
{
#if (defined (__WINDOWS__))
    WSACleanup ();
#endif
    return (0);
}


/*  ---------------------------------------------------------------------[<]-
    Function: passive_TCP

    Synopsis: Creates a passive bound TCP socket for the specified service.
    Returns socket number or INVALID_SOCKET.  If it returns INVALID_SOCKET,
    you can get the reason for the error by calling connect_error ().  This
    may be one of:
    <TABLE>
    IP_NOSOCKETS        Sockets not supported on this system
    IP_BADSERVICE       Service cannot be converted to port number
    IP_BADPROTOCOL      Cannot understand protocol name
    IP_SOCKETERROR      Cannot create the passive socket
    IP_BINDERROR        Cannot bind to the port
    IP_LISTENERROR      Cannot listen to port
    </TABLE>
    ---------------------------------------------------------------------[>]-*/

sock_t
passive_TCP (
    const char *service,                /*  Service name or port as string   */
    int queue_length                    /*  Queue length for listen()        */
)
{
    ASSERT (service && *service);
    ASSERT (queue_length > 0);
    return (passive_socket (service, "tcp", queue_length));
}


/*  ---------------------------------------------------------------------[<]-
    Function: passive_UDP

    Synopsis: Creates a passive UDP socket for the specified service.
    Returns socket number or INVALID_SOCKET.  If it returns INVALID_SOCKET,
    you can get the reason for the error by calling connect_error ().  This
    may be one of:
    <TABLE>
    IP_NOSOCKETS        Sockets not supported on this system
    IP_BADSERVICE       Service cannot be converted to port number
    IP_BADPROTOCOL      Cannot understand protocol name
    IP_SOCKETERROR      Cannot create the passive socket
    IP_BINDERROR        Cannot bind to the port
    </TABLE>
    ---------------------------------------------------------------------[>]-*/

sock_t
passive_UDP (
    const char *service                 /*  Service name or port as string   */
)
{
    ASSERT (service && *service);
    return (passive_socket (service, "udp", 0));
}


/*  ---------------------------------------------------------------------[<]-
    Function: passive_socket

    Synopsis:
    Creates a passive TCP or UDP socket.  This function allows a server
    program to create a master socket, so that connections can be accepted.
    Used by the passive_TCP and passive_UDP functions.  Returns a socket
    number or INVALID_SOCKET.  If it returns INVALID_SOCKET, you can get the
    reason for the error by calling connect_error ().  This may be one of:
    <TABLE>
    IP_NOSOCKETS        Sockets not supported on this system
    IP_BADSERVICE       Service cannot be converted to port number
    IP_BADPROTOCOL      Cannot understand protocol name
    IP_SOCKETERROR      Cannot create the passive socket
    IP_BINDERROR        Cannot bind to the port
    IP_LISTENERROR      Cannot listen to port
    </TABLE>
    By default, opens a socket on all available IP addresses.  You can open
    the socket on a specific address, by setting the global variable
    ip_passive to the address (in network order).  This variable is reset
    to INADDR_ANY after each call to passive_socket or one of the functions
    that calls it.
    ---------------------------------------------------------------------[>]-*/

sock_t
passive_socket (
    const char *service,                /*  Service name or port as string   */
    const char *protocol,               /*  Protocol "tcp" or "udp"          */
    int queue_length                    /*  Queue length for TCP sockets     */
)
{
#if (defined (DOES_SOCKETS))
    struct servent
        *pse;                           /*  Service information entry        */
    struct sockaddr_in
        sin;                            /*  Internet end-point address       */
    sock_t
        handle;                         /*  Socket from socket() call        */

    ASSERT (service && *service);
    ASSERT (protocol && *protocol);

    connect_error_value = IP_NOERROR;   /*  Assume no errors                 */

    memset ((void *) &sin, 0, sizeof (sin));
    sin.sin_family      = AF_INET;
    sin.sin_addr.s_addr = ip_passive;
    ip_passive = INADDR_ANY;            /*  Reset passive address            */

    /*  To allow privileged operations, if possible                          */
    set_uid_root ();

    /*  Map service name to port number                                      */
    pse = getservbyname (service, protocol);
    if (pse)
        sin.sin_port = htons ((dbyte) (ntohs (pse-> s_port) + ip_portbase));
    else
      {
        sin.sin_port = atoi (service);
        if (sin.sin_port + ip_portbase > 0)
            sin.sin_port = htons ((dbyte) (sin.sin_port + ip_portbase));
        else
          {
            connect_error_value = IP_BADSERVICE;
            set_uid_user ();
            return (INVALID_SOCKET);
          }
      }
    handle = create_socket (protocol);
    if (handle == INVALID_SOCKET)       /*  Cannot create the socket         */
      {
        set_uid_user ();
        return (INVALID_SOCKET);
      }

    /*  Bind the socket                                                      */
    if (bind ((SOCKET) handle, (struct sockaddr *) &sin,
        sizeof (sin)) == SOCKET_ERROR)
      {
        connect_error_value = IP_BINDERROR;
        set_uid_user ();
        return (INVALID_SOCKET);        /*  Cannot bind to port              */
      }
    set_uid_user ();

    /*  Specify incoming queue length for stream socket                      */
    if (streq (protocol, "tcp")
    && listen ((SOCKET) handle, queue_length) == SOCKET_ERROR)
      {
        connect_error_value = IP_LISTENERROR;
        return (INVALID_SOCKET);        /*  Cannot listen on port            */
      }
    return (handle);

#elif (defined (FAKE_SOCKETS))
    return (1);                         /*  Return dummy handle              */

#else
    connect_error_value = IP_NOSOCKETS;
    return (INVALID_SOCKET);            /*  Sockets not supported            */
#endif
}


/*  ---------------------------------------------------------------------[<]-
    Function: create_socket

    Synopsis:
    Creates a TCP or UDP socket.  The socket is not connected.  To use
    with TCP services you must bind or connect the socket.  You can use
    the socket with UDP services - e.g. read_UDP () - immediately.  Returns
    a socket number or INVALID_SOCKET, in which case you can get the reason
    for the error by calling connect_error ().  This may be one of:
    <TABLE>
    IP_NOSOCKETS        Sockets not supported on this system
    IP_BADPROTOCOL      Cannot understand protocol name
    IP_SOCKETERROR      Cannot create the socket
    </TABLE>
    ---------------------------------------------------------------------[>]-*/

sock_t
create_socket (
    const char *protocol                /*  Protocol "tcp" or "udp"          */
)
{
#if (defined (DOES_SOCKETS))
    struct protoent
        *ppe;                           /*  Protocol information entry       */
    int
#   if (!defined (__WINDOWS__))
        true_value = 1,                 /*  Boolean value for setsockopt()   */
#   endif
        sock_type;                      /*  Type of socket we want           */
    sock_t
        handle;                         /*  Socket from socket() call        */

⌨️ 快捷键说明

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