📄 50a731bed5b9001c180780c9bab1766d
字号:
/******************************************************************************
* Copyright ? 2004 Altera Corporation, San Jose, California, USA. *
* All rights reserved. All use of this software and documentation is *
* subject to the License Agreement located at the end of this file below. *
*******************************************************************************
* Author - PRR/JRK *
* *
* File: http.c *
* *
* A rough imlementation of HTTP. This is not intended to be a complete *
* implementation, just enough for a demo simple web server. This example *
* application is more complex than the telnet serer example in that it uses *
* non-blocking IO & multiplexing to allow for multiple simultaneous HTTP *
* sessions. *
* *
* LWIP has two API's, a callback interface and "standard" sockets this *
* example uses the sockets interface. A good introduction to sockets *
* programming is the book Unix Network Programming by Richard Stevens *
* *
* Please refer to file readme.txt for notes on this software example. *
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/fcntl.h>
#include "lwip/netif.h"
#include "lwip/sockets.h"
#include "arch/sys_arch.h"
#include "sys/alt_alarm.h"
#include "alt_types.h"
#include "http.h"
#include "user.h"
// ++ hychu
#if 0
struct __sFILE {
unsigned char *_p; /* current position in (some) buffer */
int _r; /* read space left for getc() */
int _w; /* write space left for putc() */
short _flags; /* flags, below; this FILE is free if 0 */
short _file; /* fileno, if Unix descriptor, else -1 */
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
int _lbfsize; /* 0 or -_bf._size, for inline putc */
/* operations */
_PTR _cookie; /* cookie passed to io functions */
_READ_WRITE_RETURN_TYPE _EXFUN((*_read),(_PTR _cookie, char *_buf, int _n));
_READ_WRITE_RETURN_TYPE _EXFUN((*_write),(_PTR _cookie, const char *_buf, int _n));
_fpos_t _EXFUN((*_seek),(_PTR _cookie, _fpos_t _offset, int _whence));
int _EXFUN((*_close),(_PTR _cookie));
/* separate buffer for long sequences of ungetc() */
struct __sbuf _ub; /* ungetc buffer */
unsigned char *_up; /* saved _p when _p is doing ungetc data */
int _ur; /* saved _r when _r is counting ungetc data */
/* tricks to meet minimum requirements even when malloc() fails */
unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
unsigned char _nbuf[1]; /* guarantee a getc() buffer */
/* separate buffer for fgetline() when line crosses buffer boundary */
struct __sbuf _lb; /* buffer for fgetline() */
/* Unix stdio files get aligned to block boundaries on hyseek() */
int _blksize; /* stat.st_blksize (may be != _bf._size) */
int _offset; /* current lseek offset */
#ifndef __SINGLE_THREAD__
_flock_t _lock; /* for thread-safety locking */
#endif
};
#endif
#define MAX_CONCURRENT_HYPER 64
#define HYPER_FID_START 0x7000
FILE _gFiles[MAX_CONCURRENT_HYPER];
int _ghy_initd = 0;
#define HY_CHK_FP(fp) ((fp) && ((fp)->_file >= HYPER_FID_START))
FILE * hy_allocate_fp(void)
{
int i;
for(i=0;i<MAX_CONCURRENT_HYPER;i++)
{
if(_gFiles[i]._flags != 0) continue;
_gFiles[i]._flags = 0xbeef;
return &_gFiles[i];
} // of for i
return NULL;
}
void hy_release_fp(FILE *fp)
{
fp->_flags = 0;
}
FILE * hyopen(const char * pfname, const char * pmode)
{
// bypass if ordinary file
if(strncmp(pfname+strlen(ALTERA_RO_ZIPFS_NAME), "/file?", 5)) return fopen(pfname, pmode);
// initialization
if(!_ghy_initd)
{
int i;
_ghy_initd = 1;
for(i=0;i<MAX_CONCURRENT_HYPER;i++)
{
_gFiles[i]._file = HYPER_FID_START + i;
_gFiles[i]._flags = 0;
} // of for i
} // of not init'd
FILE * fp;
if(!(fp = hy_allocate_fp())) return NULL;
int flen=0;
char * ptr;
// seek for size
if((ptr=strstr(pfname, "size="))) flen = atoi(ptr+5);
// seek for unit
for(ptr+=5; *ptr ; ptr++)
if(*ptr < '0' || *ptr > '9') break;
switch (*ptr)
{
case 'k': // 1000
flen *= 1000;
break;
case 'K': // 1024
flen *= 1024;
break;
case 'm': // 1,000,000
flen *= 1000000;
break;
case 'M': // 1024*1024
flen *= 1024*1024;
break;
default:
break;
} // of switch
fp->_cookie = flen ? (void*)flen:(void*)(1024*1024);
return fp;
}
int hygetpos(FILE * fp, fpos_t * offset)
{
if(!HY_CHK_FP(fp)) return fgetpos(fp, offset);
*offset = (int)fp->_offset;
return 0;
}
int hyseek(FILE * fp, long offset, int origin)
{
if(!HY_CHK_FP(fp)) return fseek(fp, offset, origin);
switch(origin)
{
case SEEK_SET:
fp->_offset = offset;
break;
case SEEK_CUR: // is it right ?
fp->_offset += offset;
break;
case SEEK_END:
fp->_offset = (int)(fp->_cookie) + offset;
break;
default:
return -1;
} // of switch(origin)
return 0;
}
int hyclose(FILE * fp)
{
if(!HY_CHK_FP(fp)) return fclose(fp);
hy_release_fp(fp);
return 0;
}
int hyread(void * pbuffer, size_t size, size_t count, FILE * fp)
{
if(!HY_CHK_FP(fp)) return fread(pbuffer, size, count, fp);
int total, remains;
remains = (int)(fp->_cookie) - fp->_offset;
total = (remains >= size*count)? size*count:remains;
fp->_offset += total;
return total;
}
// -- hychu
#ifdef DEBUG1
#include alt_debug.h
#else
#define ALT_DEBUG_ASSERT(a)
#endif /* DEBUG */
/*
* TX & RX buffers.
*
* These are declared globally to prevent the MicroC/OS-II thread from
* consuming too much OS-stack space
*/
alt_u8 http_rx_buffer[HTTP_NUM_CONNECTIONS][HTTP_RX_BUF_SIZE];
alt_u8 http_tx_buffer[HTTP_NUM_CONNECTIONS][HTTP_TX_BUF_SIZE];
/*
* This canned HTTP reply will serve as a "404 - Not Found" Web page. HTTP
* headers and HTML embedded into the single string.
*/
static const alt_8 canned_http_response[] = {"\
HTTP/1.0 404 Not Found\r\n\
Content-Type: text/html\r\n\
Content-Length: 272\r\n\r\n\
<HTML><HEAD><TITLE>Nios II Web Server Demonstration</TITLE></HEAD>\
<title>LWIP on Nios II</title><BODY><h1>HTTP Error 404</h1>\
<center><h2>Nios II Web Server Demonstration</h2>\
Can't find the requested file file. \
Have you programmed the flash filing system into flash?</html>\
"};
// hychu
static const alt_8 hello_http_response[] = {"\
HTTP/1.0 200\r\n\
Content-Type: text/html\r\n\
Content-Length: 203\r\n\r\n\
<HTML><HEAD><TITLE>Nios II Web Server Demonstration</TITLE></HEAD>\
<title>LWIP on Nios II</title>\
<BODY>\
<br><br>\
<center>\
<h1>Nios II Web Server Demonstration</h1><br>\
<h2>Hello World</h2><br>\
</center>\
</html>\
"};
/*
* Mapping between pages to post to and functions to call: This allows us to
* have the HTTP server respond to a POST requset saying "print" by calling
* a "print" routine (below).
*/
typedef struct funcs
{
alt_u8* name;
void (*func)();
}post_funcs;
/*
* print()
*
* This routine is called to demonstrate doing something server-side when an
* HTTP "POST" command is received.
*/
void print()
{
printf("HTTP POST received.\n");
}
/*
* The mapping (using our struct defined above) between HTTP POST commands
* that we will service and the subroutine called to service that POST
* command.
*/
post_funcs mapping =
{
"/PRINT",
print
};
/*
* http_reset_connection()
*
* This routine will clear our HTTP connection structure & prepare it to handle
* a new HTTP connection.
*/
void http_reset_connection(http_conn* conn, int http_instance)
{
memset(conn, 0, sizeof(http_conn));
conn->fd = -1;
conn->state = READY;
conn->keep_alive_count = HTTP_KEEP_ALIVE_COUNT;
conn->rx_buffer = (alt_u8 *) &http_rx_buffer[http_instance][0];
conn->tx_buffer = (alt_u8 *) &http_tx_buffer[http_instance][0];
conn->rx_wr_pos = (alt_u8 *) &http_rx_buffer[http_instance][0];
conn->rx_rd_pos = (alt_u8 *) &http_rx_buffer[http_instance][0];
}
/*
* http_manage_connection()
*
* This routine performs house-keeping duties for a specific HTTP connection
* structure. It is called from various points in the HTTP server code to
* ensure that connections are reset properly on error, completion, and
* to ensure that "zombie" connections are dealt with.
*/
void http_manage_connection(http_conn* conn, int http_instance)
{
alt_u32 current_time = 0;
/*
* Keep track of whether an open connection has timed out. This will be
* determined by comparing the current time with that of the most recent
* activity.
*/
if(conn->state == READY || conn->state == PROCESS || conn->state == DATA)
{
current_time = alt_nticks();
if( (current_time - conn->activity_time) >= HTTP_KEEP_ALIVE_TIME )
{
conn->state = RESET;
}
}
/*
* The reply has been sent. Is is time to drop this connection, or
* should we persist? We'll keep track of these here and mark our
* state machine as ready for additional connections... or not.
* - Only send so many files per connection.
* - Stop when we reach a timeout.
* - If someone (like the client) asked to close the connection, do so.
*/
if(conn->state == COMPLETE)
{
if(conn->file_handle != NULL)
{
hyclose(conn->file_handle);
}
conn->keep_alive_count--;
conn->data_sent = 0;
if(conn->keep_alive_count == 0)
{
conn->close = 1;
}
conn->state = conn->close ? CLOSE : READY;
}
/*
* Some error occured. http_reset_connection() will take care of most
* things, but the RX buffer still needs to be cleared, and any open
* files need to be closed. We do this in a separate state to maintain
* efficiency between successive (error-free) connections.
*/
if(conn->state == RESET)
{
if(conn->file_handle != NULL)
{
hyclose(conn->file_handle);
}
memset(conn->rx_buffer, 0, HTTP_RX_BUF_SIZE);
conn->state = CLOSE;
}
/* Close the TCP connection */
if(conn->state == CLOSE)
{
close(conn->fd);
http_reset_connection(conn, http_instance);
}
}
/*
* http_handle_accept()
*
* A listening socket has detected someone trying to connect to us. If we have
* any open connection slots we will accept the connection (this creates a
* new socket for the data transfer), but if all available connections are in
* use we'll ignore the client's incoming connection request.
*/
int http_handle_accept(int listen_socket, http_conn* conn)
{
int ret_code = 0, i, socket, len;
struct sockaddr_in rem;
len = sizeof(rem);
/*
* Loop through available connection slots to determine the first available
* connection.
*/
for(i=0; i<HTTP_NUM_CONNECTIONS; i++)
{
if((conn+i)->fd == -1)
{
break;
}
}
/*
* There are no more connection slots available. Ignore the connection
* request for now.
*/
if(i == HTTP_NUM_CONNECTIONS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -