1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* This program is used to test the QEMUD fast pipes.
18  * See external/qemu/docs/ANDROID-QEMUD-PIPES.TXT for details.
19  *
20  * The program acts as a simple TCP server that accepts any data and
21  * discards it immediately.
22  */
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 
31 /* Default port number */
32 #define  DEFAULT_PORT  8012
33 
34 /* Try to execute x, looping around EINTR errors. */
35 #undef TEMP_FAILURE_RETRY
36 #define TEMP_FAILURE_RETRY(exp) ({         \
37     typeof (exp) _rc;                      \
38     do {                                   \
39         _rc = (exp);                       \
40     } while (_rc == -1 && errno == EINTR); \
41     _rc; })
42 
43 #define TFR TEMP_FAILURE_RETRY
44 
45 /* Close a socket, preserving the value of errno */
46 static void
socket_close(int sock)47 socket_close(int  sock)
48 {
49     int  old_errno = errno;
50     close(sock);
51     errno = old_errno;
52 }
53 
54 /* Create a server socket bound to a loopback port */
55 static int
socket_loopback_server(int port,int type)56 socket_loopback_server( int port, int type )
57 {
58     struct sockaddr_in  addr;
59 
60     int  sock = socket(AF_INET, type, 0);
61     if (sock < 0) {
62         return -1;
63     }
64 
65     memset(&addr, 0, sizeof(addr));
66     addr.sin_family      = AF_INET;
67     addr.sin_port        = htons(port);
68     addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
69 
70     int n = 1;
71     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
72 
73     if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) {
74         socket_close(sock);
75         return -1;
76     }
77 
78     if (type == SOCK_STREAM) {
79         if (TFR(listen(sock, 4)) < 0) {
80             socket_close(sock);
81             return -1;
82         }
83     }
84 
85     return sock;
86 }
87 
88 /* Main program */
main(void)89 int main(void)
90 {
91     int sock, client;
92     int port = DEFAULT_PORT;
93 
94     printf("Starting pipe test server on local port %d\n", port);
95     sock = socket_loopback_server( port, SOCK_STREAM );
96     if (sock < 0) {
97         fprintf(stderr, "Could not start server: %s\n", strerror(errno));
98         return 1;
99     }
100 
101 RESTART:
102     client = TFR(accept(sock, NULL, NULL));
103     if (client < 0) {
104         fprintf(stderr, "Server error: %s\n", strerror(errno));
105         return 2;
106     }
107     printf("Client connected!\n");
108 
109     /* Now, accept any incoming data, and send it back */
110     for (;;) {
111         char  buff[8192], *p;
112         int   ret, count;
113 
114         ret = TFR(read(client, buff, sizeof(buff)));
115         if (ret < 0) {
116             fprintf(stderr, "Client read error: %s\n", strerror(errno));
117             socket_close(client);
118             return 3;
119         }
120         if (ret == 0) {
121             break;
122         }
123     }
124     printf("Client closed connection\n");
125     socket_close(client);
126     goto RESTART;
127 
128     return 0;
129 }
130