commit ef272cb9987741fd3f81fa232e7ba99fb7a6aa81 Author: Stephen Heumann Date: Sun Jul 29 23:40:03 2018 -0500 Initial code implementing some of the core functionality for reading blocks over HTTP. diff --git a/hostname.c b/hostname.c new file mode 100644 index 0000000..91bc278 --- /dev/null +++ b/hostname.c @@ -0,0 +1,27 @@ +#include +#include +#include "hostname.h" + +#define DNR_WAIT_TIME 15 /*seconds*/ + +Boolean DoLookupName(Session *sess) { + dnrBuffer dnrInfo; + + TCPIPDNRNameToIP(sess->domainName, &dnrInfo); + if (toolerror()) + return FALSE; + + sess->dnsTime = GetTick(); + while (dnrInfo.DNRstatus == DNR_Pending) { + if (GetTick() - sess->dnsTime >= DNR_WAIT_TIME * 60) + break; + TCPIPPoll(); + } + + if (dnrInfo.DNRstatus == DNR_OK) { + sess->ipAddr = dnrInfo.DNRIPaddress; + return TRUE; + } else { + return FALSE; + } +} diff --git a/hostname.h b/hostname.h new file mode 100644 index 0000000..f91bdff --- /dev/null +++ b/hostname.h @@ -0,0 +1,9 @@ +#ifndef HOSTNAME_H +#define HOSTNAME_H + +#include +#include "session.h" + +Boolean DoLookupName(Session *sess); + +#endif diff --git a/http.c b/http.c new file mode 100644 index 0000000..e4470a6 --- /dev/null +++ b/http.c @@ -0,0 +1,53 @@ +#pragma lint -1 +#pragma noroot + +#include +#include +#include +#include "session.h" +#include "http.h" + +Boolean BuildHTTPRequest(Session *sess, char *resourceStr, char *hostStr) { + int sizeNeeded = 0; + int rangeOffset; + int round = 0; + + do { + sizeNeeded = snprintf(sess->httpRequest, sizeNeeded, + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: GSRemoteDisk/0.1\r\n" + "Accept-Encoding: identity\r\n" + //"Accept: */*\r\n" /* default, but some clients send explicitly */ + //"Connection: Keep-Alive\r\n" /* same */ + "Range: bytes=%n1234567890-1234567890\r\n" + "\r\n", + resourceStr, + hostStr, + &rangeOffset); + + if (sizeNeeded <= 0) { + free(sess->httpRequest); + sess->httpRequest = NULL; + sess->httpRequestRange = NULL; + return FALSE; + } + + if (round == 0) { + sizeNeeded++; /* account for terminating NUL */ + free(sess->httpRequest); + sess->httpRequest = malloc(sizeNeeded); + if (sess->httpRequest == NULL) { + sess->httpRequestRange = NULL; + return FALSE; + } + } + } while (round++ == 0); + + sess->httpRequestRange = sess->httpRequest + rangeOffset; + return TRUE; +} + +void UpdateRequestRange(Session *sess, unsigned long start, unsigned long end) { + snprintf(sess->httpRequestRange, 10+1+10+5, "%lu-%lu\r\n\r\n", start, end); +} diff --git a/http.h b/http.h new file mode 100644 index 0000000..25a949c --- /dev/null +++ b/http.h @@ -0,0 +1,10 @@ +#ifndef HTTP_H +#define HTTP_H + +#include +#include "session.h" + +Boolean BuildHTTPRequest(Session *sess, char *resourceStr, char *hostStr); +void UpdateRequestRange(Session *sess, unsigned long start, unsigned long end); + +#endif \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..27a7b0d --- /dev/null +++ b/main.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include "http.h" +#include "session.h" +#include "hostname.h" + +#define buffTypePointer 0x0000 /* For TCPIPReadTCP() */ +#define buffTypeHandle 0x0001 +#define buffTypeNewHandle 0x0002 + +/* +http://archive.org/download/a2gs_System_1.0_1986_Apple_FW/System_1.0_1986_Apple_FW.2mg +redirects to: +http://ia800505.us.archive.org/16/items/a2gs_System_1.0_1986_Apple_FW/System_1.0_1986_Apple_FW.2mg +*/ + +static char delimitStr[] = "\p\r\n\r\n"; + +int main(void) { + TLStartUp(); + + LoadOneTool(54,0x200); + TCPIPStartUp(); + + TCPIPConnect(NULL); + + Session sess; + FILE *f = fopen("out", "wb"); + + BuildHTTPRequest(&sess, "/16/items/a2gs_System_1.0_1986_Apple_FW/System_1.0_1986_Apple_FW.2mg", "ia800505.us.archive.org"); + fputs(sess.httpRequest, f); + + UpdateRequestRange(&sess, 0, 511); + fputs(sess.httpRequest, f); + + strcpy(sess.domainName, "\pia800505.us.archive.org"); + Boolean result = DoLookupName(&sess); + + if (result) { + printf("IP = %lu.%lu.%lu.%lu\n", + sess.ipAddr & 0xFF, + (sess.ipAddr >> 8) & 0xFF, + (sess.ipAddr >> 16) & 0xFF, + (sess.ipAddr >> 24)); + } else { + printf("Address lookup failed\n"); + goto exit; + } + + sess.port = 80; + + int err; + if ((err = StartTCPConnection(&sess)) != 0) { + printf("StartTCPConnection error %i\n", err); + goto exit; + } + + TCPIPWriteTCP(sess.ipid, sess.httpRequest, strlen(sess.httpRequest), TRUE, FALSE); + + LongWord startTime = GetTick(); + + while (GetTick() - startTime < 3*60) { + //printf("polling\n"); + TCPIPPoll(); + } + + rlrBuff rlrBuff; + TCPIPReadLineTCP(sess.ipid, (void*)((LongWord)delimitStr | 0x80000000), + buffTypeNewHandle, (Ref)NULL, + 0xFFFFFF, &rlrBuff); + + printf("Response:\n"); + printf("=========\n"); + for (int i = 0; i < rlrBuff.rlrBuffCount; i++) { + char ch = ((char*)*(rlrBuff.rlrBuffHandle))[i]; + if (ch != '\r') + putchar(ch); + } + //printf("%s\n", *(rlrBuff.rlrBuffHandle)); + printf("=========\n"); + + printf("Response headers handle size = %lu \n", GetHandleSize(rlrBuff.rlrBuffHandle)); + printf("Reported response size = %lu \n", rlrBuff.rlrBuffCount); + + EndTCPConnection(&sess); + +exit: + TCPIPShutDown(); + UnloadOneTool(54); + TLShutDown(); +} diff --git a/readtcp.c b/readtcp.c new file mode 100644 index 0000000..79124bc --- /dev/null +++ b/readtcp.c @@ -0,0 +1,38 @@ +#pragma noroot + +#include "readtcp.h" +#include "session.h" +#include +#include + +#define buffTypePointer 0x0000 /* For TCPIPReadTCP() */ +#define buffTypeHandle 0x0001 +#define buffTypeNewHandle 0x0002 + +void InitReadTCP(Session *sess, LongWord readCount, void *readPtr) { + sess->readCount = readCount; + sess->readPtr = readPtr; +} + + +ReadStatus TryReadTCP(Session *sess) { + rrBuff rrBuff; + + TCPIPPoll(); + sess->tcperr = TCPIPReadTCP(sess->ipid, buffTypePointer, (Ref)sess->readPtr, + sess->readCount, &rrBuff); + sess->toolerr = toolerror(); + if (sess->tcperr || sess->toolerr) { + /*sess->dsiStatus = error;*/ + return rsError; + } + + sess->readCount -= rrBuff.rrBuffCount; + sess->readPtr += rrBuff.rrBuffCount; + + if (sess->readCount == 0) { + return rsDone; + } else { + return rsWaiting; + } +} diff --git a/readtcp.h b/readtcp.h new file mode 100644 index 0000000..e1b58ed --- /dev/null +++ b/readtcp.h @@ -0,0 +1,15 @@ +#ifndef READTCP_H +#define READTCP_H + +#include "session.h" + +typedef enum ReadStatus { + rsDone, + rsWaiting, + rsError +} ReadStatus; + +void InitReadTCP(Session *sess, LongWord readCount, void *readPtr); +ReadStatus TryReadTCP(Session *sess); + +#endif diff --git a/session.h b/session.h new file mode 100644 index 0000000..8787697 --- /dev/null +++ b/session.h @@ -0,0 +1,34 @@ +#ifndef SESSION_H +#define SESSION_H + +#include + +typedef struct Session { + /* Marinetti TCP connection status */ + Word ipid; + Boolean tcpLoggedIn; + + /* ReadTCP status */ + LongWord readCount; + Byte *readPtr; + + /* Marinetti error codes, both the tcperr* value and any tool error */ + Word tcperr; + Word toolerr; + + /* HTTP request to send (if non-NULL, points to malloc'd buffer) */ + char *httpRequest; + /* Pointer to the range part within httpRequest */ + char *httpRequestRange; + + /* IP address and TCP port of host */ + LongWord ipAddr; + Word port; + + /* Domain name of host (p-string; empty string for host specified by IP) */ + char domainName[256]; + /* Time (GetTick) of last DNS lookup */ + LongWord dnsTime; +} Session; + +#endif diff --git a/strncasecmp.c b/strncasecmp.c new file mode 100644 index 0000000..8318ad3 --- /dev/null +++ b/strncasecmp.c @@ -0,0 +1,20 @@ +# ifdef __ORCAC__ +# pragma noroot +# endif + +#include +#include + +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n == 0) + return 0; + + while (n > 1 && *s1 != 0 && tolower(*s1) == tolower(*s2)) { + s1++; + s2++; + n--; + } + + return (int)*s1 - (int)*s2; +} diff --git a/strncasecmp.h b/strncasecmp.h new file mode 100644 index 0000000..ae20a64 --- /dev/null +++ b/strncasecmp.h @@ -0,0 +1,6 @@ +#ifndef STRNCASECMP_H +#define STRNCASECMP_H + +int strncasecmp(const char *s1, const char *s2, size_t n); + +#endif diff --git a/tcpconnection.c b/tcpconnection.c new file mode 100644 index 0000000..5a50362 --- /dev/null +++ b/tcpconnection.c @@ -0,0 +1,65 @@ +#pragma noroot + +#define aspNetworkErr 1 +#define aspNoRespErr 2 + +#include +#include +#include +#include +#include "session.h" +#include "tcpconnection.h" + +/* Make a TCP connection for a session. + * + * On success, returns 0 and sets sess->ipid. + * On failure, returns an error code. + */ +Word StartTCPConnection(Session *sess) { + Word tcperr; + srBuff mySRBuff; + LongWord initialTime; + + if (TCPIPGetConnectStatus() == FALSE) { + TCPIPConnect(NULL); + if (toolerror()) + return aspNetworkErr; + } + + sess->ipid = + TCPIPLogin(userid(), sess->ipAddr, sess->port, 0, 0x40); + if (toolerror()) + return aspNetworkErr; + + tcperr = TCPIPOpenTCP(sess->ipid); + if (toolerror()) { + TCPIPLogout(sess->ipid); + return aspNetworkErr; + } else if (tcperr != tcperrOK) { + TCPIPLogout(sess->ipid); + return aspNoRespErr; + } + + initialTime = GetTick(); + do { + TCPIPPoll(); + TCPIPStatusTCP(sess->ipid, &mySRBuff); + } while (mySRBuff.srState == TCPSSYNSENT && GetTick()-initialTime < 15*60); + if (mySRBuff.srState != TCPSESTABLISHED) { + TCPIPAbortTCP(sess->ipid); + TCPIPLogout(sess->ipid); + return aspNoRespErr; + } + + sess->tcpLoggedIn = TRUE; + return 0; +} + +void EndTCPConnection(Session *sess) { + if (sess->tcpLoggedIn) { + TCPIPPoll(); + TCPIPAbortTCP(sess->ipid); + TCPIPLogout(sess->ipid); + sess->tcpLoggedIn = FALSE; + } +} diff --git a/tcpconnection.h b/tcpconnection.h new file mode 100644 index 0000000..5e6933f --- /dev/null +++ b/tcpconnection.h @@ -0,0 +1,9 @@ +#ifndef TCPCONNECTION_H +#define TCPCONNECTION_H + +#include "session.h" + +Word StartTCPConnection(Session *sess); +void EndTCPConnection(Session *sess); + +#endif