Webserver/Client IPv4 und IPv6

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Daniel200289
Beiträge: 20
Registriert: Mo Aug 11, 2014 12:17 pm

Webserver/Client IPv4 und IPv6

Beitrag von Daniel200289 » Mi Jan 20, 2016 2:55 pm

Hallo zusammen,

hat einer von euch eine Idee, wie ich diesen Webserver in C so umschreiben kann, dass er nicht mehr nur mit IPv4 sondern als Dual Stack mit IPv4 und IPv6 läuft?

Webserver:

Code: Alles auswählen

#include <alloca.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>

#include "common.h"

int main(int argc, char** argv) {
	// Turn off output buffering so that we see all messages immediately
	if (setvbuf(stdout, NULL, _IONBF, 0) != 0) {
		perror("setvbuf failed!");
		return 1;
	}

	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock == -1) {
		perror("Cannot create socket");
		return 1;
	}

	struct sockaddr_in sa;
	memset(&sa, 0, sizeof sa);
	sa.sin_family = AF_INET;
	sa.sin_addr.s_addr = INADDR_ANY;
	sa.sin_port = htons(PORT);
	if (bind(sock, (struct sockaddr *) &sa, sizeof sa) == -1) {
		perror("bind failed!");
		close(sock);
		return 1;
	}

	for (;;) {
		struct sockaddr_in peer;
		socklen_t peer_len = sizeof peer;
		char incoming[1+MAXSIZE];
		ssize_t len = recvfrom(sock, incoming, sizeof incoming, 0, (struct sockaddr*) &peer, &peer_len);
		if (len == -1) {
			perror("recvfrom failed");
			break;
		}
		char* peeraddr = inet_ntoa(peer.sin_addr);
		assert(strlen(peeraddr) < MAXSIZE);
		if (len <= 1) {
			printf("Message from %s too short\n", peeraddr);
			continue;
		}
		if (incoming[0] != 'M') {
			printf("Weird first byte in message from %s: %i\n", peeraddr, (int) incoming[0]);
			continue;
		}
		incoming[len-1] = '\0'; // Ensure that input is a valid C string

		// Craft message contents
		char* peername = incoming+1;
		const char* hostname = get_hostname();

		char msg[1+17+3*(MAXSIZE-1)+1];
		size_t msglen = snprintf(msg, sizeof msg, "RHello %s (%s)! I am %s.", peername, peeraddr, hostname);

		printf("Sending \"%s\" to %s\n", msg, peeraddr);

		// Send response message
		if (sendto(sock, msg, msglen+1, 0, (struct sockaddr*) &peer, peer_len) == -1) {
			perror("Send failed");
			break;
		}
	}

	// An error occured
	close(sock);
	return 2;
}
Client:

Code: Alles auswählen

#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include "common.h"

void contact(char* host) {
	// Determine remote address
	struct hostent *he = gethostbyname(host);
	if (he == NULL) {
		perror("gethostbyname failed");
		return;
	}
	struct sockaddr_in sa;
	memset(&sa, 0, sizeof sa);
	memcpy(& (sa.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
	sa.sin_port = htons(PORT);

	// Create socket
	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock == -1) {
		perror("socket creation failed");
		return;
	}

	// Compose message
	char sendbuf[1+MAXSIZE];
	int msglen = snprintf(sendbuf, sizeof sendbuf, "M%s", get_hostname()) + 1;

	// Configure socket timeouts
	struct timeval timeout;
	memset(&timeout, 0, sizeof timeout);
	timeout.tv_sec = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout) == -1) {
		perror("setsockopt(SO_RCVTIMEO) failed");
		close(sock);
		return;
	}
	if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout) == -1) {
		perror("setsockopt(SO_SNDTIMEO) failed");
		close(sock);
		return;
	}

	// Send message
	if (sendto(sock, sendbuf, msglen, 0, (struct sockaddr *) &sa, sizeof sa) == -1) {
		perror("sendto failed");
		close(sock);
		return;
	}

	char recvbuf[4*MAXSIZE];
	struct sockaddr_in peer;
	socklen_t peer_len = sizeof peer;
	size_t msgsize = recvfrom(sock, &recvbuf, sizeof recvbuf, 0, (struct sockaddr*) &peer, &peer_len);
	if (msgsize == -1) {
		if (errno == EWOULDBLOCK) {
			fprintf(stderr, "No response from %s!\n", host);
			close(sock);
			return;
		}

		perror("recvfrom failed");
		close(sock);
		return;
	}

	recvbuf[msgsize-1] = '\0';
	const char* peeraddr = inet_ntoa(sa.sin_addr);
	if (recvbuf[0] != 'R') {
		fprintf(stderr, "Reply from %s(%s) does not follow protocol!\n"
						"Expected message type 'R', but got %c\n",
						peeraddr, host, recvbuf[0]);
		close(sock);
		return;
	}

	printf("\"%s\" from %s (%s)\n", recvbuf+1, peeraddr, host);

	close(sock);
}

int main(int argc, char** argv) {
	if (argc == 1) {
		fprintf(stderr, "No remote host given!\n");
		printf("Usage: %s server-ip [server-ip..]\n", argv[0]);
		return 1;
	}

	char** host = argv+1;
	while (argc > 1) {
		contact(*host);
		host++;
		argc--;
	}

	return 0;
}
common.h:

Code: Alles auswählen

#define PORT 2673
// Maximum size of various string fields (including trailing \0)
#define MAXSIZE 256

/**
 * Determines this machine's hostname, of up to MAXSIZE characters (including trailing \0).
 * Returns a static buffer.
 */
extern const char* get_hostname();
Vielen Dank schonmal für euere Hilfe.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Webserver/Client IPv4 und IPv6

Beitrag von nufan » Mi Jan 20, 2016 3:25 pm

Du musst dir einen IPv6 Socket erstellen (AF_INET6) und darfst die Option IPV6_V6ONLY nicht gesetzt haben.

Siehe auch: https://stackoverflow.com/questions/220 ... one-socket

Antworten