AFPBridge/dsi.c
Stephen Heumann 3f40a3190d Modify FPRead requests so they don’t return more data than will fit in the reply buffer.
This issue arises because ASP requests and replies are limited to a “quantum size” of 4624 bytes even if the amount requested is larger, and the AppleShare FST relies on this behavior in sizing its buffers. DSI does not have this limitation, so it was returning more data than would fit in the buffer.

Also improve error checking, so an error is reported in cases where the buffer is too small.
2017-04-03 16:36:50 -05:00

178 lines
5.5 KiB
C

#pragma noroot
#include <AppleTalk.h>
#include <stdlib.h>
#include <orca.h>
#include <tcpip.h>
#include "dsiproto.h"
#include "session.h"
#include "readtcp.h"
#include "dsi.h"
#include "endian.h"
#include "aspinterface.h"
static DSIRequestHeader tickleRequestRec = {
DSI_REQUEST, /* flags */
DSITickle, /* command */
0, /* requestID - set later */
0, /* writeOffset */
0, /* totalDataLength */
0 /* reserved */
};
/* Actually a reply, but use DSIRequestHeader type so we can send it. */
static DSIRequestHeader attentionReplyRec = {
DSI_REPLY, /* flags */
DSIAttention, /* command */
0, /* requestID - set later */
0, /* errorCode */
0, /* totalDataLength */
0 /* reserved */
};
void SendDSIMessage(Session *sess, DSIRequestHeader *header, void *payload,
void *extraPayload) {
LongWord cmdLen;
LongWord extraLen;
sess->tcperr = TCPIPWriteTCP(sess->ipid, (void*)header,
DSI_HEADER_SIZE,
!header->totalDataLength, FALSE);
sess->toolerr = toolerror();
if (sess->tcperr || sess->toolerr) {
FlagFatalError(sess, 0);
return;
}
if (header->writeOffset) {
cmdLen = ntohl(header->writeOffset);
extraLen = ntohl(header->totalDataLength) - cmdLen;
} else {
cmdLen = ntohl(header->totalDataLength);
extraLen = 0;
}
while (cmdLen) {
sess->tcperr = TCPIPWriteTCP(sess->ipid, payload, cmdLen,
!extraLen, FALSE);
sess->toolerr = toolerror();
if (sess->tcperr || sess->toolerr) {
FlagFatalError(sess, 0);
return;
}
cmdLen = extraLen;
payload = extraPayload;
extraLen = 0;
}
}
void PollForData(Session *sess) {
ReadStatus rs;
LongWord dataLength;
if (sess->dsiStatus != awaitingHeader && sess->dsiStatus != awaitingPayload)
return;
top:
rs = TryReadTCP(sess);
if (rs != rsDone) {
if (rs == rsError) FlagFatalError(sess, 0);
return;
}
// If we're here, we successfully read something.
if (sess->dsiStatus == awaitingHeader) {
if (sess->reply.totalDataLength != 0) {
dataLength = ntohl(sess->reply.totalDataLength);
if (sess->commandPending
&& sess->reply.flags == DSI_REPLY
&& sess->reply.requestID == sess->request.requestID
&& sess->reply.command == sess->request.command)
{
if (dataLength <= sess->replyBufLen) {
InitReadTCP(sess, dataLength, sess->replyBuf);
sess->dsiStatus = awaitingPayload;
goto top;
} else {
// handle data too long
sess->junkBuf = malloc(dataLength);
if (sess->junkBuf == NULL) {
FlagFatalError(sess, atMemoryErr);
return;
} else {
InitReadTCP(sess, dataLength, sess->junkBuf);
sess->dsiStatus = awaitingPayload;
goto top;
}
}
}
else if (sess->reply.flags == DSI_REQUEST
&& sess->reply.command == DSIAttention
&& dataLength <= DSI_ATTENTION_QUANTUM)
{
InitReadTCP(sess, DSI_ATTENTION_QUANTUM, &sess->attentionCode);
sess->dsiStatus = awaitingPayload;
goto top;
}
else
{
FlagFatalError(sess, aspSizeErr);
return;
}
}
}
// If we're here, we got a full message.
// Handle a command that is now done, if any.
if (sess->commandPending
&& sess->reply.flags == DSI_REPLY
&& sess->reply.requestID == sess->request.requestID
&& sess->reply.command == sess->request.command)
{
if (sess->junkBuf != NULL) {
free(sess->junkBuf);
sess->junkBuf = NULL;
if (sess->reply.command == DSIOpenSession) {
// We ignore the DSIOpenSession options for now.
// Maybe we should do something with them?
FinishASPCommand(sess);
} else {
CompleteASPCommand(sess, aspBufErr);
}
} else {
FinishASPCommand(sess);
}
return;
}
//Handle a request from the server
else if (sess->reply.flags == DSI_REQUEST)
{
if (sess->reply.command == DSIAttention) {
attentionReplyRec.requestID = sess->reply.requestID;
SendDSIMessage(sess, &attentionReplyRec, NULL, NULL);
//TODO call attention routine.
} else if (sess->reply.command == DSICloseSession) {
// TODO handle close
} else if (sess->reply.command == DSITickle) {
tickleRequestRec.requestID = htons(sess->nextRequestID++);
SendDSIMessage(sess, &tickleRequestRec, NULL, NULL);
} else {
FlagFatalError(sess, aspNetworkErr);
return;
}
sess->dsiStatus = awaitingHeader;
InitReadTCP(sess, DSI_HEADER_SIZE, &sess->reply);
}
else
{
FlagFatalError(sess, aspNetworkErr);
return;
}
}