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