1/* 2 * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu) 3 * All rights reserved. See COPYRIGHT. 4 * 5 * this file provides the following functions: 6 * dsi_stream_write: just write a bunch of bytes. 7 * dsi_stream_read: just read a bunch of bytes. 8 * dsi_stream_send: send a DSI header + data. 9 * dsi_stream_receive: read a DSI header + data. 10 */ 11 12#ifdef HAVE_CONFIG_H 13#include "config.h" 14#endif /* HAVE_CONFIG_H */ 15 16#include <stdio.h> 17#include <stdlib.h> 18 19#ifdef HAVE_UNISTD_H 20#include <unistd.h> 21#endif 22 23#include <string.h> 24#include <errno.h> 25#include <sys/types.h> 26#include <sys/socket.h> 27#include <sys/uio.h> 28 29#include <atalk/logger.h> 30#include <atalk/dsi.h> 31#include <netatalk/endian.h> 32#include <atalk/util.h> 33 34#define min(a,b) ((a) < (b) ? (a) : (b)) 35 36#ifndef MSG_MORE 37#define MSG_MORE 0x8000 38#endif 39 40#ifndef MSG_DONTWAIT 41#define MSG_DONTWAIT 0x40 42#endif 43 44/* 45 * afpd is sleeping too much while trying to send something. 46 * May be there's no reader or the reader is also sleeping in write, 47 * look if there's some data for us to read, hopefully it will wake up 48 * the reader so we can write again. 49 * 50 * @returns 0 when is possible to send again, -1 on error 51 */ 52static int dsi_peek(DSI *dsi) 53{ 54 static int warned = 0; 55 fd_set readfds, writefds; 56 int len; 57 int maxfd; 58 int ret; 59 60 LOG(log_debug, logtype_dsi, "dsi_peek"); 61 62 maxfd = dsi->socket + 1; 63 64 while (1) { 65 if (dsi->socket == -1) 66 /* eg dsi_disconnect() might have disconnected us */ 67 return -1; 68 FD_ZERO(&readfds); 69 FD_ZERO(&writefds); 70 71 if (dsi->eof < dsi->end) { 72 /* space in read buffer */ 73 FD_SET( dsi->socket, &readfds); 74 } else { 75 if (!warned) { 76 warned = 1; 77 LOG(log_note, logtype_dsi, "dsi_peek: readahead buffer is full, possibly increase -dsireadbuf option"); 78 LOG(log_note, logtype_dsi, "dsi_peek: dsireadbuf: %d, DSI quantum: %d, effective buffer size: %d", 79 dsi->dsireadbuf, 80 dsi->server_quantum ? dsi->server_quantum : DSI_SERVQUANT_DEF, 81 dsi->end - dsi->buffer); 82 } 83 } 84 85 FD_SET( dsi->socket, &writefds); 86 87 /* No timeout: if there's nothing to read nor nothing to write, 88 * we've got nothing to do at all */ 89 if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) { 90 if (ret == -1 && errno == EINTR) 91 /* we might have been interrupted by out timer, so restart select */ 92 continue; 93 /* give up */ 94 LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s", 95 ret, ret < 0 ? strerror(errno) : ""); 96 return -1; 97 } 98 99 if (FD_ISSET(dsi->socket, &writefds)) { 100 /* we can write again */ 101 LOG(log_debug, logtype_dsi, "dsi_peek: can write again"); 102 break; 103 } 104 105 /* Check if there's sth to read, hopefully reading that will unblock the client */ 106 if (FD_ISSET(dsi->socket, &readfds)) { 107 len = dsi->end - dsi->eof; /* it's ensured above that there's space */ 108 109 if ((len = read(dsi->socket, dsi->eof, len)) <= 0) { 110 if (len == 0) { 111 LOG(log_error, logtype_dsi, "dsi_peek: EOF"); 112 return -1; 113 } 114 LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno)); 115 if (errno == EAGAIN) 116 continue; 117 return -1; 118 } 119 LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len); 120 121 dsi->eof += len; 122 } 123 } 124 125 return 0; 126} 127 128/* 129 * Return all bytes up to count from dsi->buffer if there are any buffered there 130 */ 131static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count) 132{ 133 size_t nbe = 0; 134 135 if (dsi->buffer == NULL) 136 /* afpd master has no DSI buffering */ 137 return 0; 138 139 LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count); 140 141 nbe = dsi->eof - dsi->start; 142 143 if (nbe > 0) { 144 nbe = min((size_t)nbe, count); 145 memcpy(buf, dsi->start, nbe); 146 dsi->start += nbe; 147 148 if (dsi->eof == dsi->start) 149 dsi->start = dsi->eof = dsi->buffer; 150 } 151 152 LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u", 153 dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe); 154 155 return nbe; 156} 157 158/* 159 * Get bytes from buffer dsi->buffer or read from socket 160 * 161 * 1. Check if there are bytes in the the dsi->buffer buffer. 162 * 2. Return bytes from (1) if yes. 163 * Note: this may return fewer bytes then requested in count !! 164 * 3. If the buffer was empty, read from the socket. 165 */ 166static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count) 167{ 168 ssize_t len; 169 170 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count); 171 172 if (!count) 173 return 0; 174 175 len = from_buf(dsi, buf, count); /* 1. */ 176 if (len) 177 return len; /* 2. */ 178 179 len = readt(dsi->socket, buf, count, 0, 1); /* 3. */ 180 181 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len); 182 183 return len; 184} 185 186/* 187 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads 188 * this tries to read larger chunks (8192 bytes) into a buffer. 189 */ 190static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length) 191{ 192 size_t len; 193 size_t buflen; 194 195 LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length); 196 197 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */ 198 dsi->read_count += len; 199 if (len == length) { /* got enough bytes from there ? */ 200 return len; /* yes */ 201 } 202 203 /* fill the buffer with 8192 bytes or until buffer is full */ 204 buflen = min(8192, dsi->end - dsi->eof); 205 if (buflen > 0) { 206 ssize_t ret; 207 ret = read(dsi->socket, dsi->eof, buflen); 208 if (ret > 0) 209 dsi->eof += ret; 210 } 211 212 /* now get the remaining data */ 213 if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len) 214 return 0; 215 len += buflen; 216 217 return len; 218} 219 220/* --------------------------------------- 221*/ 222static void block_sig(DSI *dsi) 223{ 224 dsi->in_write++; 225} 226 227/* --------------------------------------- 228*/ 229static void unblock_sig(DSI *dsi) 230{ 231 dsi->in_write--; 232} 233 234/********************************************************************************* 235 * Public functions 236 *********************************************************************************/ 237 238/*! 239 * Communication error with the client, enter disconnected state 240 * 241 * 1. close the socket 242 * 2. set the DSI_DISCONNECTED flag, remove possible sleep flags 243 * 244 * @returns 0 if successfully entered disconnected state 245 * -1 if ppid is 1 which means afpd master died 246 * or euid == 0 ie where still running as root (unauthenticated session) 247 */ 248int dsi_disconnect(DSI *dsi) 249{ 250 LOG(log_note, logtype_dsi, "dsi_disconnect: entering disconnected state"); 251 dsi->proto_close(dsi); /* 1 */ 252 dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP); /* 2 */ 253 dsi->flags |= DSI_DISCONNECTED; 254 if (geteuid() == 0) 255 return -1; 256 return 0; 257} 258 259/* ------------------------------ 260 * write raw data. return actual bytes read. checks against EINTR 261 * aren't necessary if all of the signals have SA_RESTART 262 * specified. */ 263ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode) 264{ 265 size_t written; 266 ssize_t len; 267 unsigned int flags = 0; 268 269 dsi->in_write++; 270 written = 0; 271 272 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): START", length); 273 274 if (dsi->flags & DSI_DISCONNECTED) 275 return -1; 276 277 while (written < length) { 278 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags); 279 if (len >= 0) { 280 written += len; 281 continue; 282 } 283 284 if (errno == EINTR) 285 continue; 286 287 if (errno == EAGAIN || errno == EWOULDBLOCK) { 288 LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno)); 289 290 if (mode == DSI_NOWAIT && written == 0) { 291 /* DSI_NOWAIT is used by attention give up in this case. */ 292 written = -1; 293 goto exit; 294 } 295 296 /* Try to read sth. in order to break up possible deadlock */ 297 if (dsi_peek(dsi) != 0) { 298 written = -1; 299 goto exit; 300 } 301 /* Now try writing again */ 302 continue; 303 } 304 305 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno)); 306 written = -1; 307 goto exit; 308 } 309 310 dsi->write_count += written; 311 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write(send: %zd bytes): END", length); 312 313exit: 314 dsi->in_write--; 315 return written; 316} 317 318 319/* --------------------------------- 320*/ 321#ifdef WITH_SENDFILE 322ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length) 323{ 324 int ret = 0; 325 size_t written; 326 ssize_t len; 327 off_t pos = offset; 328 329 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(send %zd bytes): START", length); 330 331 if (dsi->flags & DSI_DISCONNECTED) 332 return -1; 333 334 dsi->in_write++; 335 written = 0; 336 337 while (written < length) { 338 len = sys_sendfile(dsi->socket, fromfd, &pos, length - written); 339 340 if (len < 0) { 341 if (errno == EINVAL || errno == ENOSYS) { 342 ret = -1; 343 goto exit; 344 } 345 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { 346 /* 347 * May return EINTR too, see: 348 * http://wesunsolve.net/bugid/id/6408517 349 * https://issues.apache.org/bugzilla/show_bug.cgi?id=44550 350 */ 351#if defined(SOLARIS) || defined(FREEBSD) 352 if (pos > offset) { 353 /* we actually have sent sth., adjust counters and keep trying */ 354 len = pos - offset; 355 written += len; 356 offset = pos; 357 } 358#endif 359 if (dsi_peek(dsi)) { 360 /* can't go back to blocking mode, exit, the next read 361 will return with an error and afpd will die. 362 */ 363 break; 364 } 365 continue; 366 } 367 LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno)); 368 break; 369 } 370 else if (!len) { 371 /* afpd is going to exit */ 372 ret = -1; 373 goto exit; 374 } 375 else 376 written += len; 377 } 378 379 dsi->write_count += written; 380 381exit: 382 dsi->in_write--; 383 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sent: %zd", written); 384 if (ret != 0) 385 return -1; 386 return written; 387} 388#endif 389 390 391/* 392 * Essentially a loop around buf_read() to ensure "length" bytes are read 393 * from dsi->buffer and/or the socket. 394 * 395 * @returns length on success, some value smaller then length indicates an error 396 */ 397size_t dsi_stream_read(DSI *dsi, void *data, const size_t length) 398{ 399 size_t stored; 400 ssize_t len; 401 402 if (dsi->flags & DSI_DISCONNECTED) 403 return 0; 404 405 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length); 406 407 stored = 0; 408 while (stored < length) { 409 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored); 410 if (len == -1 && (errno == EINTR || errno == EAGAIN)) { 411 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop"); 412 continue; 413 } else if (len > 0) { 414 stored += len; 415 } else { /* eof or error */ 416 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */ 417#if 0 418 if (errno == ECONNRESET) 419 dsi->flags |= DSI_GOT_ECONNRESET; 420#endif 421 if (len || stored || dsi->read_count) { 422 if (! (dsi->flags & DSI_DISCONNECTED)) { 423 LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s", 424 len, (len < 0) ? strerror(errno) : "unexpected EOF"); 425 } 426 return 0; 427 } 428 break; 429 } 430 } 431 432 dsi->read_count += stored; 433 434 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored); 435 return stored; 436} 437 438/* --------------------------------------- 439 * write data. 0 on failure. this assumes that dsi_len will never 440 * cause an overflow in the data buffer. 441 */ 442int dsi_stream_send(DSI *dsi, void *buf, size_t length) 443{ 444 char block[DSI_BLOCKSIZ]; 445 struct iovec iov[2]; 446 size_t towrite; 447 ssize_t len; 448 449 LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): START", length); 450 451 if (dsi->flags & DSI_DISCONNECTED) 452 return 0; 453 454 block[0] = dsi->header.dsi_flags; 455 block[1] = dsi->header.dsi_command; 456 memcpy(block + 2, &dsi->header.dsi_requestID, 457 sizeof(dsi->header.dsi_requestID)); 458 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code)); 459 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len)); 460 memcpy(block + 12, &dsi->header.dsi_reserved, 461 sizeof(dsi->header.dsi_reserved)); 462 463 if (!length) { /* just write the header */ 464 LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block)); 465 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block)); 466 return length; /* really 0 on failure, 1 on success */ 467 } 468 469 /* block signals */ 470 block_sig(dsi); 471 iov[0].iov_base = block; 472 iov[0].iov_len = sizeof(block); 473 iov[1].iov_base = buf; 474 iov[1].iov_len = length; 475 476 towrite = sizeof(block) + length; 477 dsi->write_count += towrite; 478 while (towrite > 0) { 479 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0)) 480 continue; 481 482 if ((size_t)len == towrite) /* wrote everything out */ 483 break; 484 else if (len < 0) { /* error */ 485 if (errno == EAGAIN || errno == EWOULDBLOCK) { 486 if (!dsi_peek(dsi)) { 487 continue; 488 } 489 } 490 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno)); 491 unblock_sig(dsi); 492 return 0; 493 } 494 495 towrite -= len; 496 if (towrite > length) { /* skip part of header */ 497 iov[0].iov_base = (char *) iov[0].iov_base + len; 498 iov[0].iov_len -= len; 499 } else { /* skip to data */ 500 if (iov[0].iov_len) { 501 len -= iov[0].iov_len; 502 iov[0].iov_len = 0; 503 } 504 iov[1].iov_base = (char *) iov[1].iov_base + len; 505 iov[1].iov_len -= len; 506 } 507 } 508 509 LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): END", length); 510 511 unblock_sig(dsi); 512 return 1; 513} 514 515 516/*! 517 * Read DSI command and data 518 * 519 * @param dsi (rw) DSI handle 520 * 521 * @return DSI function on success, 0 on failure 522 */ 523int dsi_stream_receive(DSI *dsi) 524{ 525 char block[DSI_BLOCKSIZ]; 526 527 LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START"); 528 529 if (dsi->flags & DSI_DISCONNECTED) 530 return 0; 531 532 /* read in the header */ 533 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block)) 534 return 0; 535 536 dsi->header.dsi_flags = block[0]; 537 dsi->header.dsi_command = block[1]; 538 539 if (dsi->header.dsi_command == 0) 540 return 0; 541 542 memcpy(&dsi->header.dsi_requestID, block + 2, sizeof(dsi->header.dsi_requestID)); 543 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code)); 544 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len)); 545 memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved)); 546 dsi->clientID = ntohs(dsi->header.dsi_requestID); 547 548 /* make sure we don't over-write our buffers. */ 549 dsi->cmdlen = min(ntohl(dsi->header.dsi_len), DSI_CMDSIZ); 550 if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen) 551 return 0; 552 553 LOG(log_debug, logtype_dsi, "dsi_stream_receive: DSI cmdlen: %zd", dsi->cmdlen); 554 555 return block[1]; 556} 557