Tag: sockets
TCP Client IPv4/IPv6
12. November 2012 04:24

Eine Demonstration, wie man unter Linux Sockets mit Dualstack nutzt.

                    /*
 	Small, simple tcp client

	-Using epoll
	-Fairly protocol independent (IPv4 + IPv6 support)
	-With resolver function

	August 2010 tuxwave.net
	Sebastian Kricner
 */

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <errno.h>

void client(char *host, char *port, int mode)
{
	int error, count, epollfd, statechanged, sock_fd, flags, result, on = 1;
	struct sockaddr *sa;
	socklen_t salen;
	struct addrinfo hints;
	struct addrinfo *res;
        struct epoll_event ev[2], *events;
	char *msg;
	msg = malloc(sizeof(char)*64);
	memset(&hints, 0, sizeof(hints));

	epollfd = epoll_create(2);
        memset(ev, 0, sizeof(ev));
        events = malloc(sizeof(struct epoll_event));
	memset(events, 0, sizeof(struct epoll_event));

	if(mode == 4)
	{
		hints.ai_family = PF_INET;
	}
	else if(mode == 6)
	{
		hints.ai_family = PF_INET6;
	}
	else
	{
		hints.ai_family = PF_UNSPEC;
	}
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	error = getaddrinfo(host, port, &hints, &res);
	if(error)
	{
		fprintf(stderr, "%s\n", gai_strerror(error));
		exit(EXIT_FAILURE);
	}
	else
	{
		while(res)
		{
			sa = res->ai_addr;
			salen = res->ai_addrlen;
			char *hostname = malloc(sizeof(char)*512);
			char *ipaddr = malloc(sizeof(char)*res->ai_addrlen+1);
			error = getnameinfo(sa, salen, hostname, 512, NULL, 0, 0); 
			if(error)
			{
				fprintf(stderr, "%s\n", gai_strerror(error));
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}
			switch (res->ai_family)
			{
				case AF_INET:
					if((inet_ntop(res->ai_family, res->ai_addr->sa_data + 2, ipaddr, res->ai_addrlen)) == NULL)
					{
						perror("getaddrinfo");
						freeaddrinfo(res);
						exit(EXIT_FAILURE);
					}
					break;
				case AF_INET6:
					if((inet_ntop(res->ai_family, res->ai_addr->sa_data + 6, ipaddr, res->ai_addrlen)) == NULL)
					{
						perror("getaddrinfo");
						freeaddrinfo(res);
						exit(EXIT_FAILURE);
					}
					break;
			}
			if(mode == 9)
			{
				printf("Hostname: %s Address: %s\n", hostname, ipaddr);
				printf("-----------------------------------------------------------\n");
				res = res->ai_next;
				continue;
			}
			printf("Connecting to %s [%s] on port %s...\n", hostname, ipaddr, port); 
			sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
			if(sock_fd == -1)
			{
				perror("Socket error");
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}
			error = connect(sock_fd, sa, salen);
			if(error != 0)
			{
				perror("Connect error");
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}
			printf("->Connected<-\n");
			
			error = ioctl(sock_fd, FIONBIO, (char *)&on);
			if(error < 0)
			{
				perror("ioctl failed");
				close(sock_fd);
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}

			ev[0].events = EPOLLIN;
			ev[0].data.fd = sock_fd;
			ev[1].events = EPOLLIN;
			ev[1].data.fd = 0;
			if((epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &ev[0])) == -1)
			{
				perror("epoll");
				close(sock_fd);
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}
			if((epoll_ctl(epollfd, EPOLL_CTL_ADD, 0, &ev[1])) == -1)
			{
				perror("epoll");
				close(sock_fd);
				freeaddrinfo(res);
				exit(EXIT_FAILURE);
			}
			while(1)
			{
				statechanged = epoll_wait(epollfd, events, 1, -1);				
				for(count = 0;count < statechanged;count++)
				{
					int fd = events[count].data.fd;
					if(fd == sock_fd)
					{
						while(1)
						{
							memset(msg, 0, sizeof(char)*64);
							result = recv(sock_fd, msg, sizeof(char)*64, 0);
							if(result < 0)
							{
								if(errno != EWOULDBLOCK)
								{
									perror("recv failed");
									close(sock_fd);
									freeaddrinfo(res);
									exit(EXIT_FAILURE);
								}
								break;
							}
							if(result == 0)
							{
								printf("->Connection closed<-\n");
								close(sock_fd);
								freeaddrinfo(res);
								exit(EXIT_SUCCESS);
							}
							printf("%s", msg);
						}
					}
					else
					{
						memset(msg, 0, sizeof(char)*64);
						if((fgets(msg, sizeof(char)*64, stdin)) != NULL)
						{
							if(strlen(msg) == 1)
							{
								msg[0] = 0x0D;
								msg[1] = 0x0A;
							}
							error = send(sock_fd, msg, strlen(msg), 0);
							if(error == -1)
							{
								perror("Send error");
								close(sock_fd);
								freeaddrinfo(res);
								exit(EXIT_FAILURE);
							}
						}
					}
				}
			}
			close(sock_fd);
			res = res->ai_next;
		}
	}
	freeaddrinfo(res);
}

