Exemple #1
0
/*
 * \brief It gets the address/port the system picked for this socket (on connected sockets).
 *
 * It is used to return the address and port the server picked for our socket on the local machine.
 * It works only on:
 * - connected sockets
 * - server sockets
 *
 * On unconnected client sockets it does not work because the system dynamically chooses a port
 * only when the socket calls a send() call.
 *
 * \param sock: the connected socket currently opened.
 *
 * \param address: it contains the address that will be returned by the function. This buffer
 * must be properly allocated by the user. The address can be either literal or numeric depending
 * on the value of 'Flags'.
 *
 * \param addrlen: the length of the 'address' buffer.
 *
 * \param port: it contains the port that will be returned by the function. This buffer
 * must be properly allocated by the user.
 *
 * \param portlen: the length of the 'port' buffer.
 *
 * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function)
 * that determine if the resulting address must be in numeric / literal form, and so on.
 *
 * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
 * error message. This buffer has to be at least 'errbuflen' in length.
 * It can be NULL; in this case the error cannot be printed.
 *
 * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
 * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
 *
 * \return It returns '-1' if this function succeeds, '0' otherwise.
 * The address and port corresponding are returned back in the buffers 'address' and 'port'.
 * In any case, the returned strings are '0' terminated.
 *
 * \warning If the socket is using a connectionless protocol, the address may not be available
 * until I/O occurs on the socket.
 */
int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
{
	struct sockaddr_storage mysockaddr;
	socklen_t sockaddrlen;


	sockaddrlen = sizeof(struct sockaddr_storage);

	if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1)
	{
		sock_geterror("getsockname(): ", errbuf, errbuflen);
		return 0;
	}

	/* Returns the numeric address of the host that triggered the error */
	return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen);
}
/*!
	\brief It initializes a network connection both from the client and the server side.

	In case of a client socket, this function calls socket() and connect().
	In the meanwhile, it checks for any socket error.
	If an error occurs, it writes the error message into 'errbuf'.

	In case of a server socket, the function calls socket(), bind() and listen().

	This function is usually preceeded by the sock_initaddress().

	\param addrinfo: pointer to an addrinfo variable which will be used to
	open the socket and such. This variable is the one returned by the previous call to
	sock_initaddress().

	\param server: '1' if this is a server socket, '0' otherwise.

	\param nconn: number of the connections that are allowed to wait into the listen() call.
	This value has no meanings in case of a client socket.

	\param errbuf: a pointer to an user-allocated buffer that will contain the complete
	error message. This buffer has to be at least 'errbuflen' in length.
	It can be NULL; in this case the error cannot be printed.

	\param errbuflen: length of the buffer that will contains the error. The error message cannot be
	larger than 'errbuflen - 1' because the last char is reserved for the string terminator.

	\return the socket that has been opened (that has to be used in the following sockets calls)
	if everything is fine, '0' if some errors occurred. The error message is returned
	in the 'errbuf' variable.
*/
SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen)
{
    SOCKET sock;

    sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
    if (sock == -1)
    {
        sock_geterror("socket(): ", errbuf, errbuflen);
        return -1;
    }


    // This is a server socket
    if (server)
    {
#ifdef BSD
        // Force the use of IPv6-only addresses; in BSD you can accept both v4 and v6
        // connections if you have a "NULL" pointer as the nodename in the getaddrinfo()
        // This behaviour is not clear in the RFC 2553, so each system implements the
        // bind() differently from this point of view

        if (addrinfo->ai_family == PF_INET6)
        {
            int on;

            if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *)&on, sizeof (int)) == -1)
            {
                if (errbuf)
                {
                    snprintf(errbuf, errbuflen, "setsockopt(IPV6_BINDV6ONLY)");
                    errbuf[errbuflen - 1]= 0;
                }
                return -1;
            }
        }
#endif

#ifndef WIN32
        //You have to reuse socket if anybody was using it before you
        {
            int on = 1;
            setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (int));
        }
