* FIX: afpd: Fixes open file handle refcounting bug which was reported as
being unable to play movies off a Netatalk AFP share.
Bug ID 3559783.
+* FIX: afpd: Fix a possible data corruption when reading from and writing
+ to the server simultaniously under load
* FIX: Fix possible alignment violations due to bad casts
* FIX: dbd: Fix logging
* FIX: apple_dump: Extended Attributes AppleDouble support for *BSD
LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
err = (*afp_switch[function])(obj,
- (char *)&dsi->commands, dsi->cmdlen,
+ dsi->commands, dsi->cmdlen,
(char *)&dsi->data, &dsi->datalen);
LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
err = (*afp_switch[function])(obj,
- (char *)&dsi->commands, dsi->cmdlen,
+ dsi->commands, dsi->cmdlen,
(char *)&dsi->data, &dsi->datalen);
LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
uint16_t ofrefnum;
ssize_t cc;
DSI *dsi = obj->dsi;
- char *rcvbuf = dsi->buffer;
- size_t rcvbuflen = dsi->dsireadbuf * dsi->server_quantum;
+ char *rcvbuf = dsi->commands;
+ size_t rcvbuflen = dsi->server_quantum;
/* figure out parameters */
ibuf++;
return( AFP_OK );
afp_write_err:
- dsi_writeinit(obj->dsi, rbuf, *rbuflen);
- dsi_writeflush(obj->dsi);
+ dsi_writeinit(dsi, rcvbuf, rcvbuflen);
+ dsi_writeflush(dsi);
if (err != AFP_OK) {
*rbuflen = 0;
uint8_t dsi_flags; /* packet type: request or reply */
uint8_t dsi_command; /* command */
uint16_t dsi_requestID; /* request ID */
- uint32_t dsi_code; /* error code or data offset */
+ union {
+ uint32_t dsi_code; /* error code */
+ uint32_t dsi_doff; /* data offset */
+ };
uint32_t dsi_len; /* total data length */
uint32_t dsi_reserved; /* reserved field */
};
-#define DSI_CMDSIZ 8192
#define DSI_DATASIZ 8192
/* child and parent processes might interpret a couple of these
uint32_t attn_quantum, datasize, server_quantum;
uint16_t serverID, clientID;
- uint8_t commands[DSI_CMDSIZ], data[DSI_DATASIZ];
+ uint8_t *commands; /* DSI recieve buffer */
+ uint8_t data[DSI_DATASIZ]; /* DSI reply buffer */
size_t datalen, cmdlen;
off_t read_count, write_count;
uint32_t flags; /* DSI flags like DSI_SLEEPING, DSI_DISCONNECTED */
#include <atalk/util.h>
#include <atalk/logger.h>
-static void dsi_init_buffer(DSI *dsi)
-{
- /* default is 12 * 300k = 3,6 MB (Apr 2011) */
- if ((dsi->buffer = malloc(dsi->dsireadbuf * dsi->server_quantum)) == NULL) {
- LOG(log_error, logtype_dsi, "dsi_init_buffer: OOM");
- AFP_PANIC("OOM in dsi_init_buffer");
- }
- dsi->start = dsi->buffer;
- dsi->eof = dsi->buffer;
- dsi->end = dsi->buffer + (dsi->dsireadbuf * dsi->server_quantum);
-}
-
/* OpenSession. set up the connection */
void dsi_opensession(DSI *dsi)
{
uint32_t i = 0; /* this serves double duty. it must be 4-bytes long */
int offs;
- dsi_init_buffer(dsi);
if (setnonblock(dsi->socket, 1) < 0) {
LOG(log_error, logtype_dsi, "dsi_opensession: setnonblock: %s", strerror(errno));
AFP_PANIC("setnonblock error");
dsi->clientID = ntohs(dsi->header.dsi_requestID);
/* make sure we don't over-write our buffers. */
- dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
+ dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), dsi->server_quantum);
if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen)
return 0;
exit(EXITERR_CLNT);
}
+/*!
+ * Allocate DSI read buffer and read-ahead buffer
+ */
+static void dsi_init_buffer(DSI *dsi)
+{
+ if ((dsi->commands = malloc(dsi->server_quantum)) == NULL) {
+ LOG(log_error, logtype_dsi, "dsi_init_buffer: OOM");
+ AFP_PANIC("OOM in dsi_init_buffer");
+ }
+
+ /* dsi_peek() read ahead buffer, default is 12 * 300k = 3,6 MB (Apr 2011) */
+ if ((dsi->buffer = malloc(dsi->dsireadbuf * dsi->server_quantum)) == NULL) {
+ LOG(log_error, logtype_dsi, "dsi_init_buffer: OOM");
+ AFP_PANIC("OOM in dsi_init_buffer");
+ }
+ dsi->start = dsi->buffer;
+ dsi->eof = dsi->buffer;
+ dsi->end = dsi->buffer + (dsi->dsireadbuf * dsi->server_quantum);
+}
+
static struct itimerval itimer;
/* accept the socket and do a little sanity checking */
static int dsi_tcp_open(DSI *dsi)
}
#endif
+ dsi_init_buffer(dsi);
+
/* read in commands. this is similar to dsi_receive except
* for the fact that we do some sanity checking to prevent
* delinquent connections from causing mischief. */
dsi->clientID = ntohs(dsi->header.dsi_requestID);
/* make sure we don't over-write our buffers. */
- dsi->cmdlen = min(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
+ dsi->cmdlen = min(ntohl(dsi->header.dsi_len), dsi->server_quantum);
stored = 0;
while (stored < dsi->cmdlen) {
/* figure out how much data we have. do a couple checks for 0
* data */
- header = ntohl(dsi->header.dsi_code);
+ header = ntohl(dsi->header.dsi_doff);
dsi->datasize = header ? ntohl(dsi->header.dsi_len) - header : 0;
if (dsi->datasize > 0) {
- len = MIN(sizeof(dsi->commands) - header, dsi->datasize);
+ len = MIN(dsi->server_quantum - header, dsi->datasize);
/* write last part of command buffer into buf */
- memcpy(buf, dsi->commands + header, len);
+ memmove(buf, dsi->commands + header, len);
/* recalculate remaining data */
dsi->datasize -= len;