From ef272cb9987741fd3f81fa232e7ba99fb7a6aa81 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 29 Jul 2018 23:40:03 -0500 Subject: [PATCH] Initial code implementing some of the core functionality for reading blocks over HTTP. --- hostname.c | 27 ++++++++++++++ hostname.h | 9 +++++ http.c | 53 +++++++++++++++++++++++++++ http.h | 10 ++++++ main.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ readtcp.c | 38 ++++++++++++++++++++ readtcp.h | 15 ++++++++ session.h | 34 ++++++++++++++++++ strncasecmp.c | 20 +++++++++++ strncasecmp.h | 6 ++++ tcpconnection.c | 65 +++++++++++++++++++++++++++++++++ tcpconnection.h | 9 +++++ 12 files changed, 382 insertions(+) create mode 100644 hostname.c create mode 100644 hostname.h create mode 100644 http.c create mode 100644 http.h create mode 100644 main.c create mode 100644 readtcp.c create mode 100644 readtcp.h create mode 100644 session.h create mode 100644 strncasecmp.c create mode 100644 strncasecmp.h create mode 100644 tcpconnection.c create mode 100644 tcpconnection.h 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