1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include "namespace.h" 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <sys/event.h> 34 #include <sys/uio.h> 35 #include <sys/un.h> 36 #include <assert.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include "un-namespace.h" 43 #include "nscachedcli.h" 44 45 #define NS_DEFAULT_CACHED_IO_TIMEOUT 4 46 47 static int safe_write(struct cached_connection_ *, const void *, size_t); 48 static int safe_read(struct cached_connection_ *, void *, size_t); 49 static int send_credentials(struct cached_connection_ *, int); 50 51 /* 52 * safe_write writes data to the specified connection and tries to do it in 53 * the very safe manner. We ensure, that we can write to the socket with 54 * kevent. If the data_size can't be sent in one piece, then it would be 55 * splitted. 56 */ 57 static int 58 safe_write(struct cached_connection_ *connection, const void *data, 59 size_t data_size) 60 { 61 struct kevent eventlist; 62 int nevents; 63 size_t result; 64 ssize_t s_result; 65 struct timespec timeout; 66 67 if (data_size == 0) 68 return (0); 69 70 timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT; 71 timeout.tv_nsec = 0; 72 result = 0; 73 do { 74 nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 75 1, &timeout); 76 if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) { 77 s_result = _sendto(connection->sockfd, data + result, 78 eventlist.data < data_size - result ? 79 eventlist.data : data_size - result, MSG_NOSIGNAL, 80 NULL, 0); 81 if (s_result == -1) 82 return (-1); 83 else 84 result += s_result; 85 86 if (eventlist.flags & EV_EOF) 87 return (result < data_size ? -1 : 0); 88 } else 89 return (-1); 90 } while (result < data_size); 91 92 return (0); 93 } 94 95 /* 96 * safe_read reads data from connection and tries to do it in the very safe 97 * and stable way. It uses kevent to ensure, that the data are available for 98 * reading. If the amount of data to be read is too large, then they would 99 * be splitted. 100 */ 101 static int 102 safe_read(struct cached_connection_ *connection, void *data, size_t data_size) 103 { 104 struct kevent eventlist; 105 size_t result; 106 ssize_t s_result; 107 struct timespec timeout; 108 int nevents; 109 110 if (data_size == 0) 111 return (0); 112 113 timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT; 114 timeout.tv_nsec = 0; 115 result = 0; 116 do { 117 nevents = _kevent(connection->read_queue, NULL, 0, &eventlist, 118 1, &timeout); 119 if (nevents == 1 && eventlist.filter == EVFILT_READ) { 120 s_result = _read(connection->sockfd, data + result, 121 eventlist.data <= data_size - result ? 122 eventlist.data : data_size - result); 123 if (s_result == -1) 124 return (-1); 125 else 126 result += s_result; 127 128 if (eventlist.flags & EV_EOF) 129 return (result < data_size ? -1 : 0); 130 } else 131 return (-1); 132 } while (result < data_size); 133 134 return (0); 135 } 136 137 /* 138 * Sends the credentials information to the connection along with the 139 * communication element type. 140 */ 141 static int 142 send_credentials(struct cached_connection_ *connection, int type) 143 { 144 union { 145 struct cmsghdr hdr; 146 char pad[CMSG_SPACE(sizeof(struct cmsgcred))]; 147 } cmsg; 148 struct msghdr mhdr; 149 struct iovec iov; 150 struct kevent eventlist; 151 int nevents; 152 ssize_t result; 153 154 memset(&cmsg, 0, sizeof(cmsg)); 155 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 156 cmsg.hdr.cmsg_level = SOL_SOCKET; 157 cmsg.hdr.cmsg_type = SCM_CREDS; 158 159 memset(&mhdr, 0, sizeof(mhdr)); 160 mhdr.msg_iov = &iov; 161 mhdr.msg_iovlen = 1; 162 mhdr.msg_control = &cmsg; 163 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 164 165 iov.iov_base = &type; 166 iov.iov_len = sizeof(int); 167 168 EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 169 NOTE_LOWAT, sizeof(int), NULL); 170 (void)_kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 171 172 nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 1, 173 NULL); 174 if (nevents == 1 && eventlist.filter == EVFILT_WRITE) { 175 result = _sendmsg(connection->sockfd, &mhdr, 176 MSG_NOSIGNAL) == -1 ? -1 : 0; 177 EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD, 178 0, 0, NULL); 179 _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL); 180 return (result); 181 } else 182 return (-1); 183 } 184 185 /* 186 * Opens the connection with the specified params. Initializes all kqueues. 187 */ 188 struct cached_connection_ * 189 __open_cached_connection(struct cached_connection_params const *params) 190 { 191 struct cached_connection_ *retval; 192 struct kevent eventlist; 193 struct sockaddr_un client_address; 194 int client_address_len, client_socket; 195 int res; 196 197 assert(params != NULL); 198 199 client_socket = _socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); 200 client_address.sun_family = PF_LOCAL; 201 strncpy(client_address.sun_path, params->socket_path, 202 sizeof(client_address.sun_path)); 203 client_address_len = sizeof(client_address.sun_family) + 204 strlen(client_address.sun_path) + 1; 205 206 res = _connect(client_socket, (struct sockaddr *)&client_address, 207 client_address_len); 208 if (res == -1) { 209 _close(client_socket); 210 return (NULL); 211 } 212 _fcntl(client_socket, F_SETFL, O_NONBLOCK); 213 214 retval = malloc(sizeof(struct cached_connection_)); 215 assert(retval != NULL); 216 memset(retval, 0, sizeof(struct cached_connection_)); 217 218 retval->sockfd = client_socket; 219 220 retval->write_queue = kqueue(); 221 assert(retval->write_queue != -1); 222 223 EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); 224 res = _kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL); 225 226 retval->read_queue = kqueue(); 227 assert(retval->read_queue != -1); 228 229 EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL); 230 res = _kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL); 231 232 return (retval); 233 } 234 235 void 236 __close_cached_connection(struct cached_connection_ *connection) 237 { 238 assert(connection != NULL); 239 240 _close(connection->sockfd); 241 _close(connection->read_queue); 242 _close(connection->write_queue); 243 free(connection); 244 } 245 246 /* 247 * This function is very close to the cache_write function of the caching 248 * library, which is used in the caching daemon. It caches the data with the 249 * specified key in the cache entry with entry_name. 250 */ 251 int 252 __cached_write(struct cached_connection_ *connection, const char *entry_name, 253 const char *key, size_t key_size, const char *data, size_t data_size) 254 { 255 size_t name_size; 256 int error_code; 257 int result; 258 259 error_code = -1; 260 result = 0; 261 result = send_credentials(connection, CET_WRITE_REQUEST); 262 if (result != 0) 263 goto fin; 264 265 name_size = strlen(entry_name); 266 result = safe_write(connection, &name_size, sizeof(size_t)); 267 if (result != 0) 268 goto fin; 269 270 result = safe_write(connection, &key_size, sizeof(size_t)); 271 if (result != 0) 272 goto fin; 273 274 result = safe_write(connection, &data_size, sizeof(size_t)); 275 if (result != 0) 276 goto fin; 277 278 result = safe_write(connection, entry_name, name_size); 279 if (result != 0) 280 goto fin; 281 282 result = safe_write(connection, key, key_size); 283 if (result != 0) 284 goto fin; 285 286 result = safe_write(connection, data, data_size); 287 if (result != 0) 288 goto fin; 289 290 result = safe_read(connection, &error_code, sizeof(int)); 291 if (result != 0) 292 error_code = -1; 293 294 fin: 295 return (error_code); 296 } 297 298 /* 299 * This function is very close to the cache_read function of the caching 300 * library, which is used in the caching daemon. It reads cached data with the 301 * specified key from the cache entry with entry_name. 302 */ 303 int 304 __cached_read(struct cached_connection_ *connection, const char *entry_name, 305 const char *key, size_t key_size, char *data, size_t *data_size) 306 { 307 size_t name_size, result_size; 308 int error_code, rec_error_code; 309 int result; 310 311 assert(connection != NULL); 312 result = 0; 313 error_code = -1; 314 315 result = send_credentials(connection, CET_READ_REQUEST); 316 if (result != 0) 317 goto fin; 318 319 name_size = strlen(entry_name); 320 result = safe_write(connection, &name_size, sizeof(size_t)); 321 if (result != 0) 322 goto fin; 323 324 result = safe_write(connection, &key_size, sizeof(size_t)); 325 if (result != 0) 326 goto fin; 327 328 result = safe_write(connection, entry_name, name_size); 329 if (result != 0) 330 goto fin; 331 332 result = safe_write(connection, key, key_size); 333 if (result != 0) 334 goto fin; 335 336 result = safe_read(connection, &rec_error_code, sizeof(int)); 337 if (result != 0) 338 goto fin; 339 340 if (rec_error_code != 0) { 341 error_code = rec_error_code; 342 goto fin; 343 } 344 345 result = safe_read(connection, &result_size, sizeof(size_t)); 346 if (result != 0) 347 goto fin; 348 349 if (result_size > *data_size) { 350 *data_size = result_size; 351 error_code = -2; 352 goto fin; 353 } 354 355 result = safe_read(connection, data, result_size); 356 if (result != 0) 357 goto fin; 358 359 *data_size = result_size; 360 error_code = 0; 361 362 fin: 363 return (error_code); 364 } 365 366 /* 367 * Initializes the mp_write_session. For such a session the new connection 368 * would be opened. The data should be written to the session with 369 * __cached_mp_write function. The __close_cached_mp_write_session function 370 * should be used to submit session and __abandon_cached_mp_write_session - to 371 * abandon it. When the session is submitted, the whole se 372 */ 373 struct cached_connection_ * 374 __open_cached_mp_write_session(struct cached_connection_params const *params, 375 const char *entry_name) 376 { 377 struct cached_connection_ *connection, *retval; 378 size_t name_size; 379 int error_code; 380 int result; 381 382 retval = NULL; 383 connection = __open_cached_connection(params); 384 if (connection == NULL) 385 return (NULL); 386 connection->mp_flag = 1; 387 388 result = send_credentials(connection, CET_MP_WRITE_SESSION_REQUEST); 389 if (result != 0) 390 goto fin; 391 392 name_size = strlen(entry_name); 393 result = safe_write(connection, &name_size, sizeof(size_t)); 394 if (result != 0) 395 goto fin; 396 397 result = safe_write(connection, entry_name, name_size); 398 if (result != 0) 399 goto fin; 400 401 result = safe_read(connection, &error_code, sizeof(int)); 402 if (result != 0) 403 goto fin; 404 405 if (error_code != 0) 406 result = error_code; 407 408 fin: 409 if (result != 0) 410 __close_cached_connection(connection); 411 else 412 retval = connection; 413 return (retval); 414 } 415 416 /* 417 * Adds new portion of data to the opened write session 418 */ 419 int 420 __cached_mp_write(struct cached_connection_ *ws, const char *data, 421 size_t data_size) 422 { 423 int request, result; 424 int error_code; 425 426 error_code = -1; 427 428 request = CET_MP_WRITE_SESSION_WRITE_REQUEST; 429 result = safe_write(ws, &request, sizeof(int)); 430 if (result != 0) 431 goto fin; 432 433 result = safe_write(ws, &data_size, sizeof(size_t)); 434 if (result != 0) 435 goto fin; 436 437 result = safe_write(ws, data, data_size); 438 if (result != 0) 439 goto fin; 440 441 result = safe_read(ws, &error_code, sizeof(int)); 442 if (result != 0) 443 error_code = -1; 444 445 fin: 446 return (error_code); 447 } 448 449 /* 450 * Abandons all operations with the write session. All data, that were written 451 * to the session before, are discarded. 452 */ 453 int 454 __abandon_cached_mp_write_session(struct cached_connection_ *ws) 455 { 456 int notification; 457 int result; 458 459 notification = CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION; 460 result = safe_write(ws, ¬ification, sizeof(int)); 461 __close_cached_connection(ws); 462 return (result); 463 } 464 465 /* 466 * Gracefully closes the write session. The data, that were previously written 467 * to the session, are committed. 468 */ 469 int 470 __close_cached_mp_write_session(struct cached_connection_ *ws) 471 { 472 int notification; 473 474 notification = CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION; 475 (void)safe_write(ws, ¬ification, sizeof(int)); 476 __close_cached_connection(ws); 477 return (0); 478 } 479 480 struct cached_connection_ * 481 __open_cached_mp_read_session(struct cached_connection_params const *params, 482 const char *entry_name) 483 { 484 struct cached_connection_ *connection, *retval; 485 size_t name_size; 486 int error_code; 487 int result; 488 489 retval = NULL; 490 connection = __open_cached_connection(params); 491 if (connection == NULL) 492 return (NULL); 493 connection->mp_flag = 1; 494 495 result = send_credentials(connection, CET_MP_READ_SESSION_REQUEST); 496 if (result != 0) 497 goto fin; 498 499 name_size = strlen(entry_name); 500 result = safe_write(connection, &name_size, sizeof(size_t)); 501 if (result != 0) 502 goto fin; 503 504 result = safe_write(connection, entry_name, name_size); 505 if (result != 0) 506 goto fin; 507 508 result = safe_read(connection, &error_code, sizeof(int)); 509 if (result != 0) 510 goto fin; 511 512 if (error_code != 0) 513 result = error_code; 514 515 fin: 516 if (result != 0) 517 __close_cached_connection(connection); 518 else 519 retval = connection; 520 return (retval); 521 } 522 523 int 524 __cached_mp_read(struct cached_connection_ *rs, char *data, size_t *data_size) 525 { 526 size_t result_size; 527 int error_code, rec_error_code; 528 int request, result; 529 530 error_code = -1; 531 request = CET_MP_READ_SESSION_READ_REQUEST; 532 result = safe_write(rs, &request, sizeof(int)); 533 if (result != 0) 534 goto fin; 535 536 result = safe_read(rs, &rec_error_code, sizeof(int)); 537 if (result != 0) 538 goto fin; 539 540 if (rec_error_code != 0) { 541 error_code = rec_error_code; 542 goto fin; 543 } 544 545 result = safe_read(rs, &result_size, sizeof(size_t)); 546 if (result != 0) 547 goto fin; 548 549 if (result_size > *data_size) { 550 *data_size = result_size; 551 error_code = -2; 552 goto fin; 553 } 554 555 result = safe_read(rs, data, result_size); 556 if (result != 0) 557 goto fin; 558 559 *data_size = result_size; 560 error_code = 0; 561 562 fin: 563 return (error_code); 564 } 565 566 int 567 __close_cached_mp_read_session(struct cached_connection_ *rs) 568 { 569 570 __close_cached_connection(rs); 571 return (0); 572 } 573