1 /*
   2  * Copyright 2016 Jeremy Allison
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included
  12  * in all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20  * DEALINGS IN THE SOFTWARE.
  21  */
  22 
  23 #include <sys/param.h>
  24 #include <sys/types.h>
  25 #include <sys/stat.h>
  26 #include <sys/socket.h>
  27 #include <sys/un.h>
  28 #include <stdio.h>
  29 #include <unistd.h>
  30 #include <string.h>
  31 #include <errno.h>
  32 #include <stdint.h>
  33 #include <stdlib.h>
  34 #include <pthread.h>
  35 
  36 extern const char *__progname;
  37 
  38 static void *
  39 server(void *varg)
  40 {
  41         int ret;
  42         int sock = (int)varg;
  43         unsigned int i;
  44 
  45         for (i = 0; i < 5; i++) {
  46                 struct iovec iov;
  47                 struct msghdr msg;
  48                 uint8_t buf[4096];
  49 
  50                 iov = (struct iovec) {
  51                         .iov_base = buf,
  52                         .iov_len = sizeof (buf)
  53                 };
  54 
  55                 msg = (struct msghdr) {
  56                         .msg_iov = &iov,
  57                         .msg_iovlen = 1,
  58                 };
  59 
  60                 ret = recvmsg(sock, &msg, 0);
  61                 if (ret == -1) {
  62                         fprintf(stderr, "server - recvmsg fail %s\n",
  63                             strerror(errno));
  64                         exit(1);
  65                 }
  66 
  67                 printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
  68                 fflush(stdout);
  69         }
  70 
  71         exit(0);
  72 }
  73 
  74 static void *
  75 listener(void *varg)
  76 {
  77         struct sockaddr_un *addr = varg;
  78         int ret;
  79         int lsock;
  80         int asock;
  81 
  82         /* Child. */
  83         lsock = socket(AF_UNIX, SOCK_STREAM, 0);
  84         if (lsock == -1) {
  85                 fprintf(stderr, "listener - socket fail %s\n", strerror(errno));
  86                 exit(1);
  87         }
  88 
  89         ret = bind(lsock, (struct sockaddr *)addr, sizeof (*addr));
  90         if (ret == -1) {
  91                 fprintf(stderr, "listener - bind fail %s\n", strerror(errno));
  92                 exit(1);
  93         }
  94 
  95         ret = listen(lsock, 5);
  96         if (ret == -1) {
  97                 fprintf(stderr, "listener - listen fail %s\n", strerror(errno));
  98                 exit(1);
  99         }
 100 
 101         for (;;) {
 102                 asock = accept(lsock, NULL, 0);
 103                 if (asock == -1) {
 104                         fprintf(stderr, "listener - accept fail %s\n",
 105                             strerror(errno));
 106                         exit(1);
 107                 }
 108 
 109                 /* start worker */
 110                 ret = pthread_create(NULL, NULL, server, (void *)asock);
 111                 if (ret == -1) {
 112                         fprintf(stderr, "%s - thread create fail %s\n",
 113                             __progname, strerror(errno));
 114                         exit(1);
 115                 }
 116         }
 117 
 118         exit(0);
 119 }
 120 
 121 /*
 122  * This should be a place only root is allowed to write.
 123  * The test will create and destroy this directory.
 124  */
 125 char testdir[100] = "/var/run/os-tests-sockfs";
 126 struct sockaddr_un addr;
 127 int test_uid = UID_NOBODY;
 128 
 129 int
 130 main(int argc, char **argv)
 131 {
 132         int ret;
 133         int sock;
 134         unsigned int i;
 135 
 136         if (argc > 1) {
 137                 ret = strlcpy(testdir, argv[1], sizeof (testdir));
 138                 if (ret >= sizeof (testdir)) {
 139                         fprintf(stderr, "%s: too long\n", argv[1]);
 140                         exit(1);
 141                 }
 142         }
 143 
 144         addr.sun_family = AF_UNIX;
 145         (void) sprintf(addr.sun_path, "%s/s", testdir);
 146 
 147         if (mkdir(testdir, 0700) != 0) {
 148                 switch (errno) {
 149                 case EEXIST:
 150                 case EISDIR:
 151                         break;
 152                 default:
 153                         perror(testdir);
 154                         exit(1);
 155                 }
 156         }
 157         (void) unlink(addr.sun_path);
 158 
 159         /* Set up the listener. */
 160         ret = pthread_create(NULL, NULL, listener, &addr);
 161         if (ret == -1) {
 162                 fprintf(stderr, "%s - thread create fail %s\n",
 163                     argv[0], strerror(errno));
 164                 exit(1);
 165         }
 166 
 167         sleep(1);
 168 
 169         /* Create and connect the socket endpoint. */
 170 
 171         sock = socket(AF_UNIX, SOCK_STREAM, 0);
 172         if (sock == -1) {
 173                 fprintf(stderr, "%s - socket fail %s\n",
 174                     argv[0], strerror(errno));
 175                 exit(1);
 176         }
 177 
 178         ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
 179         if (ret == -1) {
 180                 fprintf(stderr, "%s - connect fail %s\n",
 181                     argv[0], strerror(errno));
 182                 exit(1);
 183         }
 184 
 185         /* Send some messages */
 186         for (i = 0; i < 5; i++) {
 187                 struct iovec iov;
 188                 struct msghdr msg;
 189                 uint8_t buf[4096];
 190 
 191                 memcpy(buf, "TEST0", sizeof ("TEST0"));
 192                 buf[4] = '0' + i;
 193 
 194                 printf("CLIENT:%s\n", buf);
 195 
 196                 iov = (struct iovec) {
 197                         .iov_base = buf,
 198                         .iov_len = sizeof (buf),
 199                 };
 200 
 201                 msg = (struct msghdr) {
 202                         .msg_iov = &iov,
 203                         .msg_iovlen = 1,
 204                 };
 205 
 206                 ret = sendmsg(sock, &msg, 0);
 207 
 208                 if (ret == -1) {
 209                         fprintf(stderr, "%s - sendmsg fail %s\n",
 210                             argv[0], strerror(errno));
 211                         exit(1);
 212                 }
 213 
 214                 fflush(stdout);
 215                 sleep(1);
 216         }
 217 
 218         close(sock);
 219         return (0);
 220 }