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 /*
  24  * Copyright 2019 Joyent, Inc.
  25  */
  26 
  27 #include <sys/param.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <sys/socket.h>
  31 #include <sys/un.h>
  32 #include <stdio.h>
  33 #include <unistd.h>
  34 #include <string.h>
  35 #include <errno.h>
  36 #include <stdint.h>
  37 #include <stdlib.h>
  38 #include <pthread.h>
  39 
  40 extern const char *__progname;
  41 
  42 static void *
  43 server(void *varg)
  44 {
  45         int ret;
  46         int sock = (int)varg;
  47         unsigned int i;
  48 
  49         for (i = 0; i < 5; i++) {
  50                 struct iovec iov;
  51                 struct msghdr msg;
  52                 uint8_t buf[4096];
  53 
  54                 iov = (struct iovec) {
  55                         .iov_base = buf,
  56                         .iov_len = sizeof (buf)
  57                 };
  58 
  59                 msg = (struct msghdr) {
  60                         .msg_iov = &iov,
  61                         .msg_iovlen = 1,
  62                 };
  63 
  64                 ret = recvmsg(sock, &msg, 0);
  65                 if (ret == -1) {
  66                         fprintf(stderr, "server - recvmsg fail %s\n",
  67                             strerror(errno));
  68                         exit(1);
  69                 }
  70 
  71                 printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
  72                 fflush(stdout);
  73         }
  74 
  75         exit(0);
  76 }
  77 
  78 static void *
  79 listener(void *varg)
  80 {
  81         struct sockaddr_un *addr = varg;
  82         int ret;
  83         int lsock;
  84         int asock;
  85 
  86         /* Child. */
  87         lsock = socket(AF_UNIX, SOCK_STREAM, 0);
  88         if (lsock == -1) {
  89                 fprintf(stderr, "listener - socket fail %s\n", strerror(errno));
  90                 exit(1);
  91         }
  92 
  93         ret = bind(lsock, (struct sockaddr *)addr, sizeof (*addr));
  94         if (ret == -1) {
  95                 fprintf(stderr, "listener - bind fail %s\n", strerror(errno));
  96                 exit(1);
  97         }
  98 
  99         ret = listen(lsock, 5);
 100         if (ret == -1) {
 101                 fprintf(stderr, "listener - listen fail %s\n", strerror(errno));
 102                 exit(1);
 103         }
 104 
 105         for (;;) {
 106                 asock = accept(lsock, NULL, 0);
 107                 if (asock == -1) {
 108                         fprintf(stderr, "listener - accept fail %s\n",
 109                             strerror(errno));
 110                         exit(1);
 111                 }
 112 
 113                 /* start worker */
 114                 ret = pthread_create(NULL, NULL, server, (void *)asock);
 115                 if (ret == -1) {
 116                         fprintf(stderr, "%s - thread create fail %s\n",
 117                             __progname, strerror(errno));
 118                         exit(1);
 119                 }
 120         }
 121 }
 122 
 123 /*
 124  * This should be a place only root is allowed to write.
 125  * The test will create and destroy this directory.
 126  */
 127 char testdir[100] = "/var/run/os-tests-sockfs";
 128 struct sockaddr_un addr;
 129 int test_uid = UID_NOBODY;
 130 
 131 int
 132 main(int argc, char **argv)
 133 {
 134         int ret;
 135         int sock;
 136         unsigned int i;
 137 
 138         if (argc > 1) {
 139                 ret = strlcpy(testdir, argv[1], sizeof (testdir));
 140                 if (ret >= sizeof (testdir)) {
 141                         fprintf(stderr, "%s: too long\n", argv[1]);
 142                         exit(1);
 143                 }
 144         }
 145 
 146         addr.sun_family = AF_UNIX;
 147         (void) sprintf(addr.sun_path, "%s/s", testdir);
 148 
 149         if (mkdir(testdir, 0700) != 0) {
 150                 switch (errno) {
 151                 case EEXIST:
 152                 case EISDIR:
 153                         break;
 154                 default:
 155                         perror(testdir);
 156                         exit(1);
 157                 }
 158         }
 159         (void) unlink(addr.sun_path);
 160 
 161         /* Set up the listener. */
 162         ret = pthread_create(NULL, NULL, listener, &addr);
 163         if (ret == -1) {
 164                 fprintf(stderr, "%s - thread create fail %s\n",
 165                     argv[0], strerror(errno));
 166                 exit(1);
 167         }
 168 
 169         sleep(1);
 170 
 171         /* Create and connect the socket endpoint. */
 172 
 173         sock = socket(AF_UNIX, SOCK_STREAM, 0);
 174         if (sock == -1) {
 175                 fprintf(stderr, "%s - socket fail %s\n",
 176                     argv[0], strerror(errno));
 177                 exit(1);
 178         }
 179 
 180         ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
 181         if (ret == -1) {
 182                 fprintf(stderr, "%s - connect fail %s\n",
 183                     argv[0], strerror(errno));
 184                 exit(1);
 185         }
 186 
 187         /* Send some messages */
 188         for (i = 0; i < 5; i++) {
 189                 struct iovec iov;
 190                 struct msghdr msg;
 191                 uint8_t buf[4096];
 192 
 193                 memcpy(buf, "TEST0", sizeof ("TEST0"));
 194                 buf[4] = '0' + i;
 195 
 196                 printf("CLIENT:%s\n", buf);
 197 
 198                 iov = (struct iovec) {
 199                         .iov_base = buf,
 200                         .iov_len = sizeof (buf),
 201                 };
 202 
 203                 msg = (struct msghdr) {
 204                         .msg_iov = &iov,
 205                         .msg_iovlen = 1,
 206                 };
 207 
 208                 ret = sendmsg(sock, &msg, 0);
 209 
 210                 if (ret == -1) {
 211                         fprintf(stderr, "%s - sendmsg fail %s\n",
 212                             argv[0], strerror(errno));
 213                         exit(1);
 214                 }
 215 
 216                 fflush(stdout);
 217                 sleep(1);
 218         }
 219 
 220         close(sock);
 221         return (0);
 222 }