xref: /haiku/src/tests/system/network/tcp_server.c (revision 5e54f6d4f9dd607ae2afcea4fe72f2f1763e4b5e)
1*5e54f6d4SAugustin Cavalier /*
2*5e54f6d4SAugustin Cavalier  * a stream socket server demo
3*5e54f6d4SAugustin Cavalier  */
4*5e54f6d4SAugustin Cavalier 
5*5e54f6d4SAugustin Cavalier 
6*5e54f6d4SAugustin Cavalier #include <arpa/inet.h>
7*5e54f6d4SAugustin Cavalier #include <errno.h>
8*5e54f6d4SAugustin Cavalier #include <netinet/in.h>
9*5e54f6d4SAugustin Cavalier #include <signal.h>
10*5e54f6d4SAugustin Cavalier #include <stdio.h>
11*5e54f6d4SAugustin Cavalier #include <stdlib.h>
12*5e54f6d4SAugustin Cavalier #include <string.h>
13*5e54f6d4SAugustin Cavalier #include <sys/socket.h>
14*5e54f6d4SAugustin Cavalier #include <sys/types.h>
15*5e54f6d4SAugustin Cavalier #include <sys/wait.h>
16*5e54f6d4SAugustin Cavalier #include <unistd.h>
17*5e54f6d4SAugustin Cavalier 
18*5e54f6d4SAugustin Cavalier 
19*5e54f6d4SAugustin Cavalier #define MYPORT 1234		// the port users will be connecting to
20*5e54f6d4SAugustin Cavalier #define BACKLOG 10		// how many pending connections queue will hold
21*5e54f6d4SAugustin Cavalier #define MAXDATASIZE	1065537
22*5e54f6d4SAugustin Cavalier 
23*5e54f6d4SAugustin Cavalier 
24*5e54f6d4SAugustin Cavalier static void
sigchld_handler(int s)25*5e54f6d4SAugustin Cavalier sigchld_handler(int s)
26*5e54f6d4SAugustin Cavalier {
27*5e54f6d4SAugustin Cavalier 	while (waitpid(-1, NULL, WNOHANG) > 0) {
28*5e54f6d4SAugustin Cavalier 	}
29*5e54f6d4SAugustin Cavalier }
30*5e54f6d4SAugustin Cavalier 
31*5e54f6d4SAugustin Cavalier 
32*5e54f6d4SAugustin Cavalier int
main(int argc,char * argv[])33*5e54f6d4SAugustin Cavalier main(int argc, char *argv[])
34*5e54f6d4SAugustin Cavalier {
35*5e54f6d4SAugustin Cavalier 	int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
36*5e54f6d4SAugustin Cavalier 	struct sockaddr_in my_addr;	// my address information
37*5e54f6d4SAugustin Cavalier 	struct sockaddr_in their_addr; // connector's address information
38*5e54f6d4SAugustin Cavalier 	uint32_t sin_size;
39*5e54f6d4SAugustin Cavalier 	struct sigaction sa;
40*5e54f6d4SAugustin Cavalier 	int yes = 1;
41*5e54f6d4SAugustin Cavalier 	short int port = MYPORT;
42*5e54f6d4SAugustin Cavalier 	char buf[MAXDATASIZE];
43*5e54f6d4SAugustin Cavalier 
44*5e54f6d4SAugustin Cavalier 	if (argc >= 2 && atoi(argv[1]) != 0)
45*5e54f6d4SAugustin Cavalier 		port = atoi(argv[1]);
46*5e54f6d4SAugustin Cavalier 
47*5e54f6d4SAugustin Cavalier 	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
48*5e54f6d4SAugustin Cavalier 		perror("socket");
49*5e54f6d4SAugustin Cavalier 		exit(1);
50*5e54f6d4SAugustin Cavalier 	}
51*5e54f6d4SAugustin Cavalier 
52*5e54f6d4SAugustin Cavalier 	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
53*5e54f6d4SAugustin Cavalier 		perror("setsockopt");
54*5e54f6d4SAugustin Cavalier 		exit(1);
55*5e54f6d4SAugustin Cavalier 	}
56*5e54f6d4SAugustin Cavalier 
57*5e54f6d4SAugustin Cavalier 	memset(&my_addr, 0, sizeof(my_addr));
58*5e54f6d4SAugustin Cavalier 	my_addr.sin_family = AF_INET;
59*5e54f6d4SAugustin Cavalier 	my_addr.sin_port = htons(port);
60*5e54f6d4SAugustin Cavalier 	my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
61*5e54f6d4SAugustin Cavalier 
62*5e54f6d4SAugustin Cavalier 	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
63*5e54f6d4SAugustin Cavalier 		perror("bind");
64*5e54f6d4SAugustin Cavalier 		exit(1);
65*5e54f6d4SAugustin Cavalier 	}
66*5e54f6d4SAugustin Cavalier 
67*5e54f6d4SAugustin Cavalier 	if (listen(sockfd, BACKLOG) == -1) {
68*5e54f6d4SAugustin Cavalier 		perror("listen");
69*5e54f6d4SAugustin Cavalier 		exit(1);
70*5e54f6d4SAugustin Cavalier 	}
71*5e54f6d4SAugustin Cavalier 
72*5e54f6d4SAugustin Cavalier 	sa.sa_handler = sigchld_handler; // reap all dead processes
73*5e54f6d4SAugustin Cavalier 	sigemptyset(&sa.sa_mask);
74*5e54f6d4SAugustin Cavalier #ifdef HAIKU_TARGET_PLATFORM_HAIKU
75*5e54f6d4SAugustin Cavalier 	sa.sa_flags = SA_RESTART;
76*5e54f6d4SAugustin Cavalier #else
77*5e54f6d4SAugustin Cavalier 	sa.sa_flags = 0;
78*5e54f6d4SAugustin Cavalier #endif
79*5e54f6d4SAugustin Cavalier 	if (sigaction(SIGCHLD, &sa, NULL) == -1) {
80*5e54f6d4SAugustin Cavalier 		perror("sigaction");
81*5e54f6d4SAugustin Cavalier 		exit(1);
82*5e54f6d4SAugustin Cavalier 	}
83*5e54f6d4SAugustin Cavalier 
84*5e54f6d4SAugustin Cavalier 	while (1) {
85*5e54f6d4SAugustin Cavalier 		// main accept() loop
86*5e54f6d4SAugustin Cavalier 		sin_size = sizeof(struct sockaddr_in);
87*5e54f6d4SAugustin Cavalier 		if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
88*5e54f6d4SAugustin Cavalier 			perror("accept");
89*5e54f6d4SAugustin Cavalier 			continue;
90*5e54f6d4SAugustin Cavalier 		}
91*5e54f6d4SAugustin Cavalier 		printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
92*5e54f6d4SAugustin Cavalier 		if (!fork()) { // this is the child process
93*5e54f6d4SAugustin Cavalier 			close(sockfd); // child doesn't need the listener
94*5e54f6d4SAugustin Cavalier 
95*5e54f6d4SAugustin Cavalier 			if (!fork()) {
96*5e54f6d4SAugustin Cavalier 				while (1) {
97*5e54f6d4SAugustin Cavalier 					// child's child process
98*5e54f6d4SAugustin Cavalier 					if (fgets(buf, MAXDATASIZE, stdin) == NULL) {
99*5e54f6d4SAugustin Cavalier 						perror("fgets");
100*5e54f6d4SAugustin Cavalier 						exit(1);
101*5e54f6d4SAugustin Cavalier 					}
102*5e54f6d4SAugustin Cavalier 
103*5e54f6d4SAugustin Cavalier 					if (!strcmp(buf, "full\n")) {
104*5e54f6d4SAugustin Cavalier 						int i;
105*5e54f6d4SAugustin Cavalier puts("HY");
106*5e54f6d4SAugustin Cavalier 						for (i = 0; i < MAXDATASIZE - 2; i++) {
107*5e54f6d4SAugustin Cavalier 							buf[i] = 'a' + (i % 26);
108*5e54f6d4SAugustin Cavalier 						}
109*5e54f6d4SAugustin Cavalier 						buf[MAXDATASIZE - 2] = '\n';
110*5e54f6d4SAugustin Cavalier 						buf[MAXDATASIZE - 1] = '\0';
111*5e54f6d4SAugustin Cavalier 					}
112*5e54f6d4SAugustin Cavalier 
113*5e54f6d4SAugustin Cavalier 					if (send(new_fd, buf, strlen(buf), 0) == -1) {
114*5e54f6d4SAugustin Cavalier 						perror("send");
115*5e54f6d4SAugustin Cavalier 						exit(1);
116*5e54f6d4SAugustin Cavalier 					}
117*5e54f6d4SAugustin Cavalier 				}
118*5e54f6d4SAugustin Cavalier 			} else {
119*5e54f6d4SAugustin Cavalier 				ssize_t numBytes;
120*5e54f6d4SAugustin Cavalier 				while (1) {
121*5e54f6d4SAugustin Cavalier 					// child process
122*5e54f6d4SAugustin Cavalier 					if ((numBytes = recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
123*5e54f6d4SAugustin Cavalier 						perror("recv");
124*5e54f6d4SAugustin Cavalier 						exit(1);
125*5e54f6d4SAugustin Cavalier 					}
126*5e54f6d4SAugustin Cavalier 					if (numBytes == 0)
127*5e54f6d4SAugustin Cavalier 						exit(0);
128*5e54f6d4SAugustin Cavalier 
129*5e54f6d4SAugustin Cavalier 					buf[numBytes] = '\0';
130*5e54f6d4SAugustin Cavalier 
131*5e54f6d4SAugustin Cavalier 					printf("%s:| %s", inet_ntoa(their_addr.sin_addr), buf);
132*5e54f6d4SAugustin Cavalier 				}
133*5e54f6d4SAugustin Cavalier 			}
134*5e54f6d4SAugustin Cavalier 
135*5e54f6d4SAugustin Cavalier 			close(new_fd);
136*5e54f6d4SAugustin Cavalier 			exit(0);
137*5e54f6d4SAugustin Cavalier 		}
138*5e54f6d4SAugustin Cavalier 		close(new_fd);  // parent doesn't need this
139*5e54f6d4SAugustin Cavalier 	}
140*5e54f6d4SAugustin Cavalier 
141*5e54f6d4SAugustin Cavalier 	return 0;
142*5e54f6d4SAugustin Cavalier }
143*5e54f6d4SAugustin Cavalier 
144