// result code is unused now. always 200 OK void http_reply(int code, char *data) // rewrite with tcp_ref() 16.12.2014 { unsigned pkt = tcp_create_packet(http.tcp_session); if(pkt != 0xFF) { unsigned dlen = strlen(data); if(dlen > 1024) dlen = 1024; char *p = tcp_ref(pkt, 0); char *s = p; p += sprintf(p, "HTTP/1.1 200 Ok\r\n" "Connection: Close\r\n" "Cache-Control: no-store, no-cache, must-revalidate\r\n" "Expires: Fri, 13 Oct 2000 00:00:00 GMT\r\n" ); if(req_origin[0] != 0) p += sprintf(p, "Access-Control-Allow-Origin: %s\r\n" "Access-Control-Allow-Credentials: true\r\n", req_origin ); p += sprintf(p, "Content-Type: %s\r\n" "Content-Length: %u\r\n" "\r\n", http.page->mime, dlen ); memcpy(p, data, dlen); p += dlen; tcp_send_packet(http.tcp_session, pkt, (unsigned)(p - s)); } tcp_close_session(http.tcp_session); http.state = HTTP_COMPLETE; }
void http_exec(void) { switch(http.state) { case HTTP_SEND_HEADERS: http_start_get(); break; case HTTP_SEND_PAGE: http_get_pumping(0xff); break; case HTTP_COMPLETE: if(TCP_CONN_IS_CLOSED(http.tcp_session)) http.state = HTTP_IDLE; break; } // sse keep alive if(sys_clock_100ms > sse_ping_timer && http_can_send_sse()) { unsigned pkt = tcp_create_packet_sized(sse_sock, 256); if(pkt != 0xff) { unsigned len = sprintf( (char*)tcp_ref(pkt, 0), "event: sse_ping\n""data: -\n\n" ); tcp_send_packet(sse_sock, pkt, len); sse_ping_timer = sys_clock_100ms + 90; // 9s } } }
void http_responce_options(void) // 16.12.2014 { http.state = HTTP_SEND_HEADERS; unsigned pkt = tcp_create_packet(http.tcp_session); if(pkt == 0xff) return; char buf[512]; char *p = buf; p += sprintf(p, "HTTP/1.1 200 Ok\r\n" "Access-Control-Allow-Origin: %s\r\n" "Access-Control-Allow-Credentials: true\r\n" "Access-Control-Allow-Methods: OPTIONS, %s\r\n" "Content-Type: %s\r\n" "Content-Length: 0\r\n" "\r\n", req_origin, (http.page->flags & HTML_FLG_POST) ? "POST" : "GET", http.page->mime ); tcp_tx_body_pointer = 0; tcp_put_tx_body(pkt, (void*)buf, p - buf); tcp_send_packet(http.tcp_session, pkt, tcp_tx_body_pointer); tcp_close_session(http.tcp_session); http.state = HTTP_COMPLETE; }
static void send_redirect(char *location, unsigned location_len) { if(location_len > 1024) return; // 16.12.2014 moved unsigned pkt = tcp_create_packet(http.tcp_session); if(pkt == 0xFF) return; tcp_tx_body_pointer = 0; tcp_put_tx_body(pkt, (unsigned char*)location, location_len); tcp_send_packet(http.tcp_session, pkt, location_len); tcp_close_session(http.tcp_session); http.state = HTTP_COMPLETE; }
void http_get_pumping(unsigned pkt) { struct page_s *page = http.page; if(tcp_socket[http.tcp_session].out_in_flight >= 2) return; // 17.05.2011 if(tcp_socket[http.tcp_session].tcp_state != TCP_ESTABLISHED) return; // 9.05.2013 if(pkt == 0xFF) { pkt = tcp_create_packet(http.tcp_session); tcp_tx_body_pointer=0; } if(pkt == 0xFF) return; if(http.page->flags & HTML_FLG_CGI) // call service (procedural data generation) { http.more_data = ((unsigned(*)(unsigned,unsigned))(http.page->addr))(pkt, http.more_data); if(http.state == HTTP_IDLE) return; // emergency cancel possibility } else // send generic http page { #if defined( HTML_RES_IS_IN_CPU_FLASH ) unsigned len = http.page->size - http.sent; // unsigned available = (1536 - 128) - tcp_tx_body_pointer; unsigned available = (1100 - 14 - 20 - 24) - tcp_tx_body_pointer; // MTU 1100 // 28.07.2014 if(len > available) len = available; tcp_put_tx_body(pkt, (unsigned char*)page->addr + http.sent, len); http.sent += len; http.more_data = http.sent < page->size; #elif defined( HTML_RES_IS_IN_EEPROM ) # error "Data in ext. flash is unsupported in this version of http2.c!" #else # error "Define HTML_RES_IS_IN_xxxxx macro in http2_def.h!" #endif } tcp_send_packet(http.tcp_session, pkt, tcp_tx_body_pointer); if(http.more_data == 0) { // push data, close tcp connection tcp_close_session(http.tcp_session); http.state = HTTP_COMPLETE; } }
void http_responce_err(int code) { char buf[256]; char *s = buf; switch(code) { case 404: s += sprintf(s,"HTTP/1.1 404 Not Found\r\n"); break; case 401: s += sprintf(s, "HTTP/1.1 401 Unauthorized\r\n" "WWW-Authenticate: Basic realm=\"%s\"\r\n", device_name); if(req_origin[0] != 0) { s += sprintf(s, "Access-Control-Allow-Origin: %s\r\n" "Access-Control-Allow-Credentials: true\r\n", req_origin); } break; default: // incl. 500 s += sprintf(s, "HTTP/1.1 500 Internal Server Error\r\n" ); break; } s += sprintf(s, "\r\n"); unsigned pkt = tcp_create_packet(http.tcp_session); if(pkt == 0xFF) return; unsigned len = (unsigned)(s - buf); tcp_tx_body_pointer = 0; tcp_put_tx_body(pkt, (unsigned char*)buf, len); tcp_send_packet(http.tcp_session, pkt, len); tcp_close_session(http.tcp_session); http.state = HTTP_COMPLETE; }
//***************************************************************************************** // // Function : client_process // Description : send temparature to web server, this option is disabled by default. // YOU MUST install webserver and server script before enable this option, // I recommented Apache webserver and PHP script. // More detail about Apache and PHP installation please visit http://www.avrportal.com/ // //***************************************************************************************** void client_process ( void ) { WORD dlength; // you can change rx,tx buffer size in includes.h BYTE rxtx_buffer[MAX_RXTX_BUFFER]; // wait for send temparature flag is set, this flag set by time_base function (menu.c) if ( flag1.bits.send_temp == 0 ) return; // AVR busy now and wait untill transfer data to web browser completed. if ( flag1.bits.syn_is_received ) return; // AVR sent temparature to web server but not found web server on port 80 //if ( flag1.bits.not_found_server ) // return; // send SYN to initial connection if ( flag1.bits.syn_is_sent == 0 ) { // start arp // server ip was not found on network if ( arp_who_is ( rxtx_buffer, (BYTE*)&server_mac, (BYTE*)&server_ip ) == 0 ) { flag1.bits.send_temp = 0; return; } // send SYN packet to initial connection tcp_send_packet ( rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_SYN_V, // flag 1, // (bool)maximum segment size 1, // (bool)clear sequence ack number 0, // 0=use old seq, seqack : 1=new seq,seqack no data : new seq,seqack with data 0, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address flag1.bits.syn_is_sent = 1; } // get new packet dlength = enc28j60_packet_receive( (BYTE*)&rxtx_buffer, MAX_RXTX_BUFFER ); // no new packet incoming if ( dlength == 0 ) { // timeout occured, when SYN has been sent but no response from web server // reset send_temp and syn_is_sent flags if ( flag1.bits.send_temp_timeout ) { flag1.bits.send_temp_timeout = 0; flag1.bits.send_temp = 0; flag1.bits.syn_is_sent = 0; } return; } // check ip packet send to avr or not? // accept ip packet only if ( ip_packet_is_ip ( (BYTE*)&rxtx_buffer ) == 0 ) { return; } // check SYNACK flag, after AVR send SYN server response by send SYNACK to AVR if ( rxtx_buffer [ TCP_FLAGS_P ] == ( TCP_FLAG_SYN_V | TCP_FLAG_ACK_V ) ) { // send ACK to answer SYNACK tcp_send_packet ( (BYTE*)&rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_ACK_V, // flag 0, // (bool)maximum segment size 0, // (bool)clear sequence ack number 1, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data 0, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address // setup http request to server dlength = http_put_request( (BYTE*)&rxtx_buffer ); // send http request packet // send packet with PSHACK tcp_send_packet ( (BYTE*)&rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_ACK_V | TCP_FLAG_PSH_V, // flag 0, // (bool)maximum segment size 0, // (bool)clear sequence ack number 0, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data dlength, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address return; } // after AVR send http request to server, server response by send data with PSHACK to AVR // AVR answer by send ACK and FINACK to server if ( rxtx_buffer [ TCP_FLAGS_P ] == (TCP_FLAG_ACK_V|TCP_FLAG_PSH_V) ) { dlength = tcp_get_dlength( (BYTE*)&rxtx_buffer ); // send ACK to answer PSHACK from server tcp_send_packet ( (BYTE*)&rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_ACK_V, // flag 0, // (bool)maximum segment size 0, // (bool)clear sequence ack number dlength, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data 0, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address // send finack to disconnect from web server tcp_send_packet ( (BYTE*)&rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_FIN_V|TCP_FLAG_ACK_V, // flag 0, // (bool)maximum segment size 0, // (bool)clear sequence ack number 0, // (bool)calculate new seq and seqack number 0, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address return; //menu_flag.bits.send_temp = 0; //send_syn = 0; } // answer FINACK from web server by send ACK to web server if ( rxtx_buffer [ TCP_FLAGS_P ] == (TCP_FLAG_FIN_V|TCP_FLAG_ACK_V) ) { // send ACK with seqack = 1 tcp_send_packet ( (BYTE*)&rxtx_buffer, (WORD_BYTES){80}, // destination port (WORD_BYTES){1200}, // source port TCP_FLAG_ACK_V, // flag 0, // (bool)maximum segment size 0, // (bool)clear sequence ack number 1, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data 0, // tcp data length (BYTE*)&server_mac, // server mac address (BYTE*)&server_ip ); // server ip address // temparature has been sent // and wait for next schedule to send temparature flag1.bits.send_temp = 0; flag1.bits.syn_is_sent = 0; } }
void http_start_get(void) { http.state = HTTP_SEND_HEADERS; unsigned pkt = tcp_create_packet(http.tcp_session); if(pkt == 0xff) return; tcp_tx_body_pointer=0; ADD_HTTP_STRING(pkt, "HTTP/1.1 200 Ok\r\n" "Connection: Close\r\n"); if(http.page->flags & HTML_FLG_NOCACHE) { ADD_HTTP_STRING(pkt, "Cache-Control: no-store, no-cache, must-revalidate\r\n" "Expires: Fri, 28 Apr 2000 00:00:00 GMT\r\n"); } else { ADD_HTTP_STRING(pkt, "Cache-Control: max-age=10000, private\r\n"); } if(http.page->flags & HTML_FLG_COMPRESSED) { ADD_HTTP_STRING(pkt, "Content-Encoding: gzip\r\n"); } char *p = tcp_ref(pkt, tcp_tx_body_pointer); char *s = p; p += sprintf(p, "Content-Type: %s\r\n", http.page->mime); if(req_origin[0] != 0) { p += sprintf(p, "Access-Control-Allow-Origin: %s\r\n", req_origin); p += sprintf(p, "Access-Control-Allow-Credentials: true\r\n"); } p += sprintf(p, "\r\n"); // end of headers tcp_tx_body_pointer += (unsigned)(p - s); if(http.page->flags & HTML_FLG_SS_EVENT) { if(sse_sock != 0xff) { // prepare old SSE socket to work as new http socket if(tcp_socket[sse_sock].tcp_state != TCP_RESERVED) { tcp_send_flags(TCP_MSK_ACK | TCP_MSK_RST | TCP_MSK_PSH, sse_sock); tcp_send_flags(TCP_MSK_ACK | TCP_MSK_RST | TCP_MSK_PSH, sse_sock); tcp_clear_connection(sse_sock); } // pass current http socket to SSE use unsigned swap_sock = sse_sock; sse_sock = http.tcp_session; http.tcp_session = swap_sock; // add initial data on SSE channel static char sse_retry_cmd[] = "retry: 2000\n\n"; tcp_put_tx_body(pkt, (void*)sse_retry_cmd, strlen(sse_retry_cmd)); ((unsigned(*)(unsigned, unsigned))(http.page->addr))(pkt, 0); // send 1st reply on SSE channel tcp_send_packet(sse_sock, pkt, tcp_tx_body_pointer); // start listening on alternative socket tcp_socket[http.tcp_session].tcp_state = TCP_LISTEN; http.state = HTTP_IDLE; } } else { http.state = HTTP_SEND_PAGE; http.sent = 0; http.more_data = 0; http_get_pumping(pkt); } }