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 FD_ZERO(&readfds); 66 FD_ZERO(&writefds); 67 68 if (dsi->eof < dsi->end) { 69 /* space in read buffer */ 70 FD_SET( dsi->socket, &readfds); 71 } else { 72 if (!warned) { 73 warned = 1; 74 LOG(log_note, logtype_dsi, "dsi_peek: readahead buffer is full, possibly increase -dsireadbuf option"); 75 LOG(log_note, logtype_dsi, "dsi_peek: dsireadbuf: %d, DSI quantum: %d, effective buffer size: %d", 76 dsi->dsireadbuf, 77 dsi->server_quantum ? dsi->server_quantum : DSI_SERVQUANT_DEF, 78 dsi->end - dsi->buffer); 79 } 80 } 81 82 FD_SET( dsi->socket, &writefds); 83 84 /* No timeout: if there's nothing to read nor nothing to write, 85 * we've got nothing to do at all */ 86 if ((ret = select( maxfd, &readfds, &writefds, NULL, NULL)) <= 0) { 87 if (ret == -1 && errno == EINTR) 88 /* we might have been interrupted by out timer, so restart select */ 89 continue; 90 /* give up */ 91 LOG(log_error, logtype_dsi, "dsi_peek: unexpected select return: %d %s", 92 ret, ret < 0 ? strerror(errno) : ""); 93 return -1; 94 } 95 96 if (FD_ISSET(dsi->socket, &writefds)) { 97 /* we can write again */ 98 LOG(log_debug, logtype_dsi, "dsi_peek: can write again"); 99 break; 100 } 101 102 /* Check if there's sth to read, hopefully reading that will unblock the client */ 103 if (FD_ISSET(dsi->socket, &readfds)) { 104 len = dsi->end - dsi->eof; /* it's ensured above that there's space */ 105 106 if ((len = read(dsi->socket, dsi->eof, len)) <= 0) { 107 if (len == 0) { 108 LOG(log_error, logtype_dsi, "dsi_peek: EOF"); 109 return -1; 110 } 111 LOG(log_error, logtype_dsi, "dsi_peek: read: %s", strerror(errno)); 112 if (errno == EAGAIN) 113 continue; 114 return -1; 115 } 116 LOG(log_debug, logtype_dsi, "dsi_peek: read %d bytes", len); 117 118 dsi->eof += len; 119 } 120 } 121 122 return 0; 123} 124 125/* 126 * Return all bytes up to count from dsi->buffer if there are any buffered there 127 */ 128static size_t from_buf(DSI *dsi, u_int8_t *buf, size_t count) 129{ 130 size_t nbe = 0; 131 132 if (dsi->buffer == NULL) 133 /* afpd master has no DSI buffering */ 134 return 0; 135 136 LOG(log_maxdebug, logtype_dsi, "from_buf: %u bytes", count); 137 138 nbe = dsi->eof - dsi->start; 139 140 if (nbe > 0) { 141 nbe = min((size_t)nbe, count); 142 memcpy(buf, dsi->start, nbe); 143 dsi->start += nbe; 144 145 if (dsi->eof == dsi->start) 146 dsi->start = dsi->eof = dsi->buffer; 147 } 148 149 LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u", 150 dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe); 151 152 return nbe; 153} 154 155/* 156 * Get bytes from buffer dsi->buffer or read from socket 157 * 158 * 1. Check if there are bytes in the the dsi->buffer buffer. 159 * 2. Return bytes from (1) if yes. 160 * Note: this may return fewer bytes then requested in count !! 161 * 3. If the buffer was empty, read from the socket. 162 */ 163static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count) 164{ 165 ssize_t len; 166 167 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count); 168 169 if (!count) 170 return 0; 171 172 len = from_buf(dsi, buf, count); /* 1. */ 173 if (len) 174 return len; /* 2. */ 175 176 len = readt(dsi->socket, buf, count, 0, 1); /* 3. */ 177 178 LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len); 179 180 return len; 181} 182 183/* 184 * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads 185 * this tries to read larger chunks (8192 bytes) into a buffer. 186 */ 187static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length) 188{ 189 size_t len; 190 size_t buflen; 191 192 LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length); 193 194 len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */ 195 dsi->read_count += len; 196 if (len == length) { /* got enough bytes from there ? */ 197 return len; /* yes */ 198 } 199 200 /* fill the buffer with 8192 bytes or until buffer is full */ 201 buflen = min(8192, dsi->end - dsi->eof); 202 if (buflen > 0) { 203 ssize_t ret; 204 ret = read(dsi->socket, dsi->eof, buflen); 205 if (ret > 0) 206 dsi->eof += ret; 207 } 208 209 /* now get the remaining data */ 210 if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len) 211 return 0; 212 len += buflen; 213 214 return len; 215} 216 217/* --------------------------------------- 218*/ 219static void block_sig(DSI *dsi) 220{ 221 dsi->in_write++; 222} 223 224/* --------------------------------------- 225*/ 226static void unblock_sig(DSI *dsi) 227{ 228 dsi->in_write--; 229} 230 231/********************************************************************************* 232 * Public functions 233 *********************************************************************************/ 234 235/*! 236 * Communication error with the client, enter disconnected state 237 * 238 * 1. close the socket 239 * 2. set the DSI_DISCONNECTED flag 240 * 241 * @returns 0 if successfully entered disconnected state 242 * -1 if ppid is 1 which means afpd master died 243 * or euid == 0 ie where still running as root (unauthenticated session) 244 */ 245int dsi_disconnect(DSI *dsi) 246{ 247 dsi->proto_close(dsi); /* 1 */ 248 dsi->flags |= DSI_DISCONNECTED; /* 2 */ 249 if (geteuid() == 0) 250 return -1; 251 return 0; 252} 253 254/* ------------------------------ 255 * write raw data. return actual bytes read. checks against EINTR 256 * aren't necessary if all of the signals have SA_RESTART 257 * specified. */ 258ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode) 259{ 260 size_t written; 261 ssize_t len; 262 unsigned int flags = 0; 263 264 dsi->in_write++; 265 written = 0; 266 267 LOG(log_maxdebug, logtype_dsi, "dsi_stream_write: sending %u bytes", length); 268 269 if (dsi->flags & DSI_DISCONNECTED) 270 return -1; 271 272 while (written < length) { 273 len = send(dsi->socket, (u_int8_t *) data + written, length - written, flags); 274 if (len >= 0) { 275 written += len; 276 continue; 277 } 278 279 if (errno == EINTR) 280 continue; 281 282 if (errno == EAGAIN || errno == EWOULDBLOCK) { 283 LOG(log_debug, logtype_dsi, "dsi_stream_write: send: %s", strerror(errno)); 284 285 if (mode == DSI_NOWAIT && written == 0) { 286 /* DSI_NOWAIT is used by attention give up in this case. */ 287 written = -1; 288 goto exit; 289 } 290 291 /* Try to read sth. in order to break up possible deadlock */ 292 if (dsi_peek(dsi) != 0) { 293 written = -1; 294 goto exit; 295 } 296 /* Now try writing again */ 297 continue; 298 } 299 300 LOG(log_error, logtype_dsi, "dsi_stream_write: %s", strerror(errno)); 301 written = -1; 302 goto exit; 303 } 304 305 dsi->write_count += written; 306 307exit: 308 dsi->in_write--; 309 return written; 310} 311 312 313/* --------------------------------- 314*/ 315#ifdef WITH_SENDFILE 316ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length) 317{ 318 size_t written; 319 ssize_t len; 320 321 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length); 322 323 if (dsi->flags & DSI_DISCONNECTED) 324 return -1; 325 326 dsi->in_write++; 327 written = 0; 328 329 while (written < length) { 330 len = sys_sendfile(dsi->socket, fromfd, &offset, length - written); 331 332 if (len < 0) { 333 if (errno == EINTR) 334 continue; 335 if (errno == EINVAL || errno == ENOSYS) 336 return -1; 337 338 if (errno == EAGAIN || errno == EWOULDBLOCK) { 339 if (dsi_peek(dsi)) { 340 /* can't go back to blocking mode, exit, the next read 341 will return with an error and afpd will die. 342 */ 343 break; 344 } 345 continue; 346 } 347 LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno)); 348 break; 349 } 350 else if (!len) { 351 /* afpd is going to exit */ 352 errno = EIO; 353 return -1; /* I think we're at EOF here... */ 354 } 355 else 356 written += len; 357 } 358 359 dsi->write_count += written; 360 dsi->in_write--; 361 return written; 362} 363#endif 364 365 366/* 367 * Essentially a loop around buf_read() to ensure "length" bytes are read 368 * from dsi->buffer and/or the socket. 369 * 370 * @returns length on success, some value smaller then length indicates an error 371 */ 372size_t dsi_stream_read(DSI *dsi, void *data, const size_t length) 373{ 374 size_t stored; 375 ssize_t len; 376 377 if (dsi->flags & DSI_DISCONNECTED) 378 return 0; 379 380 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes)", length); 381 382 stored = 0; 383 while (stored < length) { 384 len = buf_read(dsi, (u_int8_t *) data + stored, length - stored); 385 if (len == -1 && (errno == EINTR || errno == EAGAIN)) { 386 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read: select read loop"); 387 continue; 388 } else if (len > 0) { 389 stored += len; 390 } else { /* eof or error */ 391 /* don't log EOF error if it's just after connect (OSX 10.3 probe) */ 392 if (errno == ECONNRESET) 393 dsi->flags |= DSI_GOT_ECONNRESET; 394 if (len || stored || dsi->read_count) { 395 if (! (dsi->flags & DSI_DISCONNECTED)) { 396 LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s", 397 len, (len < 0) ? strerror(errno) : "unexpected EOF"); 398 } 399 return 0; 400 } 401 break; 402 } 403 } 404 405 dsi->read_count += stored; 406 407 LOG(log_maxdebug, logtype_dsi, "dsi_stream_read(%u bytes): got: %u", length, stored); 408 return stored; 409} 410 411/* --------------------------------------- 412 * write data. 0 on failure. this assumes that dsi_len will never 413 * cause an overflow in the data buffer. 414 */ 415int dsi_stream_send(DSI *dsi, void *buf, size_t length) 416{ 417 char block[DSI_BLOCKSIZ]; 418 struct iovec iov[2]; 419 size_t towrite; 420 ssize_t len; 421 422 LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes", 423 length ? length : sizeof(block)); 424 425 if (dsi->flags & DSI_DISCONNECTED) 426 return 0; 427 428 block[0] = dsi->header.dsi_flags; 429 block[1] = dsi->header.dsi_command; 430 memcpy(block + 2, &dsi->header.dsi_requestID, 431 sizeof(dsi->header.dsi_requestID)); 432 memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code)); 433 memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len)); 434 memcpy(block + 12, &dsi->header.dsi_reserved, 435 sizeof(dsi->header.dsi_reserved)); 436 437 if (!length) { /* just write the header */ 438 length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block)); 439 return length; /* really 0 on failure, 1 on success */ 440 } 441 442 /* block signals */ 443 block_sig(dsi); 444 iov[0].iov_base = block; 445 iov[0].iov_len = sizeof(block); 446 iov[1].iov_base = buf; 447 iov[1].iov_len = length; 448 449 towrite = sizeof(block) + length; 450 dsi->write_count += towrite; 451 while (towrite > 0) { 452 if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0)) 453 continue; 454 455 if ((size_t)len == towrite) /* wrote everything out */ 456 break; 457 else if (len < 0) { /* error */ 458 if (errno == EAGAIN || errno == EWOULDBLOCK) { 459 if (!dsi_peek(dsi)) { 460 continue; 461 } 462 } 463 LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno)); 464 unblock_sig(dsi); 465 return 0; 466 } 467 468 towrite -= len; 469 if (towrite > length) { /* skip part of header */ 470 iov[0].iov_base = (char *) iov[0].iov_base + len; 471 iov[0].iov_len -= len; 472 } else { /* skip to data */ 473 if (iov[0].iov_len) { 474 len -= iov[0].iov_len; 475 iov[0].iov_len = 0; 476 } 477 iov[1].iov_base = (char *) iov[1].iov_base + len; 478 iov[1].iov_len -= len; 479 } 480 } 481 482 unblock_sig(dsi); 483 return 1; 484} 485 486 487/* --------------------------------------- 488 * read data. function on success. 0 on failure. data length gets 489 * stored in length variable. this should really use size_t's, but 490 * that would require changes elsewhere. */ 491int dsi_stream_receive(DSI *dsi, void *buf, const size_t ilength, 492 size_t *rlength) 493{ 494 char block[DSI_BLOCKSIZ]; 495 496 LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: %u bytes", ilength); 497 498 if (dsi->flags & DSI_DISCONNECTED) 499 return 0; 500 501 /* read in the header */ 502 if (dsi_buffered_stream_read(dsi, (u_int8_t *)block, sizeof(block)) != sizeof(block)) 503 return 0; 504 505 dsi->header.dsi_flags = block[0]; 506 dsi->header.dsi_command = block[1]; 507 /* FIXME, not the right place, 508 but we get a server disconnect without reason in the log 509 */ 510 if (!block[1]) { 511 LOG(log_error, logtype_dsi, "dsi_stream_receive: invalid packet, fatal"); 512 return 0; 513 } 514 515 memcpy(&dsi->header.dsi_requestID, block + 2, 516 sizeof(dsi->header.dsi_requestID)); 517 memcpy(&dsi->header.dsi_code, block + 4, sizeof(dsi->header.dsi_code)); 518 memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len)); 519 memcpy(&dsi->header.dsi_reserved, block + 12, 520 sizeof(dsi->header.dsi_reserved)); 521 dsi->clientID = ntohs(dsi->header.dsi_requestID); 522 523 /* make sure we don't over-write our buffers. */ 524 *rlength = min(ntohl(dsi->header.dsi_len), ilength); 525 if (dsi_stream_read(dsi, buf, *rlength) != *rlength) 526 return 0; 527 528 return block[1]; 529} 530