#endif


        // WARNING: if the address is a mcast one, I should place the proper Win32 code here
        if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
        {
            sock_geterror("bind(): ", errbuf, errbuflen);
            return -1;
        }

        if (addrinfo->ai_socktype == SOCK_STREAM)
            if (listen(sock, nconn) == -1)
            {
                sock_geterror("listen(): ", errbuf, errbuflen);
                return -1;
            }

        // server side ended
        return sock;
    }
    else	// we're the client
    {
        struct addrinfo *tempaddrinfo;
        char *errbufptr;
        size_t bufspaceleft;

        tempaddrinfo= addrinfo;
        errbufptr= errbuf;
        bufspaceleft= errbuflen;
        *errbufptr= 0;


        // We have to loop though all the addinfo returned.
        // For instance, we can have both IPv6 and IPv4 addresses, but the service we're trying
        // to connect to is unavailable in IPv6, so we have to try in IPv4 as well
        while (tempaddrinfo)
        {

            if (connect(sock, tempaddrinfo->ai_addr, tempaddrinfo->ai_addrlen) == -1)
            {
                size_t msglen;
                char TmpBuffer[100];
                char SocketErrorMessage[SOCK_ERRBUF_SIZE];

                // We have to retrieve the error message before any other socket call completes, otherwise
                // the error message is lost
                sock_geterror(NULL, SocketErrorMessage, sizeof(SocketErrorMessage) );

                // Returns the numeric address of the host that triggered the error
                sock_getascii_addrport( (struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer) );

                snprintf(errbufptr, bufspaceleft, "Is the server properly installed on %s?  connect() failed: %s", TmpBuffer, SocketErrorMessage);

                // In case more then one 'connect' fails, we manage to keep all the error messages
                msglen= strlen(errbufptr);

                errbufptr[msglen]= ' ';
                errbufptr[msglen + 1]= 0;

                bufspaceleft= bufspaceleft - (msglen + 1);
                errbufptr+= (msglen + 1);

                tempaddrinfo= tempaddrinfo->ai_next;
            }
            else
                break;
        }

        // Check how we exit from the previous loop
        // If tempaddrinfo is equal to NULL, it means that all the connect() failed.
        if (tempaddrinfo == NULL)
        {
            closesocket(sock);
            return -1;
        }
        else
            return sock;
    }
}
void Server(char *Address, char *Port, int AddressFamily, int TransportProtocol)
{
char ErrBuf[1024];
char DataBuffer[1024];
int ServerSocket, ChildSocket;	// keeps the socket ID for this connection
struct addrinfo Hints;			// temporary struct to keep settings needed to open the new socket
struct addrinfo *AddrInfo;		// keeps the addrinfo chain; required to open a new socket
struct sockaddr_storage From;	// temp variable that keeps the parameters of the incoming connection
int ReadBytes;					// Number of bytes read from the socket
char RemoteAddress[1024];				// temp variable to store the address of the connecting host
char RemotePort[1024];				// temp variable to store the port used by the connecting host

	// Prepare to open a new server socket
	memset(&Hints, 0, sizeof(struct addrinfo));

	Hints.ai_family= AddressFamily;
	Hints.ai_socktype= TransportProtocol;	// Open a TCP/UDP connection
	Hints.ai_flags = AI_PASSIVE;		// This is a server: ready to bind() a socket 

	if (sock_initaddress (Address, Port, &Hints, &AddrInfo, ErrBuf, sizeof(ErrBuf)) == sockFAILURE)
	{
		printf("Error resolving given address/port: %s\n\n", ErrBuf);
		return;
	}

	printf("Server waiting on address %s, port %s, using protocol %s\n", 
		Address ? Address : "all local addresses", Port, (AddrInfo->ai_family == AF_INET) ? "IPv4" : "IPv6");
 
	if ( (ServerSocket= sock_open(AddrInfo, 1, 10,  ErrBuf, sizeof(ErrBuf))) == sockFAILURE)
	{
		// AddrInfo is no longer required
		sock_freeaddrinfo(AddrInfo);
		printf("Cannot opening the socket: %s\n\n", ErrBuf);
		return;
	}

	// AddrInfo is no longer required
	sock_freeaddrinfo(AddrInfo);

	if (TransportProtocol == SOCK_STREAM)
	{
		if ( (ChildSocket= sock_accept(ServerSocket, &From, ErrBuf, sizeof(ErrBuf))) == sockFAILURE)
		{
			printf("Error when accepting a new connection: %s\n\n", ErrBuf);
			return;
		}

		if (sock_getascii_addrport(&From, RemoteAddress, sizeof(RemoteAddress), RemotePort, sizeof(RemotePort),
			NI_NUMERICHOST | NI_NUMERICSERV, ErrBuf, sizeof(ErrBuf)) == sockFAILURE)
		{
			printf("Error getting information related to the connecting host: %s\n\n", ErrBuf);
			return;
		}
		printf("Accepting a new connection from host %s, using remote port %s.\n\n", RemoteAddress, RemotePort);

		ReadBytes= sock_recv(ChildSocket, DataBuffer, sizeof(DataBuffer), SOCK_RECEIVEALL_NO, 30, ErrBuf, sizeof(ErrBuf));
		if (ReadBytes == sockFAILURE)
		{
			printf("Error reading data: %s\n\n", ErrBuf);
			return;
		}
	}
	else
	{
		ReadBytes= sock_recvdgram(ServerSocket, DataBuffer, sizeof(DataBuffer), SOCK_RECEIVEALL_NO, 30, ErrBuf, sizeof(ErrBuf));
		if (ReadBytes == sockFAILURE)
		{
			printf("Error reading data: %s\n\n", ErrBuf);
			return;
		}
	}

	if (ReadBytes == sockWARNING)
	{
		printf("We waited for enough time and no data has been received so far.\nAborting the connection.\n\n");
		return;
	}

	// Terminate buffer, just for printing purposes
	// Warning: this can originate a buffer overflow
	DataBuffer[ReadBytes]= 0;
	printf("Received the following string: '%s'\n\n", DataBuffer);
}
Exemple #4
0
/*
 * \brief It initializes a network connection both from the client and the server side.
 *
 * In case of a client socket, this function calls socket() and connect().
 * In the meanwhile, it checks for any socket error.
 * If an error occurs, it writes the error message into 'errbuf'.
 *
 * In case of a server socket, the function calls socket(), bind() and listen().
 *
 * This function is usually preceeded by the sock_initaddress().
 *
 * \param addrinfo: pointer to an addrinfo variable which will be used to
 * open the socket and such. This variable is the one returned by the previous call to
 * sock_initaddress().
 *
 * \param server: '1' if this is a server socket, '0' otherwise.
 *
 * \param nconn: number of the connections that are allowed to wait into the listen() call.
 * This value has no meanings in case of a client socket.
 *
 * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
 * error message. This buffer has to be at least 'errbuflen' in length.
 * It can be NULL; in this case the error cannot be printed.
 *
 * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
 * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
 *
 * \return the socket that has been opened (that has to be used in the following sockets calls)
 * if everything is fine, INVALID_SOCKET if some errors occurred. The error message is returned
 * in the 'errbuf' variable.
 */
SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen)
{
	SOCKET sock;
#if defined(SO_NOSIGPIPE) || defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY)
	int on = 1;
#endif

	sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
	if (sock == INVALID_SOCKET)
	{
		sock_geterror("socket(): ", errbuf, errbuflen);
		return INVALID_SOCKET;
	}

	/*
	 * Disable SIGPIPE, if we have SO_NOSIGPIPE.  We don't want to
	 * have to deal with signals if the peer closes the connection,
	 * especially in client programs, which may not even be aware that
	 * they're sending to sockets.
	 */
#ifdef SO_NOSIGPIPE
	if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on,
	    sizeof (int)) == -1)
	{
		sock_geterror("setsockopt(SO_NOSIGPIPE)", errbuf, errbuflen);
		closesocket(sock);
		return INVALID_SOCKET;
	}
#endif

	/* This is a server socket */
	if (server)
	{
#if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY)
		/*
		 * Force the use of IPv6-only addresses.
		 *
		 * RFC 3493 indicates that you can support IPv4 on an
		 * IPv6 socket:
		 *
		 *    https://tools.ietf.org/html/rfc3493#section-3.7
		 *
		 * and that this is the default behavior.  This means
		 * that if we first create an IPv6 socket bound to the
		 * "any" address, it is, in effect, also bound to the
		 * IPv4 "any" address, so when we create an IPv4 socket
		 * and try to bind it to the IPv4 "any" address, it gets
		 * EADDRINUSE.
		 *
		 * Not all network stacks support IPv4 on IPv6 sockets;
		 * pre-NT 6 Windows stacks don't support it, and the
		 * OpenBSD stack doesn't support it for security reasons
		 * (see the OpenBSD inet6(4) man page).  Therefore, we
		 * don't want to rely on this behavior.
		 *
		 * So we try to disable it, using either the IPV6_V6ONLY
		 * option from RFC 3493:
		 *
		 *    https://tools.ietf.org/html/rfc3493#section-5.3
		 *
		 * or the IPV6_BINDV6ONLY option from older UN*Xes.
		 */
#ifndef IPV6_V6ONLY
  /* For older systems */
  #define IPV6_V6ONLY IPV6_BINDV6ONLY
#endif /* IPV6_V6ONLY */
		if (addrinfo->ai_family == PF_INET6)
		{
			if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
			    (char *)&on, sizeof (int)) == -1)
			{
				if (errbuf)
					pcap_snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
				closesocket(sock);
				return INVALID_SOCKET;
			}
		}
