Home | History | Annotate | Download | only in libqemu
      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 data and sends
     21  * them back to the client as is.
     22  */
     23 #include <sys/socket.h>
     24 #include <netinet/in.h>
     25 #include <sys/un.h>
     26 #include <unistd.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <errno.h>
     31 
     32 /* Default port number */
     33 #define  DEFAULT_PORT  8012
     34 #define  DEFAULT_PATH  "/tmp/libqemu-socket"
     35 
     36 /* Try to execute x, looping around EINTR errors. */
     37 #undef TEMP_FAILURE_RETRY
     38 #define TEMP_FAILURE_RETRY(exp) ({         \
     39     typeof (exp) _rc;                      \
     40     do {                                   \
     41         _rc = (exp);                       \
     42     } while (_rc == -1 && errno == EINTR); \
     43     _rc; })
     44 
     45 #define TFR TEMP_FAILURE_RETRY
     46 
     47 /* Close a socket, preserving the value of errno */
     48 static void
     49 socket_close(int  sock)
     50 {
     51     int  old_errno = errno;
     52     close(sock);
     53     errno = old_errno;
     54 }
     55 
     56 /* Create a server socket bound to a loopback port */
     57 static int
     58 socket_loopback_server( int port, int type )
     59 {
     60     struct sockaddr_in  addr;
     61 
     62     int  sock = socket(AF_INET, type, 0);
     63     if (sock < 0) {
     64         return -1;
     65     }
     66 
     67     memset(&addr, 0, sizeof(addr));
     68     addr.sin_family      = AF_INET;
     69     addr.sin_port        = htons(port);
     70     addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     71 
     72     int n = 1;
     73     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
     74 
     75     if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) {
     76         socket_close(sock);
     77         return -1;
     78     }
     79 
     80     if (type == SOCK_STREAM) {
     81         if (TFR(listen(sock, 4)) < 0) {
     82             socket_close(sock);
     83             return -1;
     84         }
     85     }
     86 
     87     return sock;
     88 }
     89 
     90 static int
     91 socket_unix_server( const char* path, int type )
     92 {
     93     struct sockaddr_un  addr;
     94 
     95     int  sock = socket(AF_UNIX, type, 0);
     96     if (sock < 0) {
     97         return -1;
     98     }
     99 
    100     memset(&addr, 0, sizeof(addr));
    101     addr.sun_family = AF_UNIX;
    102     snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
    103 
    104     unlink(addr.sun_path);
    105 
    106     printf("Unix path: '%s'\n", addr.sun_path);
    107 
    108     int n = 1;
    109     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
    110 
    111     if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) {
    112         socket_close(sock);
    113         return -1;
    114     }
    115 
    116     if (type == SOCK_STREAM) {
    117         if (TFR(listen(sock, 4)) < 0) {
    118             socket_close(sock);
    119             return -1;
    120         }
    121     }
    122 
    123     return sock;
    124 }
    125 
    126 char* progname;
    127 
    128 static void usage(int code)
    129 {
    130     printf("Usage: %s [options]\n\n", progname);
    131     printf(
    132       "Valid options are:\n\n"
    133       "  -? -h --help  Print this message\n"
    134       "  -unix <path>  Use unix server socket\n"
    135       "  -tcp <port>   Use local tcp port (default %d)\n"
    136       "\n", DEFAULT_PORT
    137     );
    138     exit(code);
    139 }
    140 
    141 /* Main program */
    142 int main(int argc, char** argv)
    143 {
    144     int sock, client;
    145     int port = DEFAULT_PORT;
    146     const char* path = NULL;
    147     const char* tcpPort = NULL;
    148 
    149     /* Extract program name */
    150     {
    151         char* p = strrchr(argv[0], '/');
    152         if (p == NULL)
    153             progname = argv[0];
    154         else
    155             progname = p+1;
    156     }
    157 
    158     /* Parse options */
    159     while (argc > 1 && argv[1][0] == '-') {
    160         char* arg = argv[1];
    161         if (!strcmp(arg, "-?") || !strcmp(arg, "-h") || !strcmp(arg, "--help")) {
    162             usage(0);
    163         } else if (!strcmp(arg, "-unix")) {
    164             if (argc < 3) {
    165                 fprintf(stderr, "-unix option needs an argument! See --help for details.\n");
    166                 exit(1);
    167             }
    168             argc--;
    169             argv++;
    170             path = argv[1];
    171         } else if (!strcmp(arg, "-tcp")) {
    172             if (argc < 3) {
    173                 fprintf(stderr, "-tcp option needs an argument! See --help for details.\n");
    174                 exit(1);
    175             }
    176             argc--;
    177             argv++;
    178             tcpPort = argv[1];
    179         } else {
    180             fprintf(stderr, "UNKNOWN OPTION: %s\n\n", arg);
    181             usage(1);
    182         }
    183         argc--;
    184         argv++;
    185     }
    186 
    187     if (path != NULL) {
    188         printf("Starting pipe test server on unix path: %s\n", path);
    189         sock = socket_unix_server( path, SOCK_STREAM );
    190     } else {
    191         printf("Starting pipe test server on local port %d\n", port);
    192         sock = socket_loopback_server( port, SOCK_STREAM );
    193     }
    194     if (sock < 0) {
    195         fprintf(stderr, "Could not start server: %s\n", strerror(errno));
    196         return 1;
    197     }
    198     printf("Server ready!\n");
    199 
    200 RESTART:
    201     client = TFR(accept(sock, NULL, NULL));
    202     if (client < 0) {
    203         fprintf(stderr, "Server error: %s\n", strerror(errno));
    204         return 2;
    205     }
    206     printf("Client connected!\n");
    207 
    208     /* Now, accept any incoming data, and send it back */
    209     for (;;) {
    210         char  buff[32768], *p;
    211         int   ret, count;
    212 
    213         ret = TFR(read(client, buff, sizeof(buff)));
    214         if (ret < 0) {
    215             fprintf(stderr, "Client read error: %s\n", strerror(errno));
    216             socket_close(client);
    217             return 3;
    218         }
    219         if (ret == 0) {
    220             break;
    221         }
    222         count = ret;
    223         p     = buff;
    224         //printf("   received: %d bytes\n", count);
    225 
    226         while (count > 0) {
    227             ret = TFR(write(client, p, count));
    228             if (ret < 0) {
    229                 fprintf(stderr, "Client write error: %s\n", strerror(errno));
    230                 socket_close(client);
    231                 return 4;
    232             }
    233             //printf("   sent: %d bytes\n", ret);
    234 
    235             p     += ret;
    236             count -= ret;
    237         }
    238     }
    239     printf("Client closed connection\n");
    240     socket_close(client);
    241     goto RESTART;
    242 
    243     return 0;
    244 }
    245