/** Cleanup and close out the BACnet/IP services by closing the socket.
 * @ingroup DLBIP
  */
void bip_cleanup(
    void)
{
    int sock_fd = 0;

    if (bip_valid()) {
        sock_fd = bip_socket();
        close(sock_fd);
    }
    bip_set_socket(-1);
    WSACleanup();

    return;
}
Beispiel #2
0
U8_T bip_NewConn(U32_T XDATA* pip, U16_T remotePort, U8_T socket)
{
	U8_T	i;

	pip = pip;
	remotePort = remotePort;
	// BIP_MAX_CONNS 1,only 1 
	for (i = 0; i < BIP_MAX_CONNS; i++)
	{
			bip_Conns[i].State = BIP_STATE_CONNECTED;
			bip_Conns[i].UdpSocket = socket;
			bip_set_socket(bip_Conns[i].UdpSocket);

			return i;
	}

	return BIP_STATE_CONNECTED;

}
/** Initialize the BACnet/IP services at the given interface.
 * @ingroup DLBIP
 * -# Gets the local IP address and local broadcast address from the system,
 *  and saves it into the BACnet/IP data structures.
 * -# Opens a UDP socket
 * -# Configures the socket for sending and receiving
 * -# Configures the socket so it can send broadcasts
 * -# Binds the socket to the local IP address at the specified port for
 *    BACnet/IP (by default, 0xBAC0 = 47808).
 *
 * @note For Windows, ifname is the dotted ip address of the interface.
 *
 * @param ifname [in] The named interface to use for the network layer.
 *        If NULL, the "eth0" interface is assigned.
 * @return True if the socket is successfully opened for BACnet/IP,
 *         else False if the socket functions fail.
 */
bool bip_init(
    char *ifname)
{
    int rv = 0; /* return from socket lib calls */
    struct sockaddr_in sin = { -1 };
    int value = 1;
    int sock_fd = -1;
    int Result;
    int Code;
    WSADATA wd;
    struct in_addr address;
    struct in_addr broadcast_address;

    Result = WSAStartup((1 << 8) | 1, &wd);
    /*Result = WSAStartup(MAKEWORD(2,2), &wd); */
    if (Result != 0) {
        Code = WSAGetLastError();
        printf("TCP/IP stack initialization failed\n" " error code: %i %s\n",
            Code, winsock_error_code_text(Code));
        exit(1);
    }
    atexit(bip_cleanup);

    if (ifname)
        bip_set_interface(ifname);
    /* has address been set? */
    address.s_addr = bip_get_addr();
    if (address.s_addr == 0) {
        address.s_addr = gethostaddr();
        if (address.s_addr == (unsigned) -1) {
            Code = WSAGetLastError();
            printf("Get host address failed\n" " error code: %i %s\n", Code,
                winsock_error_code_text(Code));
            exit(1);
        }
        bip_set_addr(address.s_addr);
    }
    if (BIP_Debug) {
        fprintf(stderr, "IP Address: %s\n", inet_ntoa(address));
    }
    /* has broadcast address been set? */
    if (bip_get_broadcast_addr() == 0) {
        set_broadcast_address(address.s_addr);
    }
    if (BIP_Debug) {
        broadcast_address.s_addr = bip_get_broadcast_addr();
        fprintf(stderr, "IP Broadcast Address: %s\n",
            inet_ntoa(broadcast_address));
        fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", ntohs(bip_get_port()),
            ntohs(bip_get_port()));
    }
    /* assumes that the driver has already been initialized */
    sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    bip_set_socket(sock_fd);
    if (sock_fd < 0) {
        fprintf(stderr, "bip: failed to allocate a socket.\n");
        return false;
    }
    /* Allow us to use the same socket for sending and receiving */
    /* This makes sure that the src port is correct when sending */
    rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value,
        sizeof(value));
    if (rv < 0) {
        fprintf(stderr, "bip: failed to set REUSEADDR socket option.\n");
        close(sock_fd);
        bip_set_socket(-1);
        return false;
    }
    /* Enables transmission and receipt of broadcast messages on the socket. */
    rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &value,
        sizeof(value));
    if (rv < 0) {
        fprintf(stderr, "bip: failed to set BROADCAST socket option.\n");
        close(sock_fd);
        bip_set_socket(-1);
        return false;
    }
#if 0
    /* probably only for Apple... */
    /* rebind a port that is already in use.
       Note: all users of the port must specify this flag */
    rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value,
        sizeof(value));
    if (rv < 0) {
        fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n");
        close(sock_fd);
        bip_set_socket(-1);
        return false;
    }
#endif
    /* bind the socket to the local port number and IP address */
    sin.sin_family = AF_INET;
#if defined(USE_INADDR) && USE_INADDR
    /* by setting sin.sin_addr.s_addr to INADDR_ANY,
       I am telling the IP stack to automatically fill
       in the IP address of the machine the process
       is running on.

       Some server computers have multiple IP addresses.
       A socket bound to one of these will not accept
       connections to another address. Frequently you prefer
       to allow any one of the computer's IP addresses
       to be used for connections.  Use INADDR_ANY (0L) to
       allow clients to connect using any one of the host's
       IP addresses. */
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
    /* or we could use the specific adapter address
       note: already in network byte order */
    sin.sin_addr.s_addr = address.s_addr;
#endif
    sin.sin_port = bip_get_port();
    memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
    rv = bind(sock_fd, (const struct sockaddr *) &sin,
        sizeof(struct sockaddr));
    if (rv < 0) {
        fprintf(stderr, "bip: failed to bind to %s port %hu\n",
            inet_ntoa(sin.sin_addr), ntohs(bip_get_port()));
        close(sock_fd);
        bip_set_socket(-1);
        return false;
    }

    return true;
}