123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- // Webserver
- // uses multiple sockets, except for socket 7 which is reserved by netHID
- #define word char
- #include "lib/math.c"
- #include "lib/stdlib.c"
- #include "lib/sys.c"
- #include "lib/fs.c"
- #include "lib/wiz5500.c"
- #define TMPMEM_LOCATION 0x440000
- #define FILE_BUFFER_LOCATION 0x430000
- #define FILE_BUFFER_SIZE 8192 // buffer size for reading files from USB storage
- char* fileBuffer = (char *) FILE_BUFFER_LOCATION; //fileBuffer[FILE_BUFFER_SIZE];
- char WIZrbuf[WIZNET_MAX_RBUF];
- //-------------------
- //LIST DIR CUSTOM FUNCTIONS
- //-------------------
- // Parses and writes name.extension and filesize on one line
- void wiz_parseFATdata(word datalen, char* fatBuffer, char* b, word* bufLen)
- {
- if (datalen != 32)
- {
- BDOS_PrintConsole("Unexpected FAT table length\n");
- return;
- }
- // start HTML link tag
- word catLen = strcpy(b + *bufLen, "<tr><td style=\"padding:0 15px 0 15px;\"><a href=\"");
- (*bufLen) += catLen;
- // parse filename
- word printLen = FS_parseFATstring(fatBuffer, 8, b, bufLen);
- // add '.' and parse extension
- if (fatBuffer[8] != ' ' || fatBuffer[9] != ' ' || fatBuffer[10] != ' ')
- {
- b[*bufLen] = '.';
- (*bufLen)++;
- printLen += FS_parseFATstring(fatBuffer+8, 3, b, bufLen) + 1;
- }
- // filesize
- word fileSize = 0;
- fileSize += fatBuffer[28];
- fileSize += (fatBuffer[29] << 8);
- fileSize += (fatBuffer[30] << 16);
- fileSize += (fatBuffer[31] << 24);
- // add slash if folder (filesize 0)
- if (fileSize == 0)
- {
- catLen = strcpy(b + *bufLen, "/");
- (*bufLen) += catLen;
- }
- // end the starting HTML link tag
- catLen = strcpy(b + *bufLen, "\">");
- (*bufLen) += catLen;
- // do again for the link text
- // parse filename
- printLen = FS_parseFATstring(fatBuffer, 8, b, bufLen);
- // add '.' and parse extension
- if (fatBuffer[8] != ' ' || fatBuffer[9] != ' ' || fatBuffer[10] != ' ')
- {
- b[*bufLen] = '.';
- (*bufLen)++;
- printLen += FS_parseFATstring(fatBuffer+8, 3, b, bufLen) + 1;
- }
- // add slash if folder (filesize 0)
- if (fileSize == 0)
- {
- catLen = strcpy(b + *bufLen, "/");
- (*bufLen) += catLen;
- }
- // end hyperlink
- catLen = strcpy(b + *bufLen, "</a></td><td style=\"padding:0 15px 0 15px;\">");
- (*bufLen) += catLen;
-
- // filesize to integer string
- char buffer[10];
- itoa(fileSize, &buffer[0]);
- // write to buffer
- word i = 0;
- while (buffer[i] != 0)
- {
- b[*bufLen] = buffer[i];
- (*bufLen)++;
- i++;
- }
- catLen = strcpy(b + *bufLen, "</td></tr>\n");
- (*bufLen) += catLen;
- }
- // Reads FAT data for single entry
- // FAT data is parsed by FS_parseFatData()
- void wiz_readFATdata(char* b, word* bufLen)
- {
- FS_spiBeginTransfer();
- FS_spiTransfer(FS_CMD_RD_USB_DATA0);
- word datalen = FS_spiTransfer(0x0);
- char fatbuf[32];
- word i;
- for (i = 0; i < datalen; i++)
- {
- fatbuf[i] = FS_spiTransfer(0x00);
- }
- wiz_parseFATdata(datalen, fatbuf, b, bufLen);
- FS_spiEndTransfer();
- }
- // Lists directory of full path f
- // f needs to start with / and not end with /
- // Returns ANSW_USB_INT_SUCCESS if successful
- // Writes parsed result to address b
- // Result is terminated with a \0
- word wiz_listDir(char* f, char* b)
- {
- word bufLen = 0;
- word* pBuflen = &bufLen;
- word retval = FS_sendFullPath(f);
- // Return on failure
- if (retval != FS_ANSW_USB_INT_SUCCESS)
- return retval;
- retval = FS_open();
- // Return on failure
- if (retval != FS_ANSW_USB_INT_SUCCESS && retval != FS_ANSW_ERR_OPEN_DIR)
- return retval;
- FS_sendSinglePath("*");
- retval = FS_open();
- // Return on failure
- if (retval != FS_ANSW_USB_INT_DISK_READ)
- return retval;
- // Init length of output buffer
- *pBuflen = 0;
- while (retval == FS_ANSW_USB_INT_DISK_READ)
- {
- wiz_readFATdata(b, pBuflen);
- FS_spiBeginTransfer();
- FS_spiTransfer(FS_CMD_FILE_ENUM_GO);
- FS_spiEndTransfer();
- retval = FS_WaitGetStatus();
- }
- // Terminate buffer
- b[*pBuflen] = 0;
- (*pBuflen)++;
- return FS_ANSW_USB_INT_SUCCESS;
- }
- word PercentageDone(word remaining, word full)
- {
- word x = remaining * 100;
- return 100 - MATH_divU(x, full);
- }
- //-------------------
- //W5500 CONNECTION HANDLING FUNCTIONS
- //-------------------
- // Writes response from (successfully) opened USB file
- word wizWriteResponseFromUSB(word s, word fileSize)
- {
- // file size is already checked on being > 0
- if (FS_setCursor(0) != FS_ANSW_USB_INT_SUCCESS)
- BDOS_PrintConsole("cursor error\n");
- word bytesSent = 0;
- char buffer[10];
- char dbuf[10]; // percentage done for progress indication
- dbuf[0] = 0; // terminate
- // loop until all bytes are sent
- while (bytesSent != fileSize)
- {
- word partToSend = fileSize - bytesSent;
- // send in parts of FILE_BUFFER_SIZE
- if (partToSend > FILE_BUFFER_SIZE)
- partToSend = FILE_BUFFER_SIZE;
- // read from usb to buffer
- if (FS_readFile(fileBuffer, partToSend, 0) != FS_ANSW_USB_INT_SUCCESS)
- BDOS_PrintConsole("read error\n");
- if (!wizWriteDataFromMemory(s, fileBuffer, partToSend))
- {
- //uprintln("wizTranser error");
- return 0;
- }
- // Update the amount of bytes sent
- bytesSent += partToSend;
- //BDOS_PrintConsole(".");
- // indicate progress
- // remove previous percentage
- word i = strlen(dbuf);
- while (i > 0)
- {
- BDOS_PrintcConsole(0x8); // backspace
- i--;
- }
- if (strlen(dbuf) != 0)
- {
- BDOS_PrintcConsole(0x8); // backspace
- }
- itoa(PercentageDone(fileSize - bytesSent, fileSize), dbuf);
- BDOS_PrintConsole(dbuf);
- BDOS_PrintcConsole('%');
- }
- // remove previous percentage
- word i = strlen(dbuf);
- while (i > 0)
- {
- BDOS_PrintcConsole(0x8); // backspace
- i--;
- }
- if (strlen(dbuf) != 0)
- {
- BDOS_PrintcConsole(0x8); // backspace
- }
- FS_close();
- return 1;
- }
- void wizSend404Response(word s)
- {
- char* retTxt = "<!DOCTYPE html><html><head><title>ERROR404</title></head><body>ERROR 404: This is not the page you are looking for</body></html>";
- wizWriteDataFromMemory(s, retTxt, strlen(retTxt));
- }
- // Gets requested file path from request header
- // Returns size of requested path (should be 1 or higher because '/')
- // Fills pbuf with path
- // Assumes a request header of appropiate size
- word wizGetFilePath(char* rbuf, char* pbuf)
- {
- word foundPath = 0;
- word foundSpace = 0;
- word cursor = 0;
- word pathIndex = 0;
- while (foundPath == 0)
- {
- // until we found the first space after GET (or POST)
- if (foundSpace == 0 && rbuf[cursor] == 32)
- {
- foundSpace = 1;
- }
- else
- {
- if (foundSpace == 1)
- {
- // until we found the second space (after the file path)
- if (rbuf[cursor] == 32)
- {
- // exit the loop, we are done
- foundPath = 1;
- }
- else
- {
- // copy the character
- pbuf[pathIndex] = rbuf[cursor];
- //uprintc(rbuf[cursor]);
- pathIndex++;
- }
- }
- }
- // go to next character
- cursor++;
- }
- pbuf[pathIndex] = 0; // terminate string
- // return the path length
- return (pathIndex + 1);
- }
- void wizDirectoryListing(word s, char* path)
- {
- // write start of html page
- wizWriteDataFromMemory(s, "<!DOCTYPE html><html><body><h2>", 31);
- word pathLen = 0;
- while (path[pathLen] != 0)
- pathLen++;
- wizWriteDataFromMemory(s, path, pathLen-1);
- wizWriteDataFromMemory(s, "</h2><table><tr><th>Name</th><th>Size</th></tr>", 47);
- char *b = (char *) TMPMEM_LOCATION;
- if (wiz_listDir(path, b) == FS_ANSW_USB_INT_SUCCESS)
- {
- word listSize = 0;
- while (b[listSize] != 0)
- listSize++;
- if (listSize == 0)
- listSize = 1;
- wizWriteDataFromMemory(s, b, listSize-1);
- }
- // write end of html page
- wizWriteDataFromMemory(s, "</table></body></html>", 22);
- }
- void wizServeFile(word s, char* path)
- {
- BDOS_PrintConsole(path);
- BDOS_PrintConsole(": ");
- // Redirect "/" to "/INDEX.HTM"
- if (path[0] == 47 && path[1] == 0)
- {
- // send an actual redirect to the browser
- char* response = "HTTP/1.1 301 Moved Permanently\nLocation: /INDEX.HTM\n";
- BDOS_PrintConsole("Redirect to /INDEX.HTM\n");
- wizWriteDataFromMemory(s, response, strlen(response));
- // Disconnect after sending the redirect
- wizCmd(s, WIZNET_CR_DISCON);
- return;
- }
- word error = 0;
- word listDir = 0;
- if (FS_sendFullPath(&path[0]) != FS_ANSW_USB_INT_SUCCESS) // automatically upercases the path
- error = 404;
- if (!error)
- {
- word openStatus = FS_open();
- if (openStatus == FS_ANSW_ERR_OPEN_DIR)
- listDir = 1;
- else if (openStatus != FS_ANSW_USB_INT_SUCCESS)
- error = 404;
- }
- word fileSize = 0;
- if (!error && !listDir)
- fileSize = FS_getFileSize();
- if (!error && !listDir)
- {
- if (fileSize == 0)
- error = 404; // handle empty files as if they do not exist
- }
- // send error response on error
- if (error)
- {
- BDOS_PrintConsole("404 ");
- // currently puts all errors under 404
- // write header
- char* header = "HTTP/1.1 404 Not Found\nServer: FPGC/1.0\nContent-Type: text/html\n\n";
- wizWriteDataFromMemory(s, header, strlen(header));
- FS_sendFullPath("/404.HTM");
- if (FS_open() != FS_ANSW_USB_INT_SUCCESS)
- {
- // if the custom 404 does not exist, return own error code
- BDOS_PrintConsole("no 404.HTM\n");
- wizSend404Response(s);
- }
- else
- {
- // send custom 404
- fileSize = FS_getFileSize();
- // write the response from USB
- BDOS_PrintConsole("/404.HTM ");
- wizWriteResponseFromUSB(s, fileSize);
- BDOS_PrintConsole("Done\n");
- }
- }
- else
- {
- if (listDir)
- {
- // check if last character is a /
- // if not, redirect to the path with / after it
- word i = 0;
- while (path[i] != 0)
- i++;
- if (path[i-1] != '/')
- {
- //BDOS_PrintConsole(path);
- //BDOS_PrintConsole("\n");
- path[i] = '/';
- path[i+1] = 0;
- char* response = "HTTP/1.1 301 Moved Permanently\nLocation: ";
- BDOS_PrintConsole("Redirect to ");
- BDOS_PrintConsole(path);
- BDOS_PrintConsole("\n");
- wizWriteDataFromMemory(s, response, strlen(response));
- wizWriteDataFromMemory(s, path, i+1);
- wizWriteDataFromMemory(s, "\n", 1);
- }
- else
- {
- BDOS_PrintConsole("200 ");
- // write header
- // currently omitting content type
- char* header = "HTTP/1.1 200 OK\nServer: FPGC/1.0\n\n";
- wizWriteDataFromMemory(s, header, strlen(header));
- wizDirectoryListing(s, path);
- BDOS_PrintConsole("Done\n");
- }
- }
- else
- {
- if (fileSize + 1 != 0) // really make sure no directory is being read
- {
- BDOS_PrintConsole("200 ");
- // write header
- // currently omitting content type
- // includes content length so the client knows how large a download is
- char header[128];
- header[0] = 0;
- strcat(header, "HTTP/1.1 200 OK\nServer: FPGC/1.0\nContent-Length: ");
- char fileSizeStr[24];
- itoa(fileSize, fileSizeStr);
- strcat(header, fileSizeStr);
- strcat(header, "\n\n");
- wizWriteDataFromMemory(s, header, strlen(header));
- // write the response from USB
- wizWriteResponseFromUSB(s, fileSize);
- BDOS_PrintConsole("Done\n");
- }
-
- }
- }
- // Disconnect after sending a response
- wizCmd(s, WIZNET_CR_DISCON);
- }
- // Handle session for socket s
- void wizHandleSession(word s)
- {
- // Size of received data
- word rsize;
- rsize = wizGetSockReg16(s, WIZNET_SnRX_RSR);
- if (rsize == 0)
- {
- wizCmd(s, WIZNET_CR_DISCON);
- return;
- }
- char* rbuf = WIZrbuf;
- wizReadRecvData(s, rbuf, rsize);
- // read rbuf for requested page
- // parse from {GET /INFO.HTM HTTP/1.1}
- char pbuf[128]; // buffer for path name
- word pbufSize = wizGetFilePath(&rbuf[1], pbuf);
- wizServeFile(s, pbuf);
- // Free received data when not read
- // Not used, since we currently read the request
- //wizFlush(s, rsize);
- }
- int main()
- {
- BDOS_PrintConsole("Starting Web Server\n");
- // Assumes that the USB drive is already properly initialized by BDOS
- word ip_addr[4] = {192, 168, 0, 213};
- word gateway_addr[4] = {192, 168, 0, 1};
- word mac_addr[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x24, 0x64};
- word sub_mask[4] = {255, 255, 255, 0};
- wiz_Init(ip_addr, gateway_addr, mac_addr, sub_mask);
- // Open all sockets in TCP Server mode at port 80
- wizInitSocketTCP(0, 80);
- wizInitSocketTCP(1, 80);
- wizInitSocketTCP(2, 80);
- wizInitSocketTCP(3, 80);
- wizInitSocketTCP(4, 80);
- wizInitSocketTCP(5, 80);
- wizInitSocketTCP(6, 80);
- // Socket s status
- word sxStatus;
- while(1)
- {
- if (HID_FifoAvailable())
- {
- HID_FifoRead(); // remove it from the buffer
- return 'q';
- }
- // handle all sockets (socket 7 is reserved by netHID)
- word s;
- for (s = 0; s < 7; s++)
- {
- // Get status for socket s
- sxStatus = wizGetSockReg8(s, WIZNET_SnSR);
- if (sxStatus == WIZNET_SOCK_CLOSED)
- {
- // Open the socket when closed
- // Set socket s in TCP Server mode at port 80
- wizInitSocketTCP(s, 80);
- }
- else if (sxStatus == WIZNET_SOCK_ESTABLISHED)
- {
- // Handle session when a connection is established
- // Also reinitialize socket
- wizHandleSession(s);
- // Set socket s in TCP Server mode at port 80
- wizInitSocketTCP(s, 80);
- }
- else if (sxStatus == WIZNET_SOCK_LISTEN || sxStatus == WIZNET_SOCK_SYNSENT || sxStatus == WIZNET_SOCK_SYNRECV)
- {
- // Do nothing in these cases
- }
- else
- {
- // In other cases, reset the socket
- // Set socket s in TCP Server mode at port 80
- wizInitSocketTCP(s, 80);
- }
- }
- // Delay a few milliseconds
- // Should (could) eventually be replaced by an interrupt checker
- delay(10);
- }
- return 'q';
- }
- void interrupt()
- {
- // Handle all interrupts
- word i = getIntID();
- switch(i)
- {
- case INTID_TIMER1:
- timer1Value = 1; // Notify ending of timer1
- break;
- }
- }
|