xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/test/sockperf.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  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 /* sockperf.c
18  * This simple network client tries to connect to an echo daemon (echod)
19  * listening on a port it supplies, then time how long it takes to
20  * reply with packets of varying sizes.
21  * It prints results once completed.
22  *
23  * To run,
24  *
25  *   ./echod &
26  *   ./sockperf
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>  /* for atexit() */
31 
32 #include "apr.h"
33 #include "apr_network_io.h"
34 #include "apr_strings.h"
35 
36 #define MAX_ITERS    10
37 #define TEST_SIZE  1024
38 
39 struct testSet {
40     char c;
41     apr_size_t size;
42     int iters;
43 } testRuns[] = {
44     { 'a', 1, 3 },
45     { 'b', 4, 3 },
46     { 'c', 16, 5 },
47     { 'd', 64, 5 },
48     { 'e', 256, 10 },
49 };
50 
51 struct testResult {
52     int size;
53     int iters;
54     apr_time_t msecs[MAX_ITERS];
55     apr_time_t avg;
56 };
57 
58 static apr_int16_t testPort = 4747;
59 static apr_sockaddr_t *sockAddr = NULL;
60 
reportError(const char * msg,apr_status_t rv,apr_pool_t * pool)61 static void reportError(const char *msg, apr_status_t rv,
62                         apr_pool_t *pool)
63 {
64     fprintf(stderr, "%s\n", msg);
65     if (rv != APR_SUCCESS)
66         fprintf(stderr, "Error: %d\n'%s'\n", rv,
67                 apr_psprintf(pool, "%pm", &rv));
68 
69 }
70 
closeConnection(apr_socket_t * sock)71 static void closeConnection(apr_socket_t *sock)
72 {
73     apr_size_t len = 0;
74     apr_socket_send(sock, NULL, &len);
75 }
76 
sendRecvBuffer(apr_time_t * t,const char * buf,apr_size_t size,apr_pool_t * pool)77 static apr_status_t sendRecvBuffer(apr_time_t *t, const char *buf,
78                                    apr_size_t size, apr_pool_t *pool)
79 {
80     apr_socket_t *sock;
81     apr_status_t rv;
82     apr_size_t len = size, thistime = size;
83     char *recvBuf;
84     apr_time_t testStart = apr_time_now(), testEnd;
85     int i;
86 
87     if (! sockAddr) {
88         rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC,
89                                    testPort, 0, pool);
90         if (rv != APR_SUCCESS) {
91             reportError("Unable to get socket info", rv, pool);
92             return rv;
93         }
94 
95         /* make sure we can connect to daemon before we try tests */
96 
97         rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
98                            pool);
99         if (rv != APR_SUCCESS) {
100             reportError("Unable to create IPv4 stream socket", rv, pool);
101             return rv;
102         }
103 
104         rv = apr_socket_connect(sock, sockAddr);
105         if (rv != APR_SUCCESS) {
106             reportError("Unable to connect to echod!", rv, pool);
107             apr_socket_close(sock);
108             return rv;
109         }
110         apr_socket_close(sock);
111 
112     }
113 
114     recvBuf = apr_palloc(pool, size);
115     if (! recvBuf) {
116         reportError("Unable to allocate buffer", ENOMEM, pool);
117         return ENOMEM;
118     }
119 
120     *t = 0;
121 
122     /* START! */
123     testStart = apr_time_now();
124     rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
125                            pool);
126     if (rv != APR_SUCCESS) {
127         reportError("Unable to create IPv4 stream socket", rv, pool);
128         return rv;
129     }
130 
131     rv = apr_socket_connect(sock, sockAddr);
132     if (rv != APR_SUCCESS) {
133         reportError("Unable to connect to echod!", rv, pool);
134         apr_socket_close(sock);
135         return rv;
136     }
137 
138     for (i = 0; i < 3; i++) {
139 
140         len = size;
141         thistime = size;
142 
143         rv = apr_socket_send(sock, buf, &len);
144         if (rv != APR_SUCCESS || len != size) {
145             reportError(apr_psprintf(pool,
146                          "Unable to send data correctly (iteration %d of 3)",
147                          i) , rv, pool);
148             closeConnection(sock);
149             apr_socket_close(sock);
150             return rv;
151         }
152 
153         do {
154             len = thistime;
155             rv = apr_socket_recv(sock, &recvBuf[size - thistime], &len);
156             if (rv != APR_SUCCESS) {
157                 reportError("Error receiving from socket", rv, pool);
158                 break;
159             }
160             thistime -= len;
161         } while (thistime);
162     }
163 
164     closeConnection(sock);
165     apr_socket_close(sock);
166     testEnd = apr_time_now();
167     /* STOP! */
168 
169     if (thistime) {
170         reportError("Received less than we sent :-(", rv, pool);
171         return rv;
172     }
173     if (strncmp(recvBuf, buf, size) != 0) {
174         reportError("Received corrupt data :-(", 0, pool);
175         printf("We sent:\n%s\nWe received:\n%s\n", buf, recvBuf);
176         return EINVAL;
177     }
178     *t = testEnd - testStart;
179     return APR_SUCCESS;
180 }
181 
runTest(struct testSet * ts,struct testResult * res,apr_pool_t * pool)182 static apr_status_t runTest(struct testSet *ts, struct testResult *res,
183                             apr_pool_t *pool)
184 {
185     char *buffer;
186     apr_status_t rv;
187     int i;
188     apr_size_t sz = ts->size * TEST_SIZE;
189 
190     buffer = apr_palloc(pool, sz);
191     if (!buffer) {
192         reportError("Unable to allocate buffer", ENOMEM, pool);
193         return ENOMEM;
194     }
195     memset(buffer, ts->c, sz);
196 
197     res->iters = ts->iters > MAX_ITERS ? MAX_ITERS : ts->iters;
198 
199     for (i = 0; i < res->iters; i++) {
200         apr_time_t iterTime;
201         rv = sendRecvBuffer(&iterTime, buffer, sz, pool);
202         if (rv != APR_SUCCESS) {
203             res->iters = i;
204             break;
205         }
206         res->msecs[i] = iterTime;
207     }
208 
209     return rv;
210 }
211 
main(int argc,char ** argv)212 int main(int argc, char **argv)
213 {
214     apr_pool_t *pool;
215     apr_status_t rv;
216     int i;
217     int nTests = sizeof(testRuns) / sizeof(testRuns[0]);
218     struct testResult *results;
219 
220     printf("APR Test Application: sockperf\n");
221 
222     apr_initialize();
223     atexit(apr_terminate);
224 
225     apr_pool_create(&pool, NULL);
226 
227     results = (struct testResult *)apr_pcalloc(pool,
228                                         sizeof(*results) * nTests);
229 
230     for (i = 0; i < nTests; i++) {
231         printf("Test -> %c\n", testRuns[i].c);
232         results[i].size = testRuns[i].size * (apr_size_t)TEST_SIZE;
233         rv = runTest(&testRuns[i], &results[i], pool);
234         if (rv != APR_SUCCESS) {
235             /* error already reported */
236             exit(1);
237         }
238     }
239 
240     printf("Tests Complete!\n");
241     for (i = 0; i < nTests; i++) {
242         int j;
243         apr_time_t totTime = 0;
244         printf("%10d byte block:\n", results[i].size);
245         printf("\t%2d iterations : ", results[i].iters);
246         for (j = 0; j < results[i].iters; j++) {
247             printf("%6" APR_TIME_T_FMT, results[i].msecs[j]);
248             totTime += results[i].msecs[j];
249         }
250         printf("<\n");
251         printf("\t  Average: %6" APR_TIME_T_FMT "\n",
252                totTime / results[i].iters);
253     }
254 
255     return 0;
256 }
257