6 /* The block size is currently chosen to be 512 bytes. This means, we can
7 allocate the receive buffer on the stack, but it results in a noticeable
9 This is what needs to be done in order to increase the block size:
10 - size negotiation needs to be implemented in TCP
11 - the buffer needs to be allocated on the heap
12 - path MTU discovery needs to be implemented
14 #define BLOCKSIZE TFTP_DEFAULTSIZE_PACKET
16 /**************************************************************************
17 SEND_TCP_CALLBACK - Send data using TCP
18 **************************************************************************/
19 struct send_recv_state {
20 struct buffer *recv_buffer;
25 enum { RESULT_CODE, HEADER, DATA, ERROR, MOVED } recv_state;
30 static int send_tcp_request(int length, void *buffer, void *ptr) {
31 struct send_recv_state *state = (struct send_recv_state *)ptr;
33 if (length > state->send_length - state->bytes_sent)
34 length = state->send_length - state->bytes_sent;
35 memcpy(buffer, state->send_buffer + state->bytes_sent, length);
36 state->bytes_sent += length;
40 /**************************************************************************
41 RECV_TCP_CALLBACK - Receive data using TCP
42 **************************************************************************/
43 static int recv_tcp_request(int length, const void *buffer, void *ptr) {
44 struct send_recv_state *state = (struct send_recv_state *)ptr;
46 /* Assume that the lines in an HTTP header do not straddle a packet */
47 /* boundary. This is probably a reasonable assumption */
48 if (state->recv_state == RESULT_CODE) {
50 /* Find HTTP result code */
51 if (*(const char *)buffer == ' ') {
52 const char *ptr = ((const char *)buffer) + 1;
53 int rc = strtoul(ptr, &ptr, 10);
54 if (ptr >= (const char *)buffer + length) {
55 state->recv_state = ERROR;
56 DBG ( "HTTP got bad result code\n" );
60 state->recv_state = HEADER;
61 DBG ( "HTTP got result code %d\n", rc );
64 ++(const char *)buffer;
67 state->recv_state = ERROR;
68 DBG ( "HTTP got no result code\n" );
71 if (state->recv_state == HEADER) {
72 header: while (length > 0) {
73 /* Check for HTTP redirect */
74 if (state->rc >= 300 && state->rc < 400 &&
75 !memcmp(buffer, "Location: ", 10)) {
78 state->url = p = ( char * ) buffer + 10;
83 state->recv_state = MOVED;
84 DBG ( "HTTP got redirect to %s\n",
88 /* Find beginning of line */
91 if (*((const char *)buffer)++ == '\n')
94 /* Check for end of header */
95 if (length >= 2 && !memcmp(buffer, "\r\n", 2)) {
96 state->recv_state = DATA;
103 if (state->recv_state == DATA) {
104 DBG2 ( "HTTP received %d bytes\n", length );
105 if ( ! fill_buffer ( state->recv_buffer, buffer,
106 state->bytes_received, length ) )
108 state->bytes_received += length;
113 /**************************************************************************
114 HTTP_GET - Get data using HTTP
115 **************************************************************************/
116 static int http ( char *url, struct sockaddr_in *server __unused,
117 char *file __unused, struct buffer *buffer ) {
118 struct protocol *proto;
119 struct sockaddr_in http_server = *server;
121 static const char GET[] = "GET /%s HTTP/1.0\r\n\r\n";
122 struct send_recv_state state;
127 state.recv_buffer = buffer;
129 length = strlen ( filename ) + strlen ( GET );
131 char send_buf[length];
133 sprintf ( send_buf, GET, filename );
134 state.send_buffer = send_buf;
135 state.send_length = strlen ( send_buf );
136 state.bytes_sent = 0;
138 state.bytes_received = 0;
139 state.recv_state = RESULT_CODE;
141 tcp_transaction ( server->sin_addr.s_addr,
142 server->sin_port, &state,
143 send_tcp_request, recv_tcp_request );
146 if ( state.recv_state == MOVED ) {
147 if ( ! parse_url ( state.url, &proto,
148 &http_server, &filename ) ) {
149 printf ( "Invalid redirect URL %s\n",
159 if ( state.rc != 200 ) {
160 printf ( "Failed to download %s (rc = %d)\n",
161 state.url, state.rc );
168 static struct protocol http_protocol __protocol = {