#endif /* defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) */

		/* WARNING: if the address is a mcast one, I should place the proper Win32 code here */
		if (bind(sock, addrinfo->ai_addr, (int) addrinfo->ai_addrlen) != 0)
		{
			sock_geterror("bind(): ", errbuf, errbuflen);
			closesocket(sock);
			return INVALID_SOCKET;
		}

		if (addrinfo->ai_socktype == SOCK_STREAM)
			if (listen(sock, nconn) == -1)
			{
				sock_geterror("listen(): ", errbuf, errbuflen);
				closesocket(sock);
				return INVALID_SOCKET;
			}

		/* server side ended */
		return sock;
	}
	else	/* we're the client */
	{
		struct addrinfo *tempaddrinfo;
		char *errbufptr;
		size_t bufspaceleft;

		tempaddrinfo = addrinfo;
		errbufptr = errbuf;
		bufspaceleft = errbuflen;
		*errbufptr = 0;

		/*
		 * We have to loop though all the addinfo returned.
		 * For instance, we can have both IPv6 and IPv4 addresses, but the service we're trying
		 * to connect to is unavailable in IPv6, so we have to try in IPv4 as well
		 */
		while (tempaddrinfo)
		{

			if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1)
			{
				size_t msglen;
				char TmpBuffer[100];
				char SocketErrorMessage[SOCK_ERRBUF_SIZE];

				/*
				 * We have to retrieve the error message before any other socket call completes, otherwise
				 * the error message is lost
				 */
				sock_geterror(NULL, SocketErrorMessage, sizeof(SocketErrorMessage));

				/* Returns the numeric address of the host that triggered the error */
				sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer));

				pcap_snprintf(errbufptr, bufspaceleft,
				    "Is the server properly installed on %s?  connect() failed: %s", TmpBuffer, SocketErrorMessage);

				/* In case more then one 'connect' fails, we manage to keep all the error messages */
				msglen = strlen(errbufptr);

				errbufptr[msglen] = ' ';
				errbufptr[msglen + 1] = 0;

				bufspaceleft = bufspaceleft - (msglen + 1);
				errbufptr += (msglen + 1);

				tempaddrinfo = tempaddrinfo->ai_next;
			}
			else
				break;
		}

		/*
		 * Check how we exit from the previous loop
		 * If tempaddrinfo is equal to NULL, it means that all the connect() failed.
		 */
		if (tempaddrinfo == NULL)
		{
			closesocket(sock);
			return INVALID_SOCKET;
		}
		else
			return sock;
	}
}