int main(int argc, char *argv[], char *envp[])
{
	int option, mode = 0;
	char *hostname, *service;

	if(argc < 3)
	{
		printf("Usage: %s {flags} [host] [port]\n", argv[0]);
		printf("Flags:\n"
		"-4	IPv4 only\n"
		"-6	IPv6 only\n"
		"-d	just resolve\n");
		exit(EXIT_FAILURE);
	}
	while((option = getopt(argc, argv, "46d")) != -1)
	{
		switch(option)
		{
			case '4':
				mode = 4;
				break;
			case '6':
				mode = 6;
				break;
			case 'd':
				mode = 9;
				break;
		}
	}
	if(argc-optind == 2)
	{
		client(argv[optind], argv[optind+1], mode);
	}
	else if(argc-optind == 1 && mode == 9)
	{
		client(argv[optind], (char *)0, mode);
	}
	else
	{
		fprintf(stderr, "Invalid arguments\n");
		exit(EXIT_FAILURE);
	}
}


                    
        
Download
epoll Syscall Demo
12. November 2012 03:50

Demonstration Code für den epoll Syscall.

                    /*
	This is a demonstration code, for coding practice.
	August 2010 tuxwave.net

	epoll
	but needs to be looked in further
	there are possibilities to optimize :)

	test it like using this:
	(just for example put this into an script and make thousands background processes, but then do not use while :))
	while true;do echo foo|nc -q 1 localhost 8080; done 

 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main(int argc, char *argv, char *envp[])
{
	struct sockaddr_in6 server_address;
	server_address.sin6_family = AF_INET6;
	server_address.sin6_addr = in6addr_any;
	server_address.sin6_port = htons(8080);
	int server_fd;
	int flags;

	int client_fd, client_len;
	struct sockaddr_in6 client_address;
	client_len = sizeof(client_address);

	if((server_fd = socket(PF_INET6, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "Error creating socket\n");
		exit(EXIT_FAILURE);
	}
	if((bind(server_fd, (struct sockaddr *)&server_address, sizeof(server_address))) == -1)
	{
		perror("Could not bind to socket");
		exit(EXIT_FAILURE);
	}

	flags = fcntl(server_fd, F_GETFL);
	flags |= O_NONBLOCK;
	fcntl(server_fd, F_SETFL, flags);
	listen(server_fd, 10000);
	
	int epollfd = epoll_create(10000);
	struct epoll_event ev, *events;
	memset(&ev, 0, sizeof(struct epoll_event));
	events = malloc(sizeof(struct epoll_event)*10000);
	memset(events, 0, sizeof(struct epoll_event)*10000);
	ev.events = EPOLLIN;
	ev.data.fd = server_fd;
	if((epoll_ctl(epollfd, EPOLL_CTL_ADD, server_fd, &ev)) == -1)
	{
		perror("epoll");
		close(server_fd);
		exit(EXIT_FAILURE);
	}
	int statechanged;
	int i;
	while(1)
	{
		statechanged = epoll_wait(epollfd, events, 10000, -1);
		for(i = 0;i < statechanged; i++)
		{
			int fd = events[i].data.fd;
			if(fd == server_fd)
			{
				if((client_fd = accept(server_fd, (struct sockaddr *) &client_address, &client_len)) != -1)
				{
					char addr[100];

					struct epoll_event cev;
					memset(&cev, 0, sizeof(struct epoll_event));
					cev.events = EPOLLIN;
					cev.data.fd = client_fd;

					if((epoll_ctl(epollfd, EPOLL_CTL_ADD, client_fd, &cev)) == -1)
					{
						perror("epoll");
						close(server_fd);
						exit(EXIT_FAILURE);
					}
					printf("%d accepted %s and added to epoll\n", client_fd, inet_ntop(AF_INET6, &client_address.sin6_addr, addr, 100));
				}
				continue;
			}
			else
			{
				int nread;
				ioctl(fd, FIONREAD, &nread);	
				if(nread > 0)
				{
					char buffer[1024];
					memset(buffer, '\0', 1024);
					recv(fd, buffer, 1023, 0);
					printf("Received: %s\n", buffer);
					if(strstr(buffer, "keks") != 0)
					{
						memset(buffer, '\0', 1024);
						strncpy(buffer, "Hier ist dein Keks\n", 19);
						send(fd, buffer, strlen(buffer), 0);
					}
					else if(strstr(buffer, "end") != 0)
					{
						if((epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL)) == -1)
						{
							perror("epoll");
							close(server_fd);
							exit(EXIT_FAILURE);
						}
						close(fd);
						printf("Removing client on fd %d\n", fd);
						continue;
					}
					else
					{
						send(fd, buffer, strlen(buffer), 0);
					}
					printf("Served client on fd %d\n", fd);				
				}
				else
				{
						if((epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL)) == -1)
						{
							perror("epoll");
							close(server_fd);
							exit(EXIT_FAILURE);
						}
						close(fd);
						printf("Removing client on fd %d\n", fd);
				}
			}
		}
	}
	exit(EXIT_SUCCESS);
}

                    
        